What is REST?
REST (Representational State Transfer) is an architectural style for building distributed systems proposed by Roy Fielding in 2000 in his doctoral dissertation. REST is not a protocol or standard, but rather a set of principles and constraints that a system must follow.
API (Application Programming Interface) is an interface for interaction between programs. REST API, respectively, is an API built in accordance with the REST principles.
In simple words, REST API is a way of organizing communication between a client and a server via HTTP protocol, where each resource (data) has a unique address (URL), and it can be accessed using standard HTTP methods.
Basic principles of REST
REST is based on six key principles that define the architecture of the system.
1. Client-Server
The architecture is divided into a client that sends requests and a server that processes these requests and returns responses. This separation allows the client and server to evolve independently of each other.
2. Stateless
Each request from the client to the server must contain all the information necessary to understand and process the request. The server does not store information about the client's status between requests. If authentication is required, the token is transmitted with each request.
3. Cacheable
Server responses must explicitly indicate whether they can be cached. This improves system performance by reducing the number of requests to the server.
4. Uniform Interface
This is a key principle of REST, which simplifies the architecture of the system. It includes four aspects: resource identification through URI, resource manipulation through representations, self-describing messages, and HATEOAS (hypermedia as an application state engine).
5. Layered System
The client cannot determine whether it is connected directly to the end server or to an intermediate node. This allows you to add load balancers, caches, and other intermediate components without changing the client code.
6. Code on Demand
This is the only optional principle. Servers can temporarily extend the functionality of the client by passing executable code, such as JavaScript.
HTTP methods in REST API
The REST API uses standard HTTP methods to perform operations with resources. Each method has a specific purpose:
GET — Receiving data
The GET method is used to read data from the server. It should not change the state of the resource.
// Get a list of all users
fetch('https://api.example.com/users')
.then(response => response.json())
.then(data => console.log(data));
// Get a specific user
fetch('https://api.example.com/users/123')
.then(response => response.json())
.then(data => console.log(data));POST — Create a new resource
POST is used to create new resources on the server.
fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'Ivan Petrov',
email: 'ivan@example.com'
})
})
.then(response => response.json())
.then(data => console.log(data));PUT — Full resource update
PUT replaces the existing resource with entirely new data.
fetch('https://api.example.com/users/123', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'Ivan Petrov',
email: 'newemail@example.com',
age: 30
})
})
.then(response => response.json())
.then(data => console.log(data));PATCH — Partial update of the resource
PATCH updates only the specified fields of the resource.
fetch('https://api.example.com/users/123', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: 'newemail@example.com'
})
})
.then(response => response.json())
.then(data => console.log(data));DELETE — Deleting a resource
DELETE is used to delete a resource from the server.
fetch('https://api.example.com/users/123', {
method: 'DELETE'
})
.then(response => {
if (response.ok) {
console.log('User removed');
}
});
REST API structure
The correct URL structure in the REST API is critical to understanding and using the API.
Resources and collections
In REST, everything is a resource. Resources are grouped into collections:
GET /users - Получить список пользователей (коллекция)
GET /users/123 - Получить конкретного пользователя (ресурс)
POST /users - Создать нового пользователя
PUT /users/123 - Обновить пользователя
DELETE /users/123 - Удалить пользователяInvested resources
Nested URLs are used for related resources:
GET /users/123/posts - Все посты пользователя
GET /users/123/posts/456 - Конкретный пост пользователя
POST /users/123/posts - Создать пост для пользователя
DELETE /users/123/posts/456 - Удалить пост пользователяFiltering and sorting
Use query parameters for filtering, sorting, and pagination:
GET /users?role=admin - Фильтрация по роли
GET /users?sort=name&order=asc - Сортировка по имени
GET /users?page=2&limit=20 - Пагинация
GET /users?search=иван - ПоискHTTP response statuses
The REST API uses standard HTTP status codes to inform the client about the result of the request.
Successful responses (2xx)
200 OK — request completed successfully (for GET, PUT, PATCH)
201 Created — resource successfully created (for POST)
204 No Content — the request was successful, but there is no content to return (often for DELETE)
Client errors (4xx)
400 Bad Request — invalid request (for example, invalid JSON)
401 Unauthorized - authentication required
403 Forbidden — access denied (authenticated, but no permissions)
404 Not Found — resource not found
409 Conflict — conflict (for example, a user with this email already exists)
422 Unprocessable Entity — validation failed
Server errors (5xx)
500 Internal Server Error — internal server error
503 Service Unavailable — service temporarily unavailable
Data format
REST API usually works with JSON (JavaScript Object Notation), although XML can also be used.
JSON response example
{
"id": 123,
"name": "Ivan Petrov",
"email": "ivan@example.com",
"created_at": "2024-01-15T10:30:00Z",
"posts": [
{
"id": 1,
"title": "First post",
"published": true
}
]
}Example of a JSON error
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Data validation error",
"details": [
{
"field": "email",
"message": "Incorrect email format"
}
]
}
}Authentication and security
REST API often requires authentication to access protected resources.
JWT (JSON Web Token)
The most popular authentication method for REST API:
// Getting a token when logging in
fetch('https://api.example.com/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: 'user@example.com',
password: 'password123'
})
})
.then(response => response.json())
.then(data => {
// Saving token
localStorage.setItem('token', data.token);
});
// Using a token for secure requests
fetch('https://api.example.com/users/me', {
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`
}
})
.then(response => response.json())
.then(data => console.log(data));API Keys
Simple method for service-oriented APIs:
fetch('https://api.example.com/data', {
headers: {
'X-API-Key': 'your-secret-key'
}
})
.then(response => response.json())
.then(data => console.log(data));API versioning
As the API evolves, it is important to maintain backward compatibility. There are several approaches to versioning:
URL Path Versioning
https://api.example.com/v1/users
https://api.example.com/v2/usersHeader Versioning
fetch('https://api.example.com/users', {
headers: {
'Accept': 'application/vnd.example.v2+json'
}
})Query Parameter Versioning
https://api.example.com/users?version=2
Practical example: creating a simple REST API on Node.js
Let's create a simple REST API to manage the task list.
const express = require('express');
const app = express();
app.use(express.json());
// Temporary data storage
let tasks = [
{ id: 1, title: 'Explore the REST API', completed: false },
{ id: 2, title: 'Create a project', completed: false }
];
let nextId = 3;
// GET - Get all tasks
app.get('/api/tasks', (req, res) => {
res.json(tasks);
});
// GET - Get a specific task
app.get('/api/tasks/:id', (req, res) => {
const task = tasks.find(t => t.id === parseInt(req.params.id));
if (!task) {
return res.status(404).json({
error: 'Task not found'
});
}
res.json(task);
});
// POST - Create a new task
app.post('/api/tasks', (req, res) => {
const { title } = req.body;
if (!title) {
return res.status(400).json({
error: 'Task name is required'
});
}
const newTask = {
id: nextId++,
title,
completed: false
};
tasks.push(newTask);
res.status(201).json(newTask);
});
// PUT - Update task
app.put('/api/tasks/:id', (req, res) => {
const taskIndex = tasks.findIndex(t => t.id === parseInt(req.params.id));
if (taskIndex === -1) {
return res.status(404).json({
error: 'Task not found'
});
}
const { title, completed } = req.body;
tasks[taskIndex] = {
id: parseInt(req.params.id),
title: title || tasks[taskIndex].title,
completed: completed !== undefined ? completed : tasks[taskIndex].completed
};
res.json(tasks[taskIndex]);
});
// DELETE - Delete task
app.delete('/api/tasks/:id', (req, res) => {
const taskIndex = tasks.findIndex(t => t.id === parseInt(req.params.id));
if (taskIndex === -1) {
return res.status(404).json({
error: 'Task not found'
});
}
tasks.splice(taskIndex, 1);
res.status(204).send();
});
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});Best Practices in REST API development
1. Use nouns, not verbs
Good:
GET /users
POST /usersBad:
GET /getUsers
POST /createUser2. Use the plural form for collections
GET /users (а не /user)
GET /posts (а не /post)3. Return the correct HTTP codes
Do not return 200 OK for all responses. Use the appropriate status codes.
4. Provide detailed error messages
{
"error": {
"code": "INVALID_EMAIL",
"message": "Invalid email address provided",
"field": "email",
"value": "invalid-email"
}
}5. Use pagination for large collections
app.get('/api/users', (req, res) => {
const page = parseInt(req.query.page) || 1;
const limit = parseInt(req.query.limit) || 10;
const startIndex = (page - 1) * limit;
const endIndex = page * limit;
const results = {
data: users.slice(startIndex, endIndex),
pagination: {
page,
limit,
total: users.length,
totalPages: Math.ceil(users.length / limit)
}
};
res.json(results);
});6. Document your API
Use tools like Swagger/OpenAPI to document the API.
7. Use HTTPS
Always use HTTPS for data transmission, especially when working with sensitive information.
8. Implement Rate Limiting
Limit the number of requests from a single client to protect against abuse.
REST vs GraphQL vs gRPC
REST is not the only way to build an API. Here is a brief comparison:
REST is suitable for most standard web applications, easy to understand and implement, has broad support and excellent caching.
GraphQL useful when the client needs flexibility in choosing data, allows you to get everything in one request and avoid over-fetching or under-fetching data.
gRPC optimal for microservice architecture, high-performance systems and internal APIs, uses a binary protocol and is faster than REST.
Tools for working with REST API
API testing
Postman — a popular tool for testing APIs with a graphical interface
Insomnia — an alternative to Postman with a minimalist interface
curl — console utility for HTTP requests
# Example of using curl
curl -X GET https://api.example.com/users
curl -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-d '{"name":"Ivan","email":"ivan@example.com"}'Client libraries
JavaScript/TypeScript:
Fetch API (built-in)
Axios
Got
Python:
requests
httpx
PHP:
Guzzle
cURL
Conclusion
REST API is a fundamental technology of modern web development that provides a simple and standardized way of interaction between the client and the server. Understanding the principles of REST, using HTTP methods and status codes correctly, and following best practices will help you create high-quality, which are scalable and easy to maintain.
Start with simple projects, gradually adding complexity, and don't forget about documentation and testing. REST API is a skill that will remain relevant for many years to come and will open the doors to the world of modern development.
Join the educational platform Code, where you will find structured courses on JavaScript, Node.js, Python and other modern technologies.
Our friendly community of developers in Telegram always ready to help with questions, share experiences and support you on your way to becoming a professional programmer!
