Introduction
Hello everyone! In today's article, we will be discussing RESTful APIs, which is a continuation of last week's article on HTTP. Before we begin, I highly recommend reading the previous article to gain a better understanding. You can find it at the following link ππ½
Understanding HTTP Basics for Beginners
That being said, Letβs dive right into the article π
Before we go further letβs remind ourselves of what an API is ππ½
What is an API?
An Application Programming Interface (API) is a set of rules and protocols that enables different software applications to communicate and interact with each other. APIs act as intermediaries, allowing developers to access and utilize the functionality of another software system, such as retrieving data or performing operations. Letβs take an example ππ½
If you are like me and you love listening to music, You can use the Spotify app to enjoy your favorite songs, but did you know that behind the scenes, there's a powerful REST API that lets you request and retrieve Spotify's raw JSON data? It's like having a backstage pass to all the music-related information you could ever want!
So, APIs make it possible for apps to talk to each other, share data, and perform amazing tasks.
What is a REST API?
REST API (or RESTful API) is basically about communication between client and server and vice versa and it is also a way to build web services that adhere to the principles of REST.
REST stands for Representational State Transfer. It is an architectural style used for designing networked applications.
These APIs allow different software systems to communicate with each other over the internet.
π‘ We are going to see some examples later in this article. So it is completely fine if you donβt understand it yet.
Key Principles of REST APIs
Here are some key aspects of REST APIs ππ½
Client-Server Architecture: REST APIs follow a client-server architecture, where the client makes requests to the server, and the server responds with the requested data or performs the requested action.
Stateless: REST APIs are stateless, meaning that the server does not store any information about the client's state between requests. Each request from the client must contain all the necessary information for the server to understand and process it. And this leads to web applications that are reliable.
HTTP Methods: REST APIs utilize the standard HTTP methods for performing different actions. The most common HTTP methods used in RESTful APIs are:
GET: Retrieves a representation of a resource.
POST: Creates a new resource.
PUT: Updates an existing resource.
DELETE: Removes a resource.
Additionally, there are other methods like PATCH, HEAD, and OPTIONS that have specific uses within the REST architecture.
Resource-Based: REST APIs are built around resources, which are the entities that the API exposes. Resources can be identified using Uniform Resource Identifiers (URIs), which are typically represented as URLs. For example,
/users
can be the URI for a collection of user resources, and/users/123
can represent a specific user with the ID 123. All these things are going to make much sense when we see the practical side of things.Representation of Resources: REST APIs use various media types, such as JSON (JavaScript Object Notation), XML (eXtensible Markup Language), or even plain text, to represent the resources being exchanged between the client and the server. JSON has become the most popular choice due to its simplicity and ease of use.
Uniform Interface: REST APIs follow a uniform interface, which means that they have consistent ways of accessing and manipulating resources. This uniformity simplifies the understanding and usage of the API.
π Request and Response Cycle in REST APIs
The request and response cycle in REST API simply involves the exchange of information between a client and a server using the HTTP protocol. The client initiates a request to the server, specifying the desired operation and any required parameters. The server processes the request and generates a response containing the requested data or indicating the outcome of the operation. Let's go through an example to get a better understanding ππ½
π‘ This example will be based on the key principles we discussed earlier. So, it is important to understand each of them first before going through this example.
Example
Letβs say we have a REST API for a blog platform, and we want to retrieve a list of blog posts. Here are the steps to achieve that ππ½
The client sends a GET Request The client initiates a GET request to the server's API endpoint that handles retrieving blog posts. The request may look like this ππ½
GET /api/posts HTTP/1.1 Host: example.com
As you can see above, the client is requesting all blog posts by accessing the "/api/posts" endpoint.
The "Host" header specifies the domain or IP address of the API that the client is visiting. In this case, the client is making a GET request to the "/api/posts" endpoint of the "example.com" domain.
The server processes the Request The server receives the GET request and identifies the corresponding endpoint ("/api/posts"). It understands that the client wants to retrieve a list of blog posts.
The server retrieves Data The server accesses the underlying database or data source to fetch the required data. In this case, it retrieves the list of blog posts.
The server generates a Response Based on the retrieved data, the server constructs an HTTP response containing the requested blog posts. The response may look like this ππ½
HTTP/1.1 200 OK Content-Type: application/json { "posts": [ { "id": 1, "title": "Introduction to REST API", "author": "John Doe", "content": "All you need to know about REST" }, { "id": 2, "title": "Building Scalable APIs with Node.js", "author": "Jane Smith", "content": "Build Scalable APIs" }, ] }
From the code above, the server responds with a "200 OK" status code, indicating a successful request. The response body contains a JSON representation of the blog posts, including their titles, authors, and other relevant information.
The Server sends the Response The server sends the generated response back to the client over the HTTP protocol.
The Client receives the Response The client receives the response from the server. It can then extract and process the data contained within the response body.
If you read the previous article about HTTP, you will get a better understanding of what the response header really is.
Now that we've seen how the request and response cycle works, let's now build our own REST API which will allow us to create, read, update, and delete data using HTTP methods such as GET, POST, PUT, and DELETE.
To accomplish this, we'll need to follow a few steps:
Define the resources: Determine what kind of data or entities the API will handle. For example, if we were building a REST API for a blog, our resources could include articles, comments, and authors.
Design the endpoints: Determine the URL endpoints that will represent each resource and the corresponding HTTP methods that will be used to perform operations on these resources. For example:
GET /articles
to retrieve a list of articlesPOST /articles
to create a new articlePUT /articles/:id
to update an existing articleDELETE /articles/:id
to delete an article with a specific ID
Implement the server-side logic: Write the server-side code to handle these API endpoints. This involves handling incoming requests, parsing the request data, performing the necessary operations on the data (e.g., querying a database), and constructing and sending back the appropriate response.
Test the API: We will be using tools like Postman to test the API endpoints. Send requests to the endpoints and verify that the responses are as expected. Make sure to test different scenarios, such as successful requests, error cases, and edge cases.
Document your API: It's important to document your API, including the available endpoints, request/response formats, and any additional details or constraints. This documentation will help other developers understand how to interact with your API.
Now letβs jump into the example proper π
Set up the project:
Create a new directory for the project on your favorite code editor (Weβll be using vscode in this article)
Open your terminal ( CTRL + ` ).
Initialize a new Node.js project by running the command:
npm init -y
.Install Express.js by running the command:
npm install express
.
Create a new JavaScript file, e.g.,
server.js
or any name you prefer.Import the necessary modules and set up the Express.js server ππ½
const express = require('express'); const app = express(); const port = 3000; // You can choose any available port // Middleware to parse JSON requests app.use(express.json()); // Define your routes and API endpoints here // Start the server app.listen(port, () => { console.log(`Server is running on http://localhost:${port}`); });
Define your API endpoints
We are going to be breaking this part down into segments for better understanding ππ½
First Segment
const express = require('express'); const app = express(); const port = 3000; // You can choose any available port
This segment imports the Express framework and creates an instance of the Express application.
It also sets the port number on which the server will run. In this case, it's set to 3000, but you can choose any available port.
Second segment
app.use(express.json());
This line adds a middleware to the Express application. The
express.json()
middleware parses incoming requests with JSON payloads and makes the parsed data available inreq.body
Third segment
let articles = [ { id: 1, title: 'First Article', content: 'Lorem ipsum dolor sit amet.' }, { id: 2, title: 'Second Article', content: 'Pellentesque ac mi sit amet turpis.', }, ];
This initializes an array called
articles
that will store the article objects.It includes two sample articles as initial data. Each article has an
id
,title
, andcontent
.Fourth segment
app.get('/articles', (req, res) => { res.json(articles); });
This defines a GET endpoint at
/articles
that retrieves a list of articles. When a GET request is made to this endpoint, it responds with thearticles
array in JSON format.Fifth Segment
app.post('/articles', (req, res) => { const newArticle = req.body; articles.push(newArticle); res.status(201).json(newArticle); });
This defines a POST endpoint at
/articles
for creating a new article. When a POST request is made to this endpoint, it extracts the new article object from the request body (req.body
). The new article is then added to thearticles
array usingarticles.push(newArticle)
. It responds with a status code 201 (Created) and the newly created article in JSON format.Sixth Segment
app.put('/articles/:id', (req, res) => { const articleId = req.params.id; const updatedArticle = req.body; articles = articles.map((article) => { if (article.id === parseInt(articleId)) { return { ...article, ...updatedArticle }; } return article; }); res.json({ id: articleId, ...updatedArticle }); });
This defines a PUT endpoint at
/articles/:id
for updating an existing article. The:id
part in the endpoint URL is a placeholder for the article ID. When a PUT request is made to this endpoint, it extracts the article ID from the URL usingreq.params.id
. It also retrieves the updated article object from the request body (req.body
). The code then searches for the article with the corresponding ID in thearticles
array. If found, it updates the article's properties with the properties from the updated article using the spread operator ({ ...article, ...updatedArticle }
).Finally, it responds with the updated article object in JSON format.
Seventh Segment
app.delete('/articles/:id', (req, res) => { const articleId = req.params.id; const deletedArticle = articles.find( (article) => article.id === parseInt(articleId) ); if (!deletedArticle) { return res.status(404).json({ error: 'Article not found' }); } articles = articles.filter((article) => article.id !== parseInt(articleId)); res.status(204).end(); });
This defines a DELETE endpoint at
/articles/:id
for deleting an article. The:id
part in the endpoint URL is a placeholder for the article ID. When a DELETE request is made to this endpoint, it extracts the article ID from the URL usingreq.params.id
. The code then searches for the article with the corresponding ID in thearticles
array. If the article is not found, it responds with a status code 404 (Not Found) and an error message in JSON format. If the article is found, it removes the article from thearticles
array using thefilter
method.Finally, it responds with a status code 204 (No Content) to indicate successful deletion.
Eight Segment
app.listen(port, () => { console.log(`Server is running on http://localhost:${port}`); });
This starts the server and listens on the specified
port
.Once the server starts, it logs a message indicating the server is running and the URL where it's accessible.
Here is the code in full ππ½
const express = require('express');
const app = express();
const port = 3000; // You can choose any available port
// Middleware to parse JSON requests
app.use(express.json());
// Initialize articles array with sample data
let articles = [
{ id: 1, title: 'First Article', content: 'Lorem ipsum dolor sit amet.' },
{
id: 2,
title: 'Second Article',
content: 'Pellentesque ac mi sit amet turpis.',
},
];
// GET /articles - Retrieve a list of articles
app.get('/articles', (req, res) => {
res.json(articles);
});
// POST /articles - Create a new article
app.post('/articles', (req, res) => {
const newArticle = req.body;
articles.push(newArticle);
res.status(201).json(newArticle);
});
// PUT /articles/:id - Update an existing article
app.put('/articles/:id', (req, res) => {
const articleId = req.params.id;
const updatedArticle = req.body;
articles = articles.map((article) => {
if (article.id === parseInt(articleId)) {
return { ...article, ...updatedArticle };
}
return article;
});
res.json({ id: articleId, ...updatedArticle });
});
// DELETE /articles/:id - Delete an article
app.delete('/articles/:id', (req, res) => {
const articleId = req.params.id;
const deletedArticle = articles.find(
(article) => article.id === parseInt(articleId)
);
if (!deletedArticle) {
return res.status(404).json({ error: 'Article not found' });
}
articles = articles.filter((article) => article.id !== parseInt(articleId));
res.status(204).end();
});
// Start the server
app.listen(port, () => {
console.log(`Server is running on http://localhost:${port}`);
});
Save the changes in your
server.js
file.Start the server by running the command
node server.js
in the terminal.Open Postman or any other API testing tool. (But weβll be using Postman in this article)
Use Postman to send requests to your API endpoints:
For
GET /articles
, send a GET request tohttp://localhost:3000/articles
.For
POST /articles
, send a POST request tohttp://localhost:3000/articles
with a JSON payload representing the new article.For
PUT /articles/:id
, send a PUT request tohttp://localhost:3000/articles/{articleId}
with a JSON payload representing the updated article.For
DELETE /articles/:id
, send a DELETE request tohttp://localhost:3000/articles/{articleId}
.
π‘ You can leave a question in the comment if you get stuck in any part of the article
Conclusion
That's all, everyone! Congratulations on reaching the end of this article π π. I understand that everything we've covered might seem overwhelming, especially if you're not familiar with Node.js or Express.js. However, I strongly recommend you revisit the previous week's article and consider watching some tutorials on Express.js and Postman to grasp the basics of how they work. This will help you gain a better understanding of the concepts discussed in this article. You've got this! Have a wonderful weekend, and I'll see you next week π