REST API Mistakes Every Junior Developer should Avoid | clean-code

preview_player
Показать описание
If you have been developing APIs using REST and sometimes getting lost, what are the best practices to follow, and what are the do's and don'ts. In this video, we'll cover what you should avoid doing as a junior developer when building RESTFUL APIs and how to improve.

⭐ Timestamps ⭐
00:00 Intro
01:10 1- Naming Conventions
03:25 2- HTTP Methods
04:34 3- Status Codes
06:30 4- Caching
08:59 5- Optimization

💻 Clean RESTFUL APIs Repo:

-- Special Links

✨ Join Figma for Free and start designing now!

👉 ✨ Join Figma For Professionals And Start Designing with your Team ✨

🧭 Build Login/Register API Server w/ Authentication | JWT Express AUTH using Passport.JS and Sequelize

🧭 Turn Design into React Code | From prototype to Full website in no time

🧭 Watch Tutorial on Designing the website on Figma

🧭 Watch Create a Modern React Login/Register Form with smooth Animations

🧭 Debug React Apps Like a Pro | Master Debugging from Zero to Hero with Chrome DevTools

🧭 Master React Like Pro w/ Redux, Typescript, and GraphQL | Beginner to Advanced in React

🧭 Learn Redux For Beginners | React Redux from Zero To Hero to build a real-world app

🧭 Introduction to GraphQL with Apollo and React

Made with 💗 by Coderone
Рекомендации по теме
Комментарии
Автор

The biggest mistake any dev can make when building a REST API is spending hours and hours agonizing over if every little thing is 'RESTful' or not. Just get it working, you will understand more about the problem space as you work and be able to make better decisions. Trying to design for some extremely vague principals of 'RESTfulness' from the get go will only cause you pain and more often than not, unless you are building an explicitly public API, the only thing that matters is that your endpoints provide the needed functionality and behave according to the documentation. Most of the worst API's I have ever had to work with in my career were just clearly designed to be 'RESTful' for the sake of being 'RESTful' and it was a nightmare to use them.

sfulibarri
Автор

Thanks for the video, i knew some of these good practices but the cache & optimization was a new thing to learn

baderelhayah
Автор

Next to naming convention there is another really important practice - entity spearation. If you work with a lot of entities, it is super easy to make your backend messy organised.

jaroslavhuss
Автор

Perfect, thank you so much Eslam for this very helpful video.

bacon
Автор

I didn't know about this caching middleware. Thank you for sharing

lukecartwright
Автор

With last example, i think it depends on type of data. If you have for each post different user, it is good to return it with one single api call, but if you have hundreds of post created by only 1 or 2 users, it would be better to fetch user by another api call (with some caching in browser) than join user for each post and return lot of duplicit data in response.

tomf
Автор

Thanks for the great review of the main concepts! Sounds valuable as a base.
But can't mention that "Optimisation" advice is completely out of REST principles. One of the REST principles is, roughly speaking, resource-per-URI. Violating it with such entities folding, you may achieve quick improvement, but with a big price to pay later.

I have at least three reasons not to go with folded entities:
1) Cache inconsistency: In your example, If any of the Users updates a name, you'll need to invalidate all Posts-related cache. It may look as not a big deal in this particular scenario, but if you expend this approach - you may come up with inconsistent caching all over your API because all entities are somehow relates\included to one another.

2) Inconsistency in approach: Let's imagine that the user has a dependency on "subscriptions". Should we include it as well? Should we include Subscription dependencies as well? Feels not too optimal, isn't it? So what are the limit levels to fold? You may say that it depends on the situation, but it's actually not - it is just better not to include related entities in the response.

Some more examples are if the entity has many dependencies. What if we have Comments? Reactions? Should we fetch it and return it all the time?
What if your folded data is big? Imagine you are fetching 100 posts for one user, and all the posts will contain the same copy of User data.
What If another 10 other Clients don't care about Users of the Posts at all, but are served with a redundant chunk of payload?

When you have no strict pattern - you'll need to make ad-hoc decisions for each case, which leads to a messy API shape, hard both to use and maintain.

3) Data type inconsistency - a nightmare when you shape folded entities in different ways, based on the use case.
Like, in the context of the posts we are interested in First Name + Last name + Avatar URL.
In the profile\admin context, we want all the details, like phone, email, address, etc.
It means that at Client we have two "kinds" of User TS interface\type - full and limited. So, should we define them separately? Otherwise - generalize them, so make all the fields that may be absent in any of the two options - nullable? This means null-checks and cast issues all over the app. Again, seems not a big deal when we have only 2 "variants". But in reality - we easily can over-"optimize" to have really different shapes of the same entity, with different "folded" entities depending on the usage context, and things go crazy.

And final - it just violates the Dependencies Inversion and Interface Segregation principles of SOLID. In this way, you are making API know about how the Client uses that data, so API depends on the Client.

Sure, there are some scenarios when you may naturally want to include the folded items, because of really strict non-functional requirements.
But those are exclusions, and shouldn't be the default tip to follow.

If you have such requirements - probably you want to consider:
1) Prefetching
2) BFF layer - where you'll define client-specific API contracts, and will have a place to collect data from different sources and aggregate them in a client-friendly structure)
3) GraphQL - which is designed for such scenarios.

ugentu
Автор

Oof. These aren't REST API mistakes you're listing, they're HTTP mistakes.
Not normally one to comment but wanted to throw things out there.

When working with HTTP, I agree with what you've said here:
- Use the correct HTTP Method
- Return the correct HTTP Status Code
- Leverage HTTP Caching
- In adhering to modern norms, sure there are URIs folks expect when dealing with entities (/posts, /posts:id).

However, what you're doing here is making the URI the API. This something different from REST.

When working with REST
- The URI *is not* the API. It only ever makes sense to add a version in the URI when the URI is what's being versioning.
- REST has nothing to do how you name things. What the URI says doesn't matter as long as it's unique. Nouns, verbs, etc. They just need to uniquely identify resources.
- Links (i.e. the hypermedia aspect) should be included. Don't return '"author": 1' in posts to link to it, return '"author": "/authors/1"'
- Build / drive your clients by consuming links (or templates) and not by being aware of the 'URI API' patterns.
- Leverage hypermedia types

In terms of REST your optimization advice and versioning advice is *potentially* bad advice depending on the use case.
First, "Optimization"
Assuming /posts and /authors are both representations of a collection of entities.

Would you say it's strange for the following to happen?
POST /posts to create a new entity with { author: 1, content: "..." }. Let's say it's assigned postId 'abc123'
GET /posts/abc123 and we get the what we created back, { author: { id: 1, name: "The Author" }, content: "..." }.
- This is weird. The entity I submitted to the server is not the entity I got back. In that, I can't GET the entity, update it, and PUT it back. Or would using PUT on a /posts/:id that includes author data also update the /author:id entity?

Now let's consider the same if /authors was valid
PUT /authors/1 -> { name: "Updated Author Name" }
GET /authors/1 -> { name: "Updated Author Name" }

Again this is strange from our /posts/1 perspective because data just changed on our post.
GET /posts/abc123 -> { author: { id: 1, name: "Updated Author Name" }, content: "..." }

You advice is effective for HTTP interactions but from a REST perspective is confusing / harmful.
If minimizing HTTP calls is optimal for your use cases and you want to aggregate data across entities, look at something else, i.e. OData, GraphQL, etc.

Second, "Versioning"
What you mention here is commonly given advice and I don't fault you or anyone else for repeating it. But play it out real quick and see if it still works?
In REST, the URI represents a 'unique' entity.
is /api/v1/posts/abc123 a different post than /api/v2/posts/abc123?
It may return a different representation / structure of the post, but I'm willing to bet that Post ID 'abc123' is the same content in v1 as in v2. So why then, does the same entity have two (or more) 'unique' identities?
And also, why would /authors or other entities be forced to version when posts wants to version? Is /api/v1/authors/1 still the same as /api/v2/authors/1?
This is what I meant earlier about how you're treating the URI as the API.

A lot, *a lot*, if REST information provided these days is confusing. We don't all have to purists but knowing what is and isn't REST is always helpful.

b.h.
Автор

Dang. I dont know about HTTP Caching before watching this video.
Great insight. Thanks a lot!

masadamsahid
Автор

Thank you for making videos like these.

memezarshrestha
Автор

All things good, knew them all. I skipped using Cache for some reason, re-implementing that from now on. :D About the last thing with author include, you can simply add 'authorname' in the post model and voilla, no extra http reqs and no extra db call internally, just another column, easy simple cheap.

RusuTraianCristian
Автор

I have to disagree with the optimization part as this depends heavily on what you need the data for. In the case of posts, you likely want to have the user with the post. Or not! If all you want to display are the titles and summaries of each post then you don't need the author. So I would make two methods: "/posts" and "/Posts/Author" where the latter will return all posts with the author, while the first just returns the posts. Of course, for a single post that would be "/posts/:id" or "/posts/:id/author" depending on what you want...
Thing is, you can also create a single method "/Authors" that return a list of all authors and store this in the client. Then you can retrieve posts without the need of returning the authors as the client already has them. This saves a lot of traffic when you have a few authors and a lot of posts, as you don't have to include the author any more as the client has them cached.
Optimizing REST services is challenging and depends heavily on how you're going to use them. Always including child records can be a bad practice.

WimtenBrink
Автор

Nice video. I only disagree with the "plural" convention for entities. You see, in MVC for models, and in OOP for classes, it is usually adviced to use singular, because in examples such as yours, you are just retrieving ONE user, ONE post. It would be different if you were working with collections of data. To keep up with that convention, allows future developers seeing your code, and even for yourself, to have LESS load of knowledge to debug something. It is easier to just follow ONE universal convention, and not changing it when we go from APIs to OOP. For the "rest" of the "REST" video, I liked it. Regards from Bogotá, Colombia, South America.

DavidLopez-gsfb
Автор

I’m not so sure that browser caching is the best for API requests. Perfectly fine for static content like html, JS and css but data I would use something like Redis on the backend

msolano
Автор

I would argue that returning 404s when a user is not found is not the best idea (especially if using integers for ids) and returning 400 with a proper error code that can be understood by the front end will be better. The main issue with returning 404s is that you are opening your system against enumeration attacks.
Example:
GET: /users/105 -> 404
GET:/users/100 -> 200
GET:/users/70 -> 200
This could tell a potential attacker that there should be users with ids ranging from 70 to 100

oygnsgy
Автор

I picked up most of the habits on my own by trial and error.. I found some methods are more efficient than others and result in cleaner and easier to understand APIs
I mostly found the problems by talking to the client side developers who are using my API and asking for their feedbacks.. this might not work for a big team but it does for a freelancer/open source developer like me

theflippantfox
Автор

REST API Mistakes Every Junior Developer should Avoid: *_thinking GraphQL can solve their problems_*

fruitfcker
Автор

Is it really all that it takes to start caching requests? 🤔

dini.alejandro.eyecue
Автор

why you said no verb, but you make store-inventory api?

kevintanudjaja
Автор

my problems is for users api as example
"/users/:id" => for public to get detail users

but what naming convention that are proper to get detail users but specific only allow accessed by the user owner?

palugaada