REST API stands for Representational State Transfer Application Programming Interface. It is a standard way for software applications to communicate with each other. This interface allows you to split your application into the backend and the frontend, with the backend in charge of providing the data and the frontend in change of interacting with the user.
The frontend sends HTTP requests to the backend in response to the user action, and the backend retrieves the necessary data and sent it to the frontend. Once the data is received, the frontend dynamically updates the interface to display the information to the user, providing a seamless and interactive experience.
So far, we've been using Express.js as a fullstack framework, which means it is responsible for handling data retrieval, as well as displaying the user interface. But in practice, it is very common for developers to use it as purely a backend program, giving us more flexible when choosing the frontend technologies.
In this lesson, we are going to discuss how to create the standard REST APIs, using Express.js and Node.js as an example.
Creating REST APIs doesn’t require any new skills, it simply states a set of standards that ensure applications can communicate effectively. REST outlines guidelines for structuring your API, handling requests, and organizing resources to maintain a predictable and accessible interface.
First of all, to set up an API, you must use HTTP methods consistently, and use them for the purpose they are designed:
GET
: Retrieves a resource.POST
: Creates a new resource.PUT
: Updates an existing resource.DELETE
: Removes a resource.
Second, the URL endpoints should be structured clearly and consistently, and they should be created around resources rather than actions. For example,
GET /posts
: Lists all posts.POST /posts
: Creates a new post.GET /posts/:id
: Retrieves a specific post by ID.PUT /posts/:id
: Updates a specific post by ID.DELETE /posts/:id
: Deletes a specific post by ID.
Third, APIs should return data in a predictable, structured format, which is usually JSON.
The response should also come with the correct response code. For example 200 OK
for successful operations, 201 Created
when a resource is created, 404 Not Found
if a resource doesn’t exist, 500 Internal Server Error
if the server encounters an error, and so on.
Lastly, the request made from the client should be stateless, meaning each request should contain all the information the backend needs in order to process that request, as the server should not store client context between requests.
For example, using Express, you can follow the rules listed above, and design the routes like this:
index.js
1import express from "express";
2import postController from "../backend/controllers/postController.js";
3
4const app = express();
5const port = 3001;
6
7app.use(express.json());
8app.use(express.urlencoded({ extended: true }));
9
10app.get("/posts", postController.list); // Retrieve a list of posts
11app.post("/posts", postController.create); // Create a new post
12app.get("/posts/:id", postController.retrieve); // Retrieve a single post according to id
13app.put("/posts/:id", postController.update); // Update a post according to id
14app.delete("/posts/:id", postController.delete); // Delete a post according to id
15
16app.listen(port, () => {
17 console.log(
18 `Blog application listening on port ${port}. Visit http://localhost:${port}.`
19 );
20});
And for the corresponding controllers:
controllers/postController.js
1const postController = {
2 create: async function (req, res) {
3 const { title, content } = req.body;
4 try {
5 console.log(
6 "Creating a new post with title:",
7 title,
8 "and content:",
9 content
10 );
11
12 res.status(201).json({ message: "Post created." });
13 } catch (e) {
14 console.log("Something went wrong.");
15 res.status(500).json({ message: "Something went wrong." });
16 }
17 },
18 . . .
19};
20
21export default postController;
For simplicity, we are going to hardcode the response, instead of actually retrieving the data from database.
Notice that we are returning the response uses json()
instead of render()
, as this API is supposed to send JSON data to the frontend, instead of rendering a page.
By using try catch
block, the error handling mechanism for JavaScript, you can create a system where different responses can be sent to the client according to different conditions.
And lastly, you can access these APIs in the frontend using the same fetch()
method we discussed before.
This lesson is only an introduction for frontend backend separation. In practice, there are many details you need to take care of, such as Cross-Origin Resource Sharing (CORS), state management, and so on.
Manually solving these problems with plain JavaScript will be tiresome, so instead, we'll come back to this topic after we have covered React.js, a frontend JavaScript framework that allows you to create we applications quickly.