Want to master Clean Architecture? Go here: bit.ly/3PupkOJ Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt Join a community of 1000+ .NET developers: www.patreon.com/milanjovanovic
Lovely video. Very nicely explained, good examples. I wonder if in my enterprise environment even 1% of people who throw the word REST around left and right have even the slightest clue of who Roy Fielding is and that something like HATEOS even exists. :)
Very good video as always, congrats. One sugestion for a video where is a kind of extra or complementary topic about it, is about Nest Resources. What are your thoughts about, how you build them, what are your primary driver to create them and so on.
I've seen some APIs that use the OPTIONS method if i remember correctly to use exactly what you described on the 3rd level. In that way they do not include extra information on every response (more bytes to transfer) and also it keeps the logic of constructing these links into a single endpoint instead of doing it on each endpoint. So the idea is that you use OPTIONS method in /products and you get all the endpoints that refer to this resource. Not sure if it is the same scenario, I would like to know your opinions. Nice video Milan 🎉
It have benifits and drawbacks. As it described in standard it can only show Verbs of request. So if you use some not standard additional endpoints - it will not fit your needs. You can add a full response with available methods as example to solve it. But there is a drawback - you can't use it on Get /resources, at least as standard says, but with full response - it will be an option. But for sure using OPTIONS method winning in amount of data, but if your client relies on available endpoints - 1 request is better than 2. And for sure with compressed and 'zipped' answer it's actually will be not so much additional traffic. Anyway - you should use approach that fit your needs.
Makes sense, from a practical perspective. I haven't seen that approach used in any application I worked on. The obvious downside is having to do an extra network request to get the available data, and this will often be more expensive than transferring a few extra bytes to the client.
@@MilanJovanovicTech Would someone use those endpoints in a production ready environment? Their use is to make it easier for a developer to know what actions @he can perform based on its roles on a certain resource. Am I wrong?
PUT: Used for complete resource updates/replacements Idempotent (multiple identical requests have same effect as single request) Replaces the entire resource with the provided payload If you omit a field, it gets removed/set to null in the resource Pros of PUT: Simpler to implement and understand Guaranteed idempotency Better for atomic updates where you want to ensure the entire state Reduces risk of partial/inconsistent updates Cons of PUT: Requires sending complete resource even for small changes Higher bandwidth usage Risk of unintentionally removing fields if not included in payload Can be inefficient for large resources PATCH: Used for partial resource updates Sends only the changes to be applied Can use different patch formats (JSON Patch, JSON Merge Patch, etc.) Not necessarily idempotent (depends on implementation) Pros of PATCH: More bandwidth efficient - only send changed fields Better for partial updates Reduces risk of overwriting concurrent changes to other fields More flexible with different patch formats Cons of PATCH: More complex to implement correctly Not guaranteed to be idempotent May require more complex validation logic Different patch formats can lead to inconsistency
My APIs are not RESTful, and seriously that's not a problem for me. I just respect URL format, the method type, returned status code and url location of created or updated entity, also a few other headers, in and out, but not much, and it's quite enough for the moment. But thanks to explain the true and deep meaning of the concept. By the way, Milan, thanks for providing/sharing your valuable knowledge across your various videos, i know as many that is also a commercial approach but anyway thanks a lot.
I'm still looking for the best way to design a web API for a CQRS system. Basically, you sent a command (POST) or a query (GET). But, the command could be "Deleted" But more likely if you are designing event based system you don't send "delete" commands. For example, for a class registration system for a university. You wouldn't "Post to register" and the "Delete the registration" if you didn't want that class. You would AddClass or DropClass. Both commands posted. Dropping a class that you didn't add would be a "Bad Request" rather than 404 registration not found. Seems similar but different.
I tend not to think about that as much. It's only us backend developers that care. If the command is delete/remove/revoke (something destructive) I'd use a DELETE method. For most other updates, I'll use PUT.
My APIs are on level 2. I don't use HATEOAS because it's really an overkill for internal APIs as it won't be used. The only case when I can consider using HATEOS is public API, but not necessarily. What about you?
Yes, there's a difference between internal/external APIs. I've actually worked on a fintech application where HATEOAS was used everywhere. It made it so much easier to find related resources. Plus the documentation is great.
@Milan Jovanović, actually there is two reasons to not make HATEOAS: 1st one - it's not needed - a lot of Apis not need it for fully working client, 2nd one - application that uses Api doen't have logick that relies on resource state. For example if you have Api for traffic light (for simplicity) - you shouldn't be able to switch to the red state if it's already red. Or you can't switch to green from red, because you should switch to yellow one before and so on. Upd: And i forgot to write it earlier - you don't cover agregates i mean links like /orders/12/items/1
It's not needed is debatable. Yes, you don't need to build an API. But the question - will your API be better/easier to use if it had HATEOAS? I think, yes - for public APIs. Internal APIs are a different thing. "links like /orders/12/items/1" You'd have an "items" link on the order, and than the specific item will have it's own links
It's a bad idea, because reflection itself, if you want something like this - use code generators. And second reason why you shouldn't do it - you loose control of what links to return based on some logick in current endpoint. Alternative can be some shared method that generates all the links or as i mentioned before this method can be generated by code generator and be used in all the endpoints if you don't need different logick in different endpoints
I haven't tried HATEOAS in a production application, but always wondered would it be a cool way of integrating with a frontend - as in you get not only a list of things, but also specific links to the allowed operations on each thing. The frontend dev just needs to take the provided uri and that's it. Could be an interesting solution to a problem - not saying a feasible one.
IMHO (wearing the heat of Captain Obvious :) ), OpenApi tools, like Swagger, made job of hypermedia as side effect of documenting API. Also, these links are predictable from level 2, so it's a few hundred bytes of bloat data for every response.
These aren't quite the same. Would you expect external clients and your UI application devs to refer to the Swagger doc whenever they need to figure out what to do next?
@@MilanJovanovicTech Milan, thank you for the video and for this comment. It depends. For simple cases that are limited in cost and have a controller-based API with the option to include XML comments(it also works with minapi, but with some workarounds), it allows us to complete a task with minimal effort and cost. For developers of a few simple first-party-developed clients, imho, making good documentation can accomplish the task and avoid a supplementary job and network traffic. But in more advanced scenarios, there will always be trade-offs. I imagined a classic example of an order that has a status, items, and delivery address. For instance, a user can cancel an order until it is sent, change the items until the order is assembled, and modify the delivery address until the order is prepared for delivery. For a time- and cost-restricted case, like the example in this video, the idea will be a swagger document with five endpoints at "/orders/{orderId?}" and a bad request in the event of an invalid domain operation. For a more advanced case, with maybe external client developers, it will be /orders/{orderId}/items and /orders/{orderId}/delivery, and level 3 has more advantages. For example, it is possible to hide information about post, delete, and put methods on /orders/{orderId}/items when the order passes the status of "assembled.". From the perspective of domain, network traffic, compute power, and the cost of development and hosting in the cloud, I believe it would be more beneficial to include this information within the domain-oriented property of the results' payload. However, from a standardization perspective, it would be more beneficial to create an adapter. Thank you for making me think in this direction.
What about filters and pagination? is there any standard in REST regarding this part? Also, tbh, I think rest should be abandoned. Graphql is just way better.
Other than not following REST API standard, all are valid web based apis .. what is bad about each one? Is convention based expectations actually better? Given the "documentation" something like a swagger page provides , nothing is hidden and reasonable expectations can be generated at all levels
HATEOAS isn't about documentation. If i correctly get your question. It's about giving available actions to client. Documentation can show all endpoints, but it can't show you which action is available at current time. If you have requirements to disable some actions based on your business logick - you should use HATEOAS.
@@MilanJovanovicTech You've created endpoints that map 1:1 to the C, R U, and D of CRUD. Almost every example of REST on the Interwebs does that, as if that's a good way to build interfaces. It's just sad. Instead, people should learn to have interfaces that reflect the business case. Nobody comes into the office with the goal of creating, reading, updating, and deleting products. What people do instead is change the price of a product, or have a special offer for Black Friday for the product, or to phase out the product and not sell it anymore, and so on. The interface (that's the I in API) should reflect that.
Want to master Clean Architecture? Go here: bit.ly/3PupkOJ
Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt
Join a community of 1000+ .NET developers: www.patreon.com/milanjovanovic
dude, i loved it! thanks Milan! continue u great job! 👏
Will do!
Lovely video. Very nicely explained, good examples. I wonder if in my enterprise environment even 1% of people who throw the word REST around left and right have even the slightest clue of who Roy Fielding is and that something like HATEOS even exists. :)
The sad part is it doesn't matter for the most part. We simply don't use HATEOAS in the industry :/
Very good video as always, congrats.
One sugestion for a video where is a kind of extra or complementary topic about it, is about Nest Resources.
What are your thoughts about, how you build them, what are your primary driver to create them and so on.
Great suggestion!
You videos helped me with tech task. I failed horrendously , but i still improved nevertheless. Thanks for your content
Keep it up
I've seen some APIs that use the OPTIONS method if i remember correctly to use exactly what you described on the 3rd level. In that way they do not include extra information on every response (more bytes to transfer) and also it keeps the logic of constructing these links into a single endpoint instead of doing it on each endpoint.
So the idea is that you use OPTIONS method in /products and you get all the endpoints that refer to this resource.
Not sure if it is the same scenario, I would like to know your opinions.
Nice video Milan 🎉
It have benifits and drawbacks. As it described in standard it can only show Verbs of request. So if you use some not standard additional endpoints - it will not fit your needs. You can add a full response with available methods as example to solve it. But there is a drawback - you can't use it on Get /resources, at least as standard says, but with full response - it will be an option. But for sure using OPTIONS method winning in amount of data, but if your client relies on available endpoints - 1 request is better than 2. And for sure with compressed and 'zipped' answer it's actually will be not so much additional traffic.
Anyway - you should use approach that fit your needs.
Makes sense, from a practical perspective. I haven't seen that approach used in any application I worked on. The obvious downside is having to do an extra network request to get the available data, and this will often be more expensive than transferring a few extra bytes to the client.
@@MilanJovanovicTech Would someone use those endpoints in a production ready environment? Their use is to make it easier for a developer to know what actions @he can perform based on its roles on a certain resource. Am I wrong?
Question : should we use PUT or PATCH to update an resource? What are pros&cons of each method?
PUT:
Used for complete resource updates/replacements
Idempotent (multiple identical requests have same effect as single request)
Replaces the entire resource with the provided payload
If you omit a field, it gets removed/set to null in the resource
Pros of PUT:
Simpler to implement and understand
Guaranteed idempotency
Better for atomic updates where you want to ensure the entire state
Reduces risk of partial/inconsistent updates
Cons of PUT:
Requires sending complete resource even for small changes
Higher bandwidth usage
Risk of unintentionally removing fields if not included in payload
Can be inefficient for large resources
PATCH:
Used for partial resource updates
Sends only the changes to be applied
Can use different patch formats (JSON Patch, JSON Merge Patch, etc.)
Not necessarily idempotent (depends on implementation)
Pros of PATCH:
More bandwidth efficient - only send changed fields
Better for partial updates
Reduces risk of overwriting concurrent changes to other fields
More flexible with different patch formats
Cons of PATCH:
More complex to implement correctly
Not guaranteed to be idempotent
May require more complex validation logic
Different patch formats can lead to inconsistency
My APIs are not RESTful, and seriously that's not a problem for me. I just respect URL format, the method type, returned status code and url location of created or updated entity, also a few other headers, in and out, but not much, and it's quite enough for the moment. But thanks to explain the true and deep meaning of the concept. By the way, Milan, thanks for providing/sharing your valuable knowledge across your various videos, i know as many that is also a commercial approach but anyway thanks a lot.
Much appreicated!
Really nice explanation.
Thanks!
I'm still looking for the best way to design a web API for a CQRS system.
Basically, you sent a command (POST) or a query (GET). But, the command could be "Deleted" But more likely if you are designing event based system you don't send "delete" commands.
For example, for a class registration system for a university. You wouldn't "Post to register" and the "Delete the registration" if you didn't want that class.
You would AddClass or DropClass. Both commands posted. Dropping a class that you didn't add would be a "Bad Request" rather than 404 registration not found.
Seems similar but different.
I tend not to think about that as much. It's only us backend developers that care. If the command is delete/remove/revoke (something destructive) I'd use a DELETE method. For most other updates, I'll use PUT.
A part of my application is fully RESTful :)
That's something 😁
My APIs are on level 2. I don't use HATEOAS because it's really an overkill for internal APIs as it won't be used.
The only case when I can consider using HATEOS is public API, but not necessarily.
What about you?
Yes, there's a difference between internal/external APIs. I've actually worked on a fintech application where HATEOAS was used everywhere. It made it so much easier to find related resources. Plus the documentation is great.
yes, i watch your video while rest ing
Same
This is the way :)
can you pls explain difference and best prctice related to conention based routing VS attribute based routing
Ok
thanks for video..In which situations should we use a minimal API, and in which situations should we use a layered architecture?
两种用途之间没有冲突
What is your context?
@Milan Jovanović, actually there is two reasons to not make HATEOAS: 1st one - it's not needed - a lot of Apis not need it for fully working client, 2nd one - application that uses Api doen't have logick that relies on resource state. For example if you have Api for traffic light (for simplicity) - you shouldn't be able to switch to the red state if it's already red. Or you can't switch to green from red, because you should switch to yellow one before and so on.
Upd: And i forgot to write it earlier - you don't cover agregates i mean links like /orders/12/items/1
It's not needed is debatable. Yes, you don't need to build an API. But the question - will your API be better/easier to use if it had HATEOAS? I think, yes - for public APIs. Internal APIs are a different thing.
"links like /orders/12/items/1" You'd have an "items" link on the order, and than the specific item will have it's own links
For a given resouce, can we get all related links/endpoints using reflections? Idea is to avoid extra code and repetition.
It's a bad idea, because reflection itself, if you want something like this - use code generators. And second reason why you shouldn't do it - you loose control of what links to return based on some logick in current endpoint. Alternative can be some shared method that generates all the links or as i mentioned before this method can be generated by code generator and be used in all the endpoints if you don't need different logick in different endpoints
I'd rather hardcode it. It'll be faster. Or try source generators, as the other comment suggests.
Please, make video how add sorting and filtering rest api with Dapper and Dynamic parameters)
Hmm, that'd be interesting
I haven't tried HATEOAS in a production application, but always wondered would it be a cool way of integrating with a frontend - as in you get not only a list of things, but also specific links to the allowed operations on each thing. The frontend dev just needs to take the provided uri and that's it. Could be an interesting solution to a problem - not saying a feasible one.
Yes, that works incredibly well for UI applications. Make the frontend dev's work simpler
IMHO (wearing the heat of Captain Obvious :) ), OpenApi tools, like Swagger, made job of hypermedia as side effect of documenting API. Also, these links are predictable from level 2, so it's a few hundred bytes of bloat data for every response.
documentation != hypermedia. It's about availability of actions on resource.
These aren't quite the same. Would you expect external clients and your UI application devs to refer to the Swagger doc whenever they need to figure out what to do next?
@@MilanJovanovicTech Milan, thank you for the video and for this comment.
It depends. For simple cases that are limited in cost and have a controller-based API with the option to include XML comments(it also works with minapi, but with some workarounds), it allows us to complete a task with minimal effort and cost. For developers of a few simple first-party-developed clients, imho, making good documentation can accomplish the task and avoid a supplementary job and network traffic.
But in more advanced scenarios, there will always be trade-offs.
I imagined a classic example of an order that has a status, items, and delivery address. For instance, a user can cancel an order until it is sent, change the items until the order is assembled, and modify the delivery address until the order is prepared for delivery.
For a time- and cost-restricted case, like the example in this video, the idea will be a swagger document with five endpoints at "/orders/{orderId?}" and a bad request in the event of an invalid domain operation.
For a more advanced case, with maybe external client developers, it will be /orders/{orderId}/items and /orders/{orderId}/delivery, and level 3 has more advantages. For example, it is possible to hide information about post, delete, and put methods on /orders/{orderId}/items when the order passes the status of "assembled.".
From the perspective of domain, network traffic, compute power, and the cost of development and hosting in the cloud, I believe it would be more beneficial to include this information within the domain-oriented property of the results' payload. However, from a standardization perspective, it would be more beneficial to create an adapter.
Thank you for making me think in this direction.
Like as always
Appreciate it!
What about filters and pagination? is there any standard in REST regarding this part? Also, tbh, I think rest should be abandoned. Graphql is just way better.
Other than not following REST API standard, all are valid web based apis .. what is bad about each one? Is convention based expectations actually better? Given the "documentation" something like a swagger page provides , nothing is hidden and reasonable expectations can be generated at all levels
HATEOAS isn't about documentation. If i correctly get your question. It's about giving available actions to client. Documentation can show all endpoints, but it can't show you which action is available at current time. If you have requirements to disable some actions based on your business logick - you should use HATEOAS.
I wouldn't call Swagger true documentation. There are better tools that can turn your OpenAPI spec into something useful.
As far as I can see the HATEOAS only contains what you already knew when you called the GET endpoint in the first place.
But it can contain a lot more. Related resources, parent resources, etc.
@@MilanJovanovicTech It made me think. Very helpful video again.
The question is, do you ever rest?
Barely
REST != CRUD.
Ok?
@@MilanJovanovicTech You've created endpoints that map 1:1 to the C, R U, and D of CRUD. Almost every example of REST on the Interwebs does that, as if that's a good way to build interfaces. It's just sad. Instead, people should learn to have interfaces that reflect the business case. Nobody comes into the office with the goal of creating, reading, updating, and deleting products. What people do instead is change the price of a product, or have a special offer for Black Friday for the product, or to phase out the product and not sell it anymore, and so on. The interface (that's the I in API) should reflect that.
Milan, isn't peoples time better spent solving their actual problem other than chasing being "pure" using the "REAL" ?
This does solve many actuals problems. HATEOAS isn't a lot of of overhead if you're already on L2