NestJs: Why do we need DTOs and interfaces both in NestJS - nestjs

The NestJS documentation showcases how to add DTOs to use in Controllers to validate request objects by using class-validator package. DTOs described there are TypeScript classes. Now, while controllers deal with DTOs(TS Classes), NestJS providers (or services), on the other hand, makes use of TypeScript interfaces. These DTOs and interfaces are pretty much of the same shape.
Now, I am seeing duplication of shape definition here. And wondering if the interfaces are needed at all?
Can we not make DTOs source of truth for the shape and validations? One of the approaches we were considering (to make the DTO source of truth) was, to have an openapi generator take the DTOs as input and generate openapi definition and from there another codegen can generate a set of typescript interfaces to be consumed by NestJS itself and which can be shared with another set of consumer applications like Angular too.
Have any people come across a similar problem? What do you think of the above? Feedback appreciated.

According to the Nestjs docs:
But first (if you use TypeScript), we need to determine the DTO (Data Transfer
Object) schema. A DTO is an object that defines how the data will be
sent over the network. We could determine the DTO schema by using
TypeScript interfaces, or by simple classes. Interestingly, we
recommend using classes here. Why? Classes are part of the JavaScript
ES6 standard, and therefore they are preserved as real entities in the
compiled JavaScript. On the other hand, since TypeScript interfaces
are removed during the transpilation, Nest can't refer to them at
runtime. This is important because features such as Pipes enable
additional possibilities when they have access to the metatype of the
variable at runtime.

I'm no expert but I'm not using DTO's at all. I really couldn't see a use for them. In each module I have a service, module, entity, and controller.

I would like to explain the concept of DTO with the simplest example possible for your better understanding.
DTO stands for Data Transfer Object. Now DTO's are used to reduce code duplication. It simply defines a schema which are passed in the parameters of functions to make it easy to get the required data from them. Here is an example of a DTO
export class AuthCredentialsDto {
email: string;
password: string;
}
Now if we make a method to check whether the password is correct or not
async password_check(usercredentials: AuthCredentialsDTO)
{
//Destructuring in JAVASCRIPT
const {email} = usercredentials;
//Database Logic to find the email
return user;
}
Now if we didn't make use of the DTO, then the code would have looked like
async password_check(email: string, password: string)
{
//Database Logic to find the email
return user;
}
also the point is that this is just one function, in a framework, Multiple function call multiple other functions which requires passing the parameters again and again. Just consider that a function requires 10 parameters. you would have to pass them multiple times. although it is possible to work without a DTO but it is not a development friendly practice. Once you get used to DTO you would love to use them as they save a lot of extra code and effort.
Regards

To extend #Victor's answer regarding the DTO concept and its role, I'd like to point that interfaces allow us to set a contract which represents something meaningful in our app. We can then implement and/or extend this contract in other places where needed as well e.g. entity definition for database objects - DAOs, data transfer objects - DTOs, and business models definitions notably.
Also interfaces for DTOs can be shared across a backend and a front-end so that both projects can avoid code duplicate and differences between objects exchanged for ease of development and maintainability.

one thing that dto provides more than interface is. with dto and class validator you can make the validations quickly at request level. But when it comes to interface you cannot add class validator to it. dtos are class in general. that means you have more to do with that than a interface.

DTO has a little bit different mission. This is an additional abstraction for data transfer connection by the network between FE and BE layers of your application and at the same time, DTO gives a description of your data like it doing Interface. But the main mission is a distinct place for data connection and due to this you could implement many helpful things in your DTO layer it could be some transformation for DTO fields values, validation for them, checking with regular expression, etc. So you have a convenient place for attendant changes for data just on early receiving or sending to FE side

TLDR
The answer to your question is yes, you could use them for shape if you wanted to, but it might be unnecessary in some situations.
DTOs are a great solution for when you need to enforce some shape on your data(specially on the nestjs ecosystem where it interacts a lot with class-validator) or transform it somehow. Examples of that would be when you're recieving data from your client or from another service. In this case the DTOs are the way to go for setting contracts.
However when you're sending data for example, between two layers of the same application -- for instance between your controller and your usecase or between your usecase and your repository -- you might want to use an interface there since you know your data is comming in the correct format in this scenarios.
One key difference to understand is that the interface serves as a development tool, it keeps you for making mistakes like passing an object lacking a certain required property between two classes, while the DTO affects the application itself, it's an object that's going to be instantiated at runtime and might be used for validation and data transformation purposes, that`s the idea, but of course it also has the capacities of an interface.
There might be exceptions to this rule of thumb depending on the architecture you're going for. For example, on a project I'm working on it's very common to have the contract between domain and presentation layers equal to the contract between frontend and the API. On this project, to avoid having to create two similar contracts, I`ve chosen to use a DTO to set the contract between the presentation and domain layers. Now in most cases I just extend the DTO when setting the contracts between API and clients.

Reason for using of DTO and Interface in NestJS
Basically in rest API we have to types of operation, One is Input and Another is Output. which is Request and Response
During response we doesn't need to validate return value. We just need to pass data based on interface
But in request we need to validate body
for example you want to create a user. Then the request body might be something like this
const body = {
name: "Test Name",
email: "test#gmail.com",
phone: "0393939",
age: 25
}
so during request we need to validate email, phone number or password is matched regex etc.
so in DTO we can do all validation
Here is one of my DTO example
import { IsEmail, IsNotEmpty, IsString, MinLength } from 'class-validator';
export class RegisterUserRequest {
#IsString()
#IsNotEmpty()
name: string;
#IsEmail()
#IsNotEmpty()
email: string;
#IsNotEmpty()
#MinLength(6)
password: string;
}
export class LoginUserRequest {
#IsEmail()
#IsNotEmpty()
email: string;
#IsNotEmpty()
#MinLength(6)
password: string;
}
And here is the interface example
import { UserRole } from './user.schema';
export interface UserType {
_id?: string;
email?: string;
name?: string;
role: UserRole;
createdAt?: Date;
updatedAt?: Date;
}
Hope you understand.
Thanks

I read through all of the answers, and none really seem to answer your question. I believe that yes, although DTOs and interfaces serve different purposes, I don't see a reason why you need to create an additional interface for typing purposes.
Happy to be proven wrong here, but none of the answers really address the OP's point, which is that the DTO serves a validation purpose, but you also get the typing for free.

In the nestjs-query packages there are two types of DTOs referenced. Read DTO - The DTO returned from queries and certain mutations, the read DTO does not typically define validation and is used as the basis for querying and filtering. Input DTOs - The DTO used when creating or updating records.

Basically you can validate request input without Dto. But imagination, you have to work with body payload, route params, query params or even header values. Without Dto you have to put your validation code inside each controller's methods to handle the request.
With Class Validation and Class Transformer, you can use decorator to do that. Your mission is defining your Dto Classes and add the validation annotations for each property.
You can find out the details here How to validate request input in nestjs and How to use pipe in nestjs

For example, if the Dto you created for the incoming request needs to be checked for the incoming data, the best way to do this is to create the Dto as a class. Because after typescript is compiled, they continue to exist in your javascript code. In this way, you can add various validations. For example "IsNotEmpy", "IsString" etc. If the data doesn't need to be validated, you can create Dto using interface. So here, rather than a single correct or correct method, it's about what you need.

BTW, even despite on DTO is a Java convention it can't solve the problem of Generic fields, e.g.:
#Get(url/${variable})
#Reponse({
[$variable: string]: $value
})
TS Interfaces can solve this issue only, but you cant describe it in DTO
And to show it you will pass some hardcoded example
class ResponseDto {
#ApiProperty({
...
example: [...]
})
[$variable]: SomeTSInterface[]
}
#Reponse({ status: 200, type: ResponseDto })

DTOs represent the structure of data transferred over the network it is meant to be for a specific use case whereas interfaces are more generalized specificity helps with better readability and optimizations. Interfaces don't exist after transpiling but nest accommodates dtos to be useful even after the transpilation face.

I think the NestJs documentation answered this precisely:
A DTO is an object that defines how the data will be sent over the network. We could determine the DTO schema by using TypeScript interfaces, or by simple classes. Interestingly, we recommend using classes here. Why? Classes are part of the JavaScript ES6 standard, and therefore they are preserved as real entities in the compiled JavaScript. On the other hand, since TypeScript interfaces are removed during the transpilation, Nest can't refer to them at runtime. This is important because features such as Pipes enable additional possibilities when they have access to the metatype of the variable at runtime.
Link to this pragraph: https://docs.nestjs.com/controllers#request-payloads

In my opinion,
DTO = Data Transfer Object. Dtos are like interfaces but their whole goal is to transfer data and validate it. They are mostly used in routers/controllers.
You can simplify your API body and query validation logic by using them. For instance, you have a AuthDto which automatically maps the user email and password to an object dto to enforce validations.
Where as the interface is just to declare how your response or a particular data model will be.

I'm not an expert but I do not understand why we use Dto
When we can use the schema model - what is the need for Dto and additional objects

Related

NestJS Mapped Types and DTO usage

I'm confused about the mapped types in NestJS.
The documentation says that PartialType create a new class making its validation decorators optional.
So, we use it in our validation pipes as we do with the original classes.
I'm wondering if it's the normal usage of the derived classes.
I mean, to make it easy to create a partial update DTO.
And if so, why is it in a swagger package (or graphql) and not in a utils of the core?
So, there's three mapped-types in Nest actually: the base #nestjs/mapped-types, the one in #nestjs/swagger, and the one in #nestjs/graphql. The reason for these packages is to allow devs to define a base class, and then be able to define classes that extend off this base class but use different decorators for validations/schema definitions. These mixin methods become useful because they read the existing metadata on the class and make modifications to it for the resulting class, like making every property optional, or leaving out key properties, like a password field on a User class.
The #nestjs/mapped-types package deals with class-validator and class-transformer metadata and is the basis for the other two packages. If the metadata doesn't exist, nothing is effected in terms of metadata, and the types are the only thing updated.
#nestjs/swagger's mapped-types update the swagger schema metadata so that your OpenAPI spec shows up properly.
Similarly, the #nestjs/graphql mapped-types updates the GraphQL schema so that Apollo doesn't throw exceptions on partial updates.
Because all of this metadata is handled differently, and it doesn't overlap, is the reason for three different ways to deal with it. Also, to help keep the base package small, rather than requiring the metadata keys from the other two packages.

Models vs DTO in NestJS

I am completely new to NestJS. I have seen that in NestJS, a model is created to specify the details of data, e.g. when creating a simple task manager, when we want to specify what a single task will look like, we specify it in the model (example below):
export interface Task {
id: string;
title: string;
description: string;
status: TaskStatus;
}
export enum TaskStatus {
OPEN = 'OPEN',
IN_PROGRESS = 'IN_PROGRESS',
DONE = 'DONE',
}
However, I later came across DTOs, where once again the shape of data is described. My understanding is that DTOs are used when transferring data, i.e. it describes the kind of data that you will post or get.
My question is that when I am already using DTOs to describe the shape of data, why use Models at all?
Also, I read that with DTOs we can have a single source of truth and in case we realise that the structure of data needs to change, we won't have to specify it separately in the controller and service files, however, this still means we will have to update the Model?
Most of the time over a long period of time your DTOs and your models can and will diverge from each other. What comes of the the HTTP request and what gets sent back can be in a different format than what is kept in your database, so keeping them separate can lead to more flexibility as time goes on. This basically comes into an argument of DTO (Data Transfer Objects) and DAO (Data Access Object) versus DTAO (Data Transfer/Access Object) (at least that's what I call them).
This also deals with the Single Responsibility Principle as each class should deal with one thing and one thing only.
There's also this SO post from a Java thread that talks about what you're thinking of

ServiceStack.Text JsonConfig Scoping Ignoring Attributes

I'm looking to effectively create logic via attributes on a .net core API project that, depending on a attribute will serialise or de-serialise while ignoring certain properties.
Eg.
If a property was decorated with [OutputOnly] it would not allow users to pass it in via the API, but the API would be able to return this value.
Inversely [InputOnly] would enable users to only pass this value in, but an API would not return this.
The issue I am having is JsConfig static and the property (IgnoreAttributesNamed) that enables Ignoring fields is a singleton too and not part of the Scope functionality in JsConfig.With()
My idea currently is to have an InputFormatter and an OutputFormatter in .net core, that will handle the this logic, but need to be able to config which properties are ignored in those contexts
any suggestions would be greatly appreciated :)
I don't really understand what the goal is here, you would use a Request DTO to define which Parameters a Service Accepts and Response DTO to define what your Service returns, the explicit purpose of the Request/Response DTOs is to define your Services Contract, i.e. the most important contract in your System, whose well-defined interface is used to encapsulate your systems capabilities and is what all consumers of your APIs binds to.
The C# POCO used to define your Request/Response DTO classes should be considered as a DSL for defining the inputs/outputs of your API, trying to collapse and merge their explicit intent of your APIs into multi competing Types with custom attributes is self-defeating, it adds unnecessary confusion, blurs its explicit definition which invalidates the primary purpose of having service contracts which is what all metadata services look at for documenting your API and generating the typed bindings in different supported languages.
So the approach and desired goal for using custom attributes for controlling serialization behavior so you can reuse the same types in different contracts is highly discouraged, but should you wish to continue with this approach you can refer to this answer for different ways to Ignore properties in ServiceStack.Text, specifically ShouldSerailize() API which will allow you to dynamically specify which fields ServiceStack.Text should serialize, if you intend on implementing a convention you can delegate the implementation to a custom extension method, e.g:
class MyRequest
{
public bool? ShouldSerialize(string fieldName) =>
MyUtils.ShouldSerialize(GetType(),fieldName);
}
Other than the linked answer the only other opportunity to manipulate serialization is potentially to use the built-in AutoMapping utils for selecting which properties should be copied over and the Object Dictionary APIs for converting C# Types into an Object Dictionary and manipulate it that way, then can dehydrate it back into the C# type after applying your conventions.

What is the best way to restrict strings in an Object Oriented model?

I need to select a modeling method for documenting extensions to an existing collection of web services. The method/tool needs to be used by tech business analysts. The existing API is defined in XML Schema. XML Schema work well with the one exception. Take a PaymentInformation class as an example. One partner might accept Visa and Mastercard as an example. Another also excepts Amex. We want to be able to extend PaymentInformation for PartnerA and PartnerB.
class PaymentInformation
method // CASH,CC
ccNumber
ccType // MC,V,AMEX
class PaymentInformationPartnerA
method // CASH,CC,PAYPAL
ccNumber
ccType // MC, V
The problem with XML Schema is that to apply a restriction to a class requires redefining the whole type. This seems like a maintenance nightmare. UML doesn't seem to support restricted strings (patterns, length, etc). What tool/method do you recommend for this? We have a preference, but not a requirement for Eclipse IDE.
You can add an UML constraint or a condition on your class. This is either a graphical note or directly an information hand coded on the UML metamodel.
The UML model is already an XMI 2.1 therefore like a XML but using specific rules.
Don't do that. If PaymentInformationPartnerA extends PaymentInformation then for all uses of PaymentInformation you can use PaymentInformationPartnerA, whereas you are saying that for some uses ( assigning a value to ccType of "AMEX" ) it is not covariant.
You're probably better off putting the constraint as a pre-condition of the endpoint receiving the message rather than as a constraint on the message type itself.

Protecting sensitive entity data

I'm looking for some advice on architecture for a client/server solution with some peculiarities.
The client is a fairly thick one, leaving the server mostly to peristence, concurrency and infrastructure concerns.
The server contains a number of entities which contain both sensitive and public information. Think for example that the entities are persons, assume that social security number and name are sensitive and age is publicly viewable.
When starting the client, the user is presented with a number of entities, not disclosing any sensitive information. At any time the user can choose to log in and authenticate against the server, given the authentication is successful the user is granted access to the sensitive information.
The client is hosting a domain model and I was thinking of implementing this as some kind of "lazy loading", making the first request instantiating the entities and later refreshing them with sensitive data. The entity getters would throw exceptions on sensitive information when they've not been disclosed, f.e.:
class PersonImpl : PersonEntity
{
private bool undisclosed;
public override string SocialSecurityNumber {
get {
if (undisclosed)
throw new UndisclosedDataException();
return base.SocialSecurityNumber;
}
}
}
Another more friendly approach could be to have a value object indicating that the value is undisclosed.
get {
if (undisclosed)
return undisclosedValue;
return base.SocialSecurityNumber;
}
Some concerns:
What if the user logs in and then out, the sensitive data has been loaded but must be disclosed once again.
One could argue that this type of functionality belongs within the domain and not some infrastructural implementation(i.e. repository implementations).
As always when dealing with a larger number of properties there's a risk that this type of functionality clutters the code
Any insights or discussion is appreciated!
I think that this is actually a great example of using View Models. Your concern seems directly related to the consumption of the entities, because of the data that they contain. Instead of passing your entities all the way up to the UI, you could restrict them to live within the domain only - i.e. no entities are passed into or out of the domain at all, with most/all activities done with a command/query approach on the repositories. Repositories would then return a view model instead of the entity.
So how/why does this apply? You could actually have two different view models. One for authenticated and one for non-authenticated users. You expose the actual values for the sensitive data in the authenticated view model and not for the non-authenticated one. You could have them derived from a common interface, and then code against the interface instead of the object type. For your concrete implementation of the non-authenticated user, you can just populate the non-sensitive data, leaving the sensitive getters to do what you want them to do.
My opinion on a couple of points:
I am not a fan of lazy loading in entities. Lazy loading is a data access responsibility and not really part of the model. For me, it is a first-class member of the things I vehemently avoid in my domain, along with paging and sorting. As for how to relate these items together, I would rather loosely couple the objects via ID pointers to other entities. If I want/need the data contained by one of these entities, then I can load it. It is kind of like lazy loading in a way, but I enforce that it never happens in the domain model itself by doing this.
I am not a fan of throwing exceptions on getters. Setters, on the other hand, is fine. I look at it this way. The entity should always be in a valid state. Getters will not impact the state of the entity - setters will. Throwing on a setter is enforcing the integrity of the model. Using the two view model approach would allow me to move the logic to the presenter. So, I could basically do something like "if user is of type non-authorized, do this; otherwise do something else". Since what you are referring to would ultimately be a case of how the data is presented to the user, and not important to the model, I think it fits well. In general, I use nullable types for my properties that can be null and do not enforce anything on the getters, as it is not part of its responsibility, usually. Instead, I use roles to determine what view model to use.
The obvious drawback is that there is more coding required to use the view models, but it comes at the obvious benefit of decoupling presentation and views from the domain. It also will help in unit/integration testing, where you can verify that a certain view model cannot return a type of data.
However, you can use something akin to AutoMapper (depending on what your platform is) to help in populating your view model from your entities.
I made the mistake of posting the question without creating an OpenId so it looks like I'll have to comment here(?).
First of all, thanks for taking you time to answer - It certainly has more to do with how data is presented than how the model works. However, I feel the need to clarify a few things.
The domain model / entities are never referenced directly from the UI. I'm using a variant of the DM-V-VM pattern for UI/business model separation. For lazy loading and repository implementation in general I have entity implementations in a infrastructure layer where things like serialization, dirty tracking and lazy loading is handled.
So the domain layer has entities like:
class Entity {
virtual string SocialSecurityNumber { get; }
}
And the infrastructure layer adds some other functionality to be able to update and restore entites from a server:
class EntityImpl : Entity {
bool isDirty;
bool isLoaded;
// Provide the means to set value on deserialization
override string SocialSecurityNumber;
}
So the lazy loading behavior would be implemented in the infrastructure layer and never seen by the domain layer.
I agree that throwing on getters wouldn't be nice but my concerns are on how an anonymous view model would retrieve the data. As of now, to retrieve a list of entities the viewmodel would hold a reference to a domain repository, should I have two repositories, one for authenticated(and therefore disclosed) entities, and another one for the unauthenticated users - maybe even two different entities?

Resources