How are DTO utilized
So I've been writing some end points for my learning project, and I stumbled on DTO. The concept I understand, limit view you return for privacy reasons, security reasons, having a smaller payload, etc.
How does it work in practice though, I saw that
auto mapper
is a thing used, which is awesome, that I can use and understand easily. However, what's best practice, when you have a DTO for a model, does the endpoint always return the DTO? Or do you have two endpoints, one that return the actual model, and one the DTO?86 Replies
Or am i completely missing the point of DTO's, and should they only be used if we always only want to return the DTO, if thats the case just always returning the DTO model makes sense, and having different endpoints for the model and its DTO would not make sense.
Your endpoints traditionally only take DTOs
You'll have a different DTO for Create vs Read vs Update
you map from entity to DTO, but rarely the other way.
wait so if i were to update, I wouldnt use a DTO
i'd guess most people use PUT for that
you'd still use a DTO
ie,
CreatePersonDto
and UpdatePersonDto
the idea is that you don't want re-use within your DTOs
they should be separate so you have distinct control over themPastebin
using AutoMapper;using Microsoft.AspNetCore.Mvc;using _1._1._4._3__...
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
I see, makes sense, same case when using an auto mapper?
... generic controller? š¤®
well you know my background
Do I?
C++, I've told you before when we talked about generics
Sorry, I help hundreds of people per month :p
Can't remember each discussion
that's okay, anyway, generic controllers are not the way?
Well, imho not
cant I just make them overridable though?
or hide them
But maybe its the right call for you. Idk
if i dont like them
I've never written a "pure CRUD" web api thou
I mean, im new to wep api's
I've got no idea
this is a test project to learn
which is the only usecase generic controllers makes sense for, imho
where you need 2-* controllers with the exact same endpoints and code, only changing what entity they handle
makes sense
but to answer your question
so in my example, does the auto mapper solve all my issues?
or do I need a seperate DTO
Automapper takes care of Entity -> DTO
so I create one DTO, and the rest is taking care of by the auto mapper?
but as said, best practice is to have one DTO per endpoint that is meaningfully different
no?
You create several DTOs
for one model?
yes
One for read, one for create, one for update, etc
that pains me
update must have an ID, for example
while create does not, and read might need it
most likely it will, but maybe not (if your system uses slugs etc)
im just a littel confused as to how my current setup works then
well you certainly can use only a single DTO
but then you get no benefits at all from having it, imho
its the same as if you used your entity :p
yes but how is that decided though
wdym?
take this for instance, this is in my base controller
the TDto is passed, the type depends on template param meters of the BaseController
public abstract class BaseController<TEntity, TRepository, TDto>
in other words
this makes no senseyeah, thats why I said generic controllers are garbo
it'd be limited to one TDto, per controller
even for a PURE crud app, I'd say you need 3 dtos
read/create/update
and thats assuming you want fully editable models
so I can throw away my controller nonsense
that's where im getting at
Thats my opinion, yes
generic part of it
I can make it non generic, just an interface
i guess
just so I have my mapper and repository there
for each controller
could still have it be generic, just not for the dto
and not have the methods
so you implement those in the child classes
true actually
mhm, thanks, ill just fix that real quick and come back with some follow up questions
Alternatively make it be generic over 3 dto types š
I need to stop trying to make everything a generic
so lets practice writing non generic code
for once š
hah
sure š
@Pobiega I suppose its a silly idea having my base controller define the standard end points most tables have?
Like, Get, Post, etc based on the primary key
depends?
not define, declare I mean
If you need them to always exist, then yes
but what if you don
I dont know if that's normal though
in my pokemon application its like, I suppose so
base controllers are not normal, as far as I'm concerned
but I dont write CRUD apps, again
very few of my controllers are identical
fair enough, I think its a silly idea then
i wont lie
sure, a lot of them might have an
/entity/{id}
route, but not allye, its just a stupid idea
ill just do it when I know it's 100% needed for all my controllers
hm
there is an alternative to controllers btw
oh?
yeah, something called "minimal APIs"
you literally map a route and a verb to a function
in its simplest form
There is a neat "framework" library that wraps that functionality very nicely called "FastEndpoints"
I personally use that when I make new APIs, instead of controllers
Ill give their documentation a read, might be more suitable for me
I hate this MCV (or whatever its called) pattern
Management Control View?
Model View Controller
yup
so this is currently my Pokemon controller, now it's still using the same DTO, for each endpoint
so the idea is that I have different DTO's defined based on the end point correct?
Post is to create, iirc
something like that, ye
the delete one might not need a dTO
since its probably just an ID
š
and thats given by the url(route)
ahhhhhhh its for the payload, we can make it smaller since the rest is irrelevant
ye
makes sense
you are one smart individual, let me make some DTO's and ill send them here so you can double check if you want
is it common practice to have all the TDO's in the same file?
or more like the java route, where each class has its own file
I feel like that'd be so overkill, considering the sizes of TDO's in general
I'd rather say I'm one experienced individual š
I've gone through all the pain points of not using DTOs, reusing a single DTO etc
you can have either. when using Fast Endpoints I keep em in the same file as the endpoint itself
when using controllers I usually bunch em up in a "Dtos.cs" file next to the controller
So this is my model:
Now let's say I wish to add a new Pokemon, it has to have a
PokemonCategories
assigned, doesnt need reviews but it could for instance? Same with owner, it could have a owner at some point
so should I have a DTO for when u update the owner of a pokemon, or when a review is added
wait those dont need DTO's, as it'd be a single field have the optional props be nullale
in the dto
that translates to my API properly?
i suppose so I guess
if
PokemonCategory
etc is also an entity, you'd have DTOs for them too btwye
well, in some way ye
it is
a DTO for this controller or just in general you mean?
for
PokemonCategory
depends
could be either its own for this controller, if it needs a special data subset
or you re-use the "read" dto from the category endpoints
thats more niche thou, and sort of violates the idea of DTOs
I'd say that most of the time, you'd have a special sub-dto for this dto
how'd you make that?
another class, and then use that class inside the DTO?
ye
assuming source and destination have the same property names, and both dtos are mapped to their respective entity, automapper understands it
my model:
and then
yep!
and the reason I do this is, when I try to create, it will require me for the information I have in my PokemonCategorySubDTO, rather than the model itself?
So now this Post request, will require all fields except those that are nullable correct?
it wont be "required" unless you mark it as such
with the
required
keywordah fair, makes sense
how does my end point look, does it look good?
sure, yeah
now when I add a pokemon, it looks like this:
and a bunch more, seems like a large input to be given
to add a pokemon...
if I wanted to limit it to just adding a pokemon
I'd change my DTO to just the pokemon data
yep
but my relations might get missed that way
thats a risk I carry
I guess I should mark whatever is required as required
though that doesnt stop me from writing a incomplete DTO...
no, but ASP wont allow it
the model binder will say "nah, you missed a required prop"
I see, makes sense