What are DTOs and their significance?

Pratham Jagga - Jun 20 - - Dev Community

What's up amazing people ๐Ÿ‘‹

I just wanted to talk a lil bit about the concept of DTOs in programming and how they might be useful and significant in your code.

So, what is a DTO? Well, it stands for Data Transfer Object. It is basically defining an interface for various types of data transfers within a system. Some examples are: typescript interfaces which we use in our typescript code, mongoose schemas, etc.

DTOs make it easier to identify the flow of data between functions, services, modules and components of our application. Having the structure of data clear makes it easier to understand code, apply validations on data, identify unintentional flow of sensitive information and easier to document the code.

Let's take an example of our simple Node.js application and implement a simple API controller first without using DTO and then using DTOs. Later we will compare both of the strategies.

Basic API example without using DTO

const express = require("express");
const app = express();

// controller without using DTO
async function getUserData(req, res) {
    const username = req.query.username;
    const key = req.query.key;
    if (!username || !key) {
        return res.json({ success: false, info: "Invalid parameters!" });
    }

    // process user data
    // may be from your database
    // like db.get(users, {username})
    const userData = {
        name: "XYZ",
        age: "23",
        // ... more data
    };

    return res.json({ success: true, data: userData });
}

// route
app.get("/user", getUserData);

app.listen(5000, () => console.log("SERVER LISTENING ON 5000"));
Enter fullscreen mode Exit fullscreen mode

This is a very basic API implementation in Nodejs using express, right?

Let's try implementing the same with a DTO object.

const express = require("express");
const app = express();

class UsernameQueryDTO {
    username;
    key;
    constructor(query) {
        this.username = query.username;
        this.key = query.key;
    }
    isValid() {
        if (
            !this.username ||
            this.username.length < 5 ||
            !this.key ||
            this.key != "your_secret_key"
        ) {
            return false;
        }
        return true;
    }
    get() {
        return { username: this.username };
    }
}

// controller using our DTO object
async function getUserData(req, res) {
    const query = (new UsernameQueryDTO(req.query)).get();
    if (!query.isValid())
        return res.json({ success: false, info: "Invalid parameters!" });

    // process user data
    // may be from your database
    // like db.get(users, {username: query.username})
    const userData = {
        name: "XYZ",
        age: "23",
        // ... more data
    };

    return res.json({ success: true, data: userData });
}

// route
app.get("/user", getUserData);

app.listen(5000, () => console.log("SERVER LISTENING ON 5000"));
Enter fullscreen mode Exit fullscreen mode

You can clearly see now we are easily able to:

  • define validations. ๐Ÿคจ
  • see the structure of incoming data. ๐Ÿ“Š
  • determine sensitive data such as secret key is filtered beforehand (you can see our get function only returns the username). ๐Ÿ”’
  • understand the flow of data and document the APIs more effectively as we already have the data defined. ๐Ÿ“

I hope you got the point now !!
Now I leave it up to you as a task to define a DTO class for the response object as well and post it in the comments ๐Ÿ’ฌ.

That was it guys, Thankyou for reading the blog and if you like my work you can follow me here ๐Ÿ˜ƒ

See you next week with a new blog :)

. .