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.
from my 2 years as junior software engineer, as long as you have the CONSISTENT RESPONSE OF DATA all over your APIs endpoint, then it will be just fine. We (the company) recently used a third-party vendor to get us a payment point on line banking service for our app. Unfortunately, the response for each APIs from the third party is inconsistent, causing us a problem, like we literally have to create more tables in our database, and suffer inconsistent data return. It f*cked up me as the fullstack developer for the admin side, and my friends as the fullstack developer for the client side. HTTP codes, methods, and url naming mistakes is still i can tolerate, but inconsistent response all over the APIs... That is a f*cked up one that just might lose you a job.
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.
Alternatively the response could come with 2 lists in the payload, one with posts and one with authors, and then you can cross-match the post's authorId with the author's id. Then duplicates don't appear in the authors list, and it can be trimmed to not include users that aren't authors.
How do you know the ratio of post x user? Today you may have 1 or 2 Users only, however as your API grows you can't be sure about this ratio (e.g. StackOverflow)
@@guilhermeferreirabr as I said "it depends on type of data", in some cases you know, in some cases you don't know. As an pure example (just made up), you can have software for bills in restaurant. You can be almost sure that you will have few tens of waitress per restaurant who creates a bill. But you will have thousands of bills. And if you change waitresses more times than you have customers, than you have bigger problem than not optimal API. Than if you want some report for restaurant per month. You will get long list of bills but there will be only few waitresses across this bills.
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.
thanks for sharing such an insightful comment but in the end, REST does not promote optimization (i.e you need to call multiple api to get enough data you need)?
ปีที่แล้ว +1
Relationships just don't work in REST, in my experience. It's also a pain to figure out how you would alter a many-many relationship. I've seen many people try, but it's always been meh at best. I love the simplicity of a good REST API, but it's also very important to be cognizant about when your model breaks down,and this is the kind of problem GraphQL was built to solve.
@@free2idol1 Yep, kind of. We should use other techniques to overcome some performance limitations when we face them. Consider the analogy with SQL - you have two Tables: Users and Posts. I believe no one will agree that stating the rule as "Always JOIN the tables to optimize your calls" makes sense. Or like "Always create INDEXes for all of your columns". In some cases, it's reasonable, in - it's will screw up your performance completely. And if you think about what's going on behind your API when you include soresource resourse the (like in exthe ample in video) - it will be achieved exac with additional Subqueries or JOINs, which also havea price, regardless of do consumers need that info or not. So, even that folding can be considered as a way toptimizese problematic calls, it's far froa m "rule of thumb" to rely on by default. I would rather say that you need to hava really strics reasons for such a folding.
@@ugentu thanks for your reply. If this is the case, then does REST only applies for simple CRUP app (show, create, edit only 1 resource at a time)? And if my project has lots of apis that need multiple JOINs for fetching, multiple updating/creating action under the hood, then I'd go against REST and choose GraphQL as others recommend?
@@free2idol1 Yes, like than. But there some more options how to achieve it. Like creating the "Middleware" Service, like BFF, to move all data aggregation login into it, to avoid placing it in frontend. So, it will expose It's interface in a way best suits frontend. But, REST isn't a all-or-nothing choose. There a different steps on the RESTfull way, and you can stick on 'earlier" stages it that's suits your needs. One thing is to maintain the public API that will be available for millions users. And another - just an API for your home page.
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.
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.
@@jordanb9363 The 'posts' and 'author' part are fixed text, while the ':id' part would be a variable, to be replaced with the ID number. You use 'posts' to indicate access to the posts data. Then you select a specific record by the id. Then you tell that you want the author part of this record. So for post with ID 4242 it would be /posts/4242/author
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. Folks who want to learn about REST should start with the thesis: www.ics.uci.edu/~fielding/pubs/dissertation/abstract.htm 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. And here's a link to someone explaining REST in a helpful way: th-cam.com/video/pspy1H6A3FM/w-d-xo.html
The uri addresses a resource. The content and mime types address the format of the resource. Version usually related the format of the json and should correctly be addressed in this manner or a separate header
api/v1/posts may have a different implementation than api/v2/posts that is why they are considered unique. Maybe api/v2/post has more property or has a different property than api/v1/posts.
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
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
Hi, I have my Excel file which is updated through an odbc connection. But how can I sync that Excel data into Google Sheets that could be updated automatically in periodic intervals. Any Solution? Thanks
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.
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
11:40 - i had to use a digital coin API and it was giving all the info so i had to manually take what i needed so for me it is a bad practice when there is a lot of data in that entity.
Be careful with caching. Only use for static data that never changes, never be updated or deleted. Any other case, avoid it. I think his info on that is incomplete. Caching done wrongly creates the most frustrating, untraceable bugs in software dev.
@@awmy3109 Or when data is changed you can revalidate cache. Cache response from Headless CMS api, but when admin is changed something, revalidate it. But that's outside of this video probably
I often see 404 used instead of 204. 404 is, among others, for inexistent resource access, while 204 is a successful call but without returnable content. Correct me if I'm wrong.
Yeah 404s are overused and to be considered extremely unreliable regarding the actual non-existence of a resource. At most they mean, "the resource is currently unavailable. It may or may not exist and this may or may not be temporary" For example, a misconfigured proxy in the middle may return 404 (e.g. an nginx that failed to load its config due to a typo).
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?
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.
While it might not solve all your problems. especially not on small apps with only a few post types due to a lot of code overhead. it's far easier to work with for pure frontend devs. Many juniors and a fair number of senior devs still manage to make a garbage API's with it by not following the standards hammered down in the design documents however. There is no defeating garbage coders in the end...
And when I have multiple POST controllers, what would the names look like, for example three POST controllers, Create Password, Create User, and Login?
Make the end points easy and simple Definitely read the hateos guide and steal some inspiration from graphql and make some of your controller functions where they could do many different exclusive actions depending on the inputs. Maximize your use of route params Just user _ post delete put/patch Sometimes u can set all the fields at once in updates but youll want separate end point to handle password updates
const setCache is a function expression and function setCache is a function definition. This is valid: setCache(); function setCache() { console.log("foo"); This is invalid: setCache(): // an error is thrown const setCache = function() { console.log("bar"); }
@@md2perpe it is used to not pollute the global scope, cause the function expression is not available everywhere in the scope and it's also good if you need to put a function into a callback.
404 response cannot be agreed. I think 404 status code corresponds to when information about the url is not found on the web server (for example, nginx) for that path. If the user does not exist, you can simply return an empty array or an empty object.
@@romanstingler435 When you delete a user, you receive a status code of 204 and expect a status code of 204 even if you do it again and again. However, in the case of get, I think it is possible if only the user returns. I don't know in general situations where values from other tables as well as users are joined and returned. In addition, if the server uses the response type for get as fixed as shown below, 204 may not be a good way. { request_date: Date... data: {...someuser} } But I also return 404 when there is no user.
404 is exactly for such a case. Returning an empty array for a resource that is supposed to return an object - is far more confusing. It's like asking "Give me a Cola" in the store but getting an Empty bottle crate instead.
@@ugentu I disagree. To take your analogy: 404 is like asking to get the list of the cars avaliable to rent in a McDonalds 200 with empty array is like asking for a ice cream in a McDonald's 404 happens when the client wants to access a resource that does not exist, and it's the client's fault. The client made a bad request that the server can't do anything about it. 200 happens when the request was correct, but there was just no response. The client asked for ice cream in a McDonald's, which is a valid request, but the ice cream machine was broken (the resource doesn't exist).
Summary based on scaffold what I've been use for my project Route Methods get /Models ----> all index get /Models/:id ---> show single record post /Models ---> create a new record put /Models/:id ---> update a record delete /Models/:id ---> delete a record
Http or https just transmission layer, define your own business status code keep the compatiblity between different transmission layers. Hance stop mapping http status to business please. And, the protocol of http status code is prior agreement in the http reference, the implementation of http client library follows the reference strictly. That's means you may get unexpeceted expection from the http client library during develoment when you assign additional means to an existing http status code. At last, assign private protocol over a stander protocol is against the best practice.
And very important, REST APIs should be stateless!!! But this video was more about HTTP and when you make that bad choice of using HTTP, at least always use HTTPS (also in dev and catch your issues with certificates early). But a far better protocol to send your messages over is a Message Queue (AMQP). At least that gives guaranteed delivery, to the subscriber channels guaranteed in order delivery and unlike HTTP has routing abilities. Kafka and RabbitMQ are far better choices than REST over HTTP(S) is.
I remember working with an app developer. He wanted me to always return status code of 200 on every request, that got me really irritated even when I tried explaining to him why we shouldn't, he was being rude and claimed he's a senior dev. I wish he could see this video and be humble.
Honestly, you should restrict the use of HTTP status codes to very early failures. Any errors (beyond 403, I suppose) emitted by the implementation code should be encoded in the response body instead.
I work on FE and I kid you not I received a status 200 response which had a JSON object which had `statusCode: 500` and errorMessage which said user not authorized. Why it was not just 401 escapes me. I have daubed it the Schrodinger response.
Imagine you handled multiple status in you app like 403, 404... If you still have an error What will be the default status code you will choose for a rest endpoint ? Status code 409 ?
@@AnotherSmartMonkey It's difficult to understand what you mean with your question. I do not understand it. The returned status code should be chosen by what you want to say: 200 = OK, 404 = Not found, ...
Depends on the source of the error. if it's because the server can't do something it should have been able to do, due to having lost access to it's db or something. you use a 500 internal server error with a generic message. Never expose the inner workings of your server when it fails. those error messages goes into the error log.
@@md2perpe Imagine you have a post request with a stringified json object in the body but this json object is not well created and in your code you do a JSON.parse() that fails and you forgot to handle the error that should be a 400 bad request. By default which error code should you throw ? 500 internal server is more you didn't reach the server at all
HTTP was actually never meant to be used for APIs. Hence HTTP status codes are not sufficiently granular. That is an issue. Also HTTP has no way to define types. Overall: REST is nice an easy but gRPC or other are actually better suited.
@@nothingisreal6345 Statelessness is one of the cornerstones of REST. HTTP began as a simple TCP/IP request/response language using TCP to retrieve information from a server in a stateless manner (most TCP/IP applications are stateless). Because the server is stateless, the server has no idea of any history of the interaction between client and server. Therefore, any state information has to be stored in the client. In other words, HTTP has been extremely successful because of its stability, extensibility, and evolvability. So, you were saying?
@@cybrown3369 HTTP is an object-oriented language, and it’s commands are, actually, called methods. (Even though the http portion of a URI is formally listed as the “scheme,” its actually a method.) So, you were saying something about business logic…
it's all fun and games until someone builds a microapi, but during every deploy, it querys (i.e. select * from MyTable) the table it is responsible for and caches the result
Every time I’ve tried to create a RESTful API, it never really fits what I need, and I end up just creating my own API that absolutely does not follow any REST patterns. 🤣
It's absolutely bonkers to me that EVERY course on rest API doesn't include managing relationships in your data. It should be mandatory to include managing types of relationships.
Your kidding right? After having a separate section on using the http methods and your using a POST method to REQUEST data that should be in a GET request? Looks like your a junior too.
This was horrible on so many levels. Coder One? Seriously? I watched the entire video. I learned nothing because you're not saying anything interesting to begin with and I'm an experienced developer. But I had to see it because it's like a car crash. It's hard to avert the eyes.
Amazing how you expect to have the holy grail of knowledge but if you're out there learning programming for years, you should we'll know that every single developer will try to explain, but not 100% accurate or the way you want to be taught. Yet, you're here making your destructive criticism as if you paid him to make this video for you
@@jkf16m96 REST stand for REpresentational State Transfer. Did you know? What's it for? What does that mean? Nothing is explained. It's also telling you to do things REST explicitly prohibits. It's a bad video.
@@abdulazeez.98 I wonder too. As far as languages go. I find javascript to be the easiest to read for us humans. I would never use Rust as explanatory code for example. It's got too much unrelated stuff going on in the form of verbose typing. (I'm aware he was "using" typescript, but he wrote in plain js for the examples here. And that is valid typescript too)
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.
I couldn’t agree more.
from my 2 years as junior software engineer, as long as you have the CONSISTENT RESPONSE OF DATA all over your APIs endpoint, then it will be just fine.
We (the company) recently used a third-party vendor to get us a payment point on line banking service for our app. Unfortunately, the response for each APIs from the third party is inconsistent, causing us a problem, like we literally have to create more tables in our database, and suffer inconsistent data return. It f*cked up me as the fullstack developer for the admin side, and my friends as the fullstack developer for the client side.
HTTP codes, methods, and url naming mistakes is still i can tolerate, but inconsistent response all over the APIs... That is a f*cked up one that just might lose you a job.
Yeah, some google APIs are abysmal
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.
Alternatively the response could come with 2 lists in the payload, one with posts and one with authors, and then you can cross-match the post's authorId with the author's id. Then duplicates don't appear in the authors list, and it can be trimmed to not include users that aren't authors.
How do you know the ratio of post x user? Today you may have 1 or 2 Users only, however as your API grows you can't be sure about this ratio (e.g. StackOverflow)
@@guilhermeferreirabr as I said "it depends on type of data", in some cases you know, in some cases you don't know. As an pure example (just made up), you can have software for bills in restaurant. You can be almost sure that you will have few tens of waitress per restaurant who creates a bill. But you will have thousands of bills. And if you change waitresses more times than you have customers, than you have bigger problem than not optimal API. Than if you want some report for restaurant per month. You will get long list of bills but there will be only few waitresses across this bills.
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.
thanks for sharing such an insightful comment but in the end, REST does not promote optimization (i.e you need to call multiple api to get enough data you need)?
Relationships just don't work in REST, in my experience. It's also a pain to figure out how you would alter a many-many relationship. I've seen many people try, but it's always been meh at best.
I love the simplicity of a good REST API, but it's also very important to be cognizant about when your model breaks down,and this is the kind of problem GraphQL was built to solve.
@@free2idol1 Yep, kind of. We should use other techniques to overcome some performance limitations when we face them.
Consider the analogy with SQL - you have two Tables: Users and Posts. I believe no one will agree that stating the rule as "Always JOIN the tables to optimize your calls" makes sense. Or like "Always create INDEXes for all of your columns". In some cases, it's reasonable, in - it's will screw up your performance completely. And if you think about what's going on behind your API when you include soresource resourse the (like in exthe ample in video) - it will be achieved exac with additional Subqueries or JOINs, which also havea price, regardless of do consumers need that info or not. So, even that folding can be considered as a way toptimizese problematic calls, it's far froa m "rule of thumb" to rely on by default. I would rather say that you need to hava really strics reasons for such a folding.
@@ugentu thanks for your reply.
If this is the case, then does REST only applies for simple CRUP app (show, create, edit only 1 resource at a time)?
And if my project has lots of apis that need multiple JOINs for fetching, multiple updating/creating action under the hood, then I'd go against REST and choose GraphQL as others recommend?
@@free2idol1 Yes, like than. But there some more options how to achieve it. Like creating the "Middleware" Service, like BFF, to move all data aggregation login into it, to avoid placing it in frontend. So, it will expose It's interface in a way best suits frontend.
But, REST isn't a all-or-nothing choose.
There a different steps on the RESTfull way, and you can stick on 'earlier" stages it that's suits your needs.
One thing is to maintain the public API that will be available for millions users. And another - just an API for your home page.
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.
This is why graphql is nice
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.
Your explanation seems super good. As a newbie i'm curious why there is a colon infront of id? why not just post/id, what's with post/:id?
@@jordanb9363 The 'posts' and 'author' part are fixed text, while the ':id' part would be a variable, to be replaced with the ID number.
You use 'posts' to indicate access to the posts data. Then you select a specific record by the id. Then you tell that you want the author part of this record. So for post with ID 4242 it would be /posts/4242/author
@@jordanb9363 colon means variable
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.
Folks who want to learn about REST should start with the thesis: www.ics.uci.edu/~fielding/pubs/dissertation/abstract.htm
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.
And here's a link to someone explaining REST in a helpful way: th-cam.com/video/pspy1H6A3FM/w-d-xo.html
The uri addresses a resource. The content and mime types address the format of the resource. Version usually related the format of the json and should correctly be addressed in this manner or a separate header
api/v1/posts may have a different implementation than api/v2/posts that is why they are considered unique. Maybe api/v2/post has more property or has a different property than api/v1/posts.
Hey, thank you for the links! This is some quality stuff I wish someone told me about earlier.
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
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
Hi,
I have my Excel file which is updated through an odbc connection. But how can I sync that Excel data into Google Sheets that could be updated automatically in periodic intervals. Any Solution?
Thanks
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.
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
hello could you help me understand what I could do with my APIs by using them in gpt customs
why you said no verb, but you make store-inventory api?
11:40 - i had to use a digital coin API and it was giving all the info so i had to manually take what i needed so for me it is a bad practice when there is a lot of data in that entity.
Dang. I dont know about HTTP Caching before watching this video.
Great insight. Thanks a lot!
Be careful with caching. Only use for static data that never changes, never be updated or deleted. Any other case, avoid it. I think his info on that is incomplete.
Caching done wrongly creates the most frustrating, untraceable bugs in software dev.
@@awmy3109 Or when data is changed you can revalidate cache. Cache response from Headless CMS api, but when admin is changed something, revalidate it. But that's outside of this video probably
What’s theme you use ?
I often see 404 used instead of 204. 404 is, among others, for inexistent resource access, while 204 is a successful call but without returnable content. Correct me if I'm wrong.
me: Pleas add this to db
server: sure, 404 no content found
me: ??
Yeah 404s are overused and to be considered extremely unreliable regarding the actual non-existence of a resource. At most they mean, "the resource is currently unavailable. It may or may not exist and this may or may not be temporary"
For example, a misconfigured proxy in the middle may return 404 (e.g. an nginx that failed to load its config due to a typo).
Thanks for the video, i knew some of these good practices but the cache & optimization was a new thing to learn
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?
You can have another endpoint like "/users/me" for the owner user
that is achieved thru authorization. which you might want to handle for all protected endpoints separately before processing the request.
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.
REST API Mistakes Every Junior Developer should Avoid: thinking GraphQL can solve their problems
While it might not solve all your problems. especially not on small apps with only a few post types due to a lot of code overhead. it's far easier to work with for pure frontend devs.
Many juniors and a fair number of senior devs still manage to make a garbage API's with it by not following the standards hammered down in the design documents however. There is no defeating garbage coders in the end...
And when I have multiple POST controllers, what would the names look like, for example three POST controllers, Create Password, Create User, and Login?
Make the end points easy and simple
Definitely read the hateos guide and steal some inspiration from graphql and make some of your controller functions where they could do many different exclusive actions depending on the inputs.
Maximize your use of route params
Just user _ post delete put/patch
Sometimes u can set all the fields at once in updates but youll want separate end point to handle password updates
Perfect, thank you so much Eslam for this very helpful video.
Why do you use
const setCache = function (...) { ... };
and not
function setCache(...) { ... }
?
const setCache is a function expression and function setCache is a function definition.
This is valid:
setCache();
function setCache() { console.log("foo");
This is invalid:
setCache(): // an error is thrown
const setCache = function() { console.log("bar"); }
@@philippebaillargeon5204 That still doesn't explain why the second one is used here.
@@md2perpe it is used to not pollute the global scope, cause the function expression is not available everywhere in the scope and it's also good if you need to put a function into a callback.
Probably just a style thing. I mix up all unless I want to about this confusion within in a child function
@@md2perpe it's just a styling thing (ugly imo to use the const blah = function, but valid JS).
I didn't know about this caching middleware. Thank you for sharing
404 response cannot be agreed.
I think 404 status code corresponds to when information about the url is not found on the web server (for example, nginx) for that path.
If the user does not exist, you can simply return an empty array or an empty object.
I would argue Status Code 204 (The server successfully processed the request, and is not returning any content) with an empty (whatever)
@@romanstingler435 When you delete a user, you receive a status code of 204 and expect a status code of 204 even if you do it again and again.
However, in the case of get, I think it is possible if only the user returns. I don't know in general situations where values from other tables as well as users are joined and returned.
In addition, if the server uses the response type for get as fixed as shown below, 204 may not be a good way.
{
request_date: Date...
data: {...someuser}
}
But I also return 404 when there is no user.
404 is exactly for such a case. Returning an empty array for a resource that is supposed to return an object - is far more confusing. It's like asking "Give me a Cola" in the store but getting an Empty bottle crate instead.
@@ugentu I disagree.
To take your analogy:
404 is like asking to get the list of the cars avaliable to rent in a McDonalds
200 with empty array is like asking for a ice cream in a McDonald's
404 happens when the client wants to access a resource that does not exist, and it's the client's fault. The client made a bad request that the server can't do anything about it.
200 happens when the request was correct, but there was just no response. The client asked for ice cream in a McDonald's, which is a valid request, but the ice cream machine was broken (the resource doesn't exist).
Summary based on scaffold what I've been use for my project
Route Methods
get /Models ----> all index
get /Models/:id ---> show single record
post /Models ---> create a new record
put /Models/:id ---> update a record
delete /Models/:id ---> delete a record
Http or https just transmission layer, define your own business status code keep the compatiblity between different transmission layers. Hance stop mapping http status to business please.
And, the protocol of http status code is prior agreement in the http reference, the implementation of http client library follows the reference strictly. That's means you may get unexpeceted expection from the http client library during develoment when you assign additional means to an existing http status code.
At last, assign private protocol over a stander protocol is against the best practice.
And very important, REST APIs should be stateless!!!
But this video was more about HTTP and when you make that bad choice of using HTTP, at least always use HTTPS (also in dev and catch your issues with certificates early).
But a far better protocol to send your messages over is a Message Queue (AMQP). At least that gives guaranteed delivery, to the subscriber channels guaranteed in order delivery and unlike HTTP has routing abilities. Kafka and RabbitMQ are far better choices than REST over HTTP(S) is.
Is it really all that it takes to start caching requests? 🤔
I remember working with an app developer. He wanted me to always return status code of 200 on every request, that got me really irritated even when I tried explaining to him why we shouldn't, he was being rude and claimed he's a senior dev. I wish he could see this video and be humble.
Honestly, you should restrict the use of HTTP status codes to very early failures. Any errors (beyond 403, I suppose) emitted by the implementation code should be encoded in the response body instead.
@@senkrouf This is not how http protocol works bro
I work on FE and I kid you not I received a status 200 response which had a JSON object which had `statusCode: 500` and errorMessage which said user not authorized.
Why it was not just 401 escapes me.
I have daubed it the Schrodinger response.
@@senkrouf You are indeed status 200 dev according to your own definition.
@@senkrouf It was more aimed at your approach to status codes. No mater what happens it is all ok
The worst you can do is ignore the content type header and make your api vulnerable for csrf
GraphQL probably solves that problem a bit better, as you have a full control over the selected data from the tree of the model
Imagine you handled multiple status in you app like 403, 404... If you still have an error
What will be the default status code you will choose for a rest endpoint ? Status code 409 ?
What do you mean with "a rest endpoint 409"?
@@md2perpe I am speaking about status code 409 it is the code you use by default or you use another one
@@AnotherSmartMonkey It's difficult to understand what you mean with your question. I do not understand it.
The returned status code should be chosen by what you want to say: 200 = OK, 404 = Not found, ...
Depends on the source of the error. if it's because the server can't do something it should have been able to do, due to having lost access to it's db or something. you use a 500 internal server error with a generic message. Never expose the inner workings of your server when it fails. those error messages goes into the error log.
@@md2perpe Imagine you have a post request with a stringified json object in the body but this json object is not well created and in your code you do a JSON.parse() that fails and you forgot to handle the error that should be a 400 bad request. By default which error code should you throw ?
500 internal server is more you didn't reach the server at all
Thank you for making videos like these.
Thanks man
HTTP was actually never meant to be used for APIs. Hence HTTP status codes are not sufficiently granular. That is an issue. Also HTTP has no way to define types. Overall: REST is nice an easy but gRPC or other are actually better suited.
You literally don’t know what you’re talking about. (I mean, you probably think you do, but you don’t.)
@@charlessimms84 Go and stupid somewhere else
@@nothingisreal6345 Statelessness is one of the cornerstones of REST. HTTP began as a simple TCP/IP request/response language using TCP to retrieve information from a server in a stateless manner (most TCP/IP applications are stateless). Because the server is stateless, the server has no idea of any history of the interaction between client and server. Therefore, any state information has to be stored in the client. In other words, HTTP has been extremely successful because of its stability, extensibility, and evolvability.
So, you were saying?
Willing to match your business logic to a technical protocol is just heresy
@@cybrown3369 HTTP is an object-oriented language, and it’s commands are, actually, called methods. (Even though the http portion of a URI is formally listed as the “scheme,” its actually a method.)
So, you were saying something about business logic…
TLDR; learn the REST definition before implementing a REST service. Good practical 101 primer for designing RESTful web services.
I agree, you need to cut last 15 minutes, because this mistake will cost a lot.
You keep saying “insinuate” when you mean “imply.” “Insinuate” includes a connotation of being sneaky or underhanded.
Such an excellent video!
You forgot the period after the T in R.E.S.T.
Cache only static data that never changes otherwise avoid it like the plague.
the best decision i made to day is to watch this video ...
it's all fun and games until someone builds a microapi, but during every deploy, it querys (i.e. select * from MyTable) the table it is responsible for and caches the result
Every time I’ve tried to create a RESTful API, it never really fits what I need, and I end up just creating my own API that absolutely does not follow any REST patterns. 🤣
the CORS is another part to secure the API
Honestly this is basic if you learned from the right instructors
It's absolutely bonkers to me that EVERY course on rest API doesn't include managing relationships in your data. It should be mandatory to include managing types of relationships.
I think, no content should return 204.
why does he sound like he's getting choked?
People overuse Error 400 and 404. Where most often we should return 422 with more context/details in the Error payload
thx sir help for development
So it needs to take forever to develop and slow and in the end not working too like big M$ has 😁
Not convinced
Your kidding right? After having a separate section on using the http methods and your using a POST method to REQUEST data that should be in a GET request? Looks like your a junior too.
😅🤣
Can you add the timestamp? I can't find what you're talking about.
@@biskitpagla around the 11:15 mark. There is code written to post data to the record while making a get request.
Where exactly? Could you provide timestamp?
@@GreyDeathVaccine objection. And and answered
open the noor
This was horrible on so many levels. Coder One? Seriously? I watched the entire video. I learned nothing because you're not saying anything interesting to begin with and I'm an experienced developer. But I had to see it because it's like a car crash. It's hard to avert the eyes.
Amazing how you expect to have the holy grail of knowledge but if you're out there learning programming for years, you should we'll know that every single developer will try to explain, but not 100% accurate or the way you want to be taught.
Yet, you're here making your destructive criticism as if you paid him to make this video for you
@@jkf16m96 REST stand for REpresentational State Transfer. Did you know? What's it for? What does that mean? Nothing is explained. It's also telling you to do things REST explicitly prohibits. It's a bad video.
Man you give lessons about best practices and you're using express..no offense..
What is the problem with express?
@@abdulazeez.98 I wonder too.
As far as languages go. I find javascript to be the easiest to read for us humans. I would never use Rust as explanatory code for example. It's got too much unrelated stuff going on in the form of verbose typing. (I'm aware he was "using" typescript, but he wrote in plain js for the examples here. And that is valid typescript too)
Good content but your voice is irritating dude.. hot large coffee ..
Bot'l of Wa'r 😂