Hey, DEV.to community!
Web development has been changed drastically in the past few years. Websites used to use template engines to render the page and send it to the client. There used to be SOAP protocol to retrieve information from another server which usually used XML as its specification language. Later on, RESTful appeared and people started using it with JSON. Nowadays, RESTful is something that controls the whole website instead of only the remote parts. Showing a post, showing the list of posts, user data and etc, all are done by RESTful instead of server-rendered representation. Bottom line, RESTful is very important these days in web development and other software that need to connect to a server and retrieve some data, and this importance urges us to use a good pattern and related tools in order to achieve the best quality and assure the maintainability of the system.
In my experience of developing RESTful APIs I've encountered many issues and gained some information while going on. Here I am sharing what I've learned and how I design RESTful APIs as well as the answer to frequently asked questions.
What is RESTful?
RESTful is an architectural style of designing an end-point in which software can retrieve data. RESTFul APIs usually return JSON data as it is readable by many programming languages with no effort.
Is it possible to return anything else than JSON?
Technically speaking, yes! RESTful is just a pattern of design and doesn't specifically make you use JSON. A RESTful API can return plain text, XML, CSV, or any other format but since the community already has chosen JSON it is better to go on with that. Many tools used to design a RESTful API assume your end-points to be returning JSON and nothing else.
For further information on how RESTful API's should act please refer to https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven. This information is added here thanks to:
How to design a RESTful API server?
A RESTful API server can be designed using almost every back-end programming language. We will discuss this later in this article. Here we are trying to understand the pattern of RESTful API. What usually is needed in an application is the ability of CRUD. CRUD stands for Create, Read, Update, and Delete. These are four things every application has. Just like creating a post, reading a post, updating a post, and finally deleting the post. In a RESTful API, you would create a path (route) called /posts
. The usual naming convention is using the plural form. CRUD has four actions, so we need to assign four actions to this path as well. The HTTP protocol has four methods suitable for this matter, being POST
, GET
, PUT
, DELETE
. These methods can be respectively used for CRUD actions. Here is an example:
GET /posts # Get the posts list
GET /posts/{id} # Get the post with id of {id}
POST /posts # Create post
PUT /posts/{id} # Update the post with id of {id}
DELETE /posts/{id} # Delete the post with id of {id}
A route prefix like /post
is often called a collection as well.
Don't use abbreviated pathnames like /p
for /posts
. This makes it harder to remember what the end-point does.
Never use verbs in a pathname. This means that the following routes are not considered as a good RESTful API:
POST /createPost
POST /deletePost
POST /updatePost
HTTP methods aren't that different when it comes to POST
, PUT
, and DELETE
. But using POST
for every route makes it ambiguous.
Why do we need to use the plural form of nouns?
Using a singular form can be confusing. Imagine using the route /post
but receiving all of the posts! It doesn't make sense!
Why shouldn't we use verbs in pathnames?
Using a verb in a pathname is going to make the API end-points much more than needed. But in the case of using HTTP methods on the same route, you have a very concise and easy-to-understand API.
For example, can we use GET to create a record?
Again technically speaking, yes! But you shouldn't, as the GET
method is conventionally used for retrieving data. And even if you pay attention it makes more sense to say "Get that post" to get that post's data instead of calling it "Post that post" to get that post's data.
Nesting
Imagine you have a post and you want to retrieve its comments as well. You can use the nesting method to represent the belongings of a resource (like a post) or in a hierarchical situation.
Since you already have a route for GET /posts/{id}
you need to add a set of routes as below:
GET /posts/{id}/comments # Get all comments of post with id of {id}
GET /posts/{id}/comments/{cid} # Get the comment with id of {cid} of post with id of {id}
POST /posts/{id}/comments # Send a comment belonging to post with id of {id}
PUT /posts/{id}/comments/{cid} # Update the comment with id of {cid} of post with id of {id}
DELETE /posts/{id}/comments/{cid} # Delete the comment with id of {cid} of post with id of {id}
Querying
Not always you need to get all the posts or all data of a specific resource. Sometimes you need to filter it, sort it, or paginate it. Despite the fact that how you do this matter in your back-end code you should follow some rules to make your end-points clearer:
- Use a full name for the query.
Do not use
p
for paginating orf
for filters. - If your query param takes more than one word, separate them with an underline (often referred to as snake_case). For instance, never use
limitPerPage
orlimitperpage
, instead you should uselimit_per_page
. - Do not ever combine two data into one.
Although some people rather combine some data, I strictly dislike this behavior since it reduces the readability. For example, when ordering the date you should use two query params called
order_by
andorder
. As an example, a route should be like/posts/?order_by=date&order=asc
instead of/posts/?order_by=date:asc
or/posts/?order_by=date:desc
.
Finally, a route with queries should look like this:
GET /posts/?page=1&limit_per_page=20&order_by=date&order=desc
Instead of this:
GET /posts/?p=1&lpp=20&&o=date:desc
Errors
Whenever a task is done successfully return the response with code 200. Whenever a route is not found return the response with code 400. Some programmers forget to do this and they only mention the result in the JSON response instead of in the HTTP response itself as well. Returning a code makes it much easier to handle responses. Here is the list of standard HTTP response codes: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
An error should as well contain a human-readable message and a domain-specific message that only your application can understand for later usages. For example, this can be an error message:
HTTP/1.1 403 Forbidden
...
{
"status": 403,
"err_code": "permission_denied",
"message": "User doesn't have enough privileges"
}
A fault-tolerant API should not return the error message generated by the server or language. In case any error happens make sure to handle it (for example by using a try/catch block) and return an appropriate JSON response.
Version your API
Over time you might need to change some of your APIs functionality. This might as well break the applications using it. So in order to prevent this problem version your API and let the previous API be there for a while until you replace all the previous APIs with the new API. One of the most used ways of doing this is prefixing all of the API end-points with the version. For instance:
/api/v1/post
What languages/frameworks and database should we use to design a RESTful API server?
As mentioned before, RESTful is just a commonly accepted pattern is not a language-specific thing. Thus you can design a RESTful API server using your own preferred language/framework.
What is really common as I am writing this post is the Express framework. It is super easy and fast to make a RESTful API using Express. Express is built on top of Node.js so you should know JavaScript to utilize this framework.
Another option can be Laravel. Laravel provides almost every asset needed for a RESTful API out of the box, like authentication and routings. Laravel is written in PHP.
These mentioned frameworks are completely personal opinionated. You can go on with any other option. I've mentioned these since I've tried many options and found these easy and fun to work with.
A database can be a huge matter when writing any application. A RESTful API server is no exception as well. Your database should be fast and maintainable. Depending on the needs of your application you should choose your database. If you need database-side relations you should go with an RDBMS like MySQL or PostgreSQL. If you are planning on growing your database horizontally you'd better choose MongoDB.
Designing a RESTful API doesn't necessarily need to be done by one programming language/framework. An approach can be microservices written in multiple languages. You might need multiple databases based on their usages or multiple programming languages based on their useful libraries or performances in specific situations. This is where microservices can help.
Imagine you are assigned to design an API for an image sharing and processing website and you want it to be super fast and you choose Express/Node.js for your back-end code. But you know that Python has many good libraries for AI or image processing. Here you can implement Python as a microservice to help you complete your main API server.
Testing your API server
While designing an API server (be it RESTful or not) you need to test it every time you make a new route or make changes to the previous ones. It is impossible to reload the browser every time or make a form using HTML to send the data back and forth along with custom headers. So what you need is API testing software. There are many tools out there but what I usually prefer to use is Postman. It is free and simple.
Postman features every kind of feature you need to test your API, including all HTTP methods, custom headers, params, and so on. It prettifies the JSON response and also generates you the code needed to make an HTTP request as you defined in many languages and cURL.
I hope you've enjoyed this article!
BTW! Check out my free Node.js Essentials E-book here:
Top comments (12)
you have not described REST but have confused HTTP to be synonymous with REST:
Thanks for reading my article. As the title suggests I tend to explain some of the ways I like to organize my API server. Here I am not trying to explain how RESTful systems should be designed. Still thanks for the information.
right on, but you raise the question: "What is RESTful?" and then subsequently give a definition that does not consider the constraints of REST or specifically HATEOAS.
you say:
"RESTful is an architectural style of designing an end-point in which software can retrieve data using the HTTP protocol."
this is an incomplete definition. as Roy fielding suggests, if you want to use a buzz word, stick with CRUD and HTTP, but you do not need to confuse the reader by mentioning REST if you are not interested in developing, describing, interpreting or explaining REST architectural style.
we want to focus on the essentials and allow developers to learn the right concepts
I have rephrased the sentence, thanks for helping me out. Tell me if I need to change to anything else. I'd appreciate it.
Thanks again for the information. I've updated the post and added this link for further studies in case anyone wanted to read.
If you'd like to test your APIs online, try Hoppscotch - A free, fast and beautiful API request builder used by 100k+ developers.
Project is open source:
hoppscotch / hoppscotch
👽 A free, fast and beautiful API request builder used by 100k+ developers. https://hoppscotch.io
Also supports WebSocket, SSE, Socket.IO, MQTT, API Documentation generator, CLI tool, GraphQL playground etc.
If you like to test your endpoints more, you can use Humlix, a tool that generates tests for RESTful APIS. See this article on how Humlix was used to discover bugs in GitLab CI/CD
What make an existing API Restful is its constraints, without those, at least some, is just still an API not restful.
Thanks for reading my article. Do you mean like authentication and authorization?
restfulapi.net/rest-architectural-...
Thanks for this useful information. I aimed to describe the way of RESTful pattern works in this post though rather than how a RESTful server would act. Thanks again.
又有点意思