-
Notifications
You must be signed in to change notification settings - Fork 0
REST API
A REST API (Representational State Transfer Application Programming Interface) is a set of rules and conventions that allows different software applications to communicate and interact with each other over the internet.
It is a popular architectural style used in web services and web-based applications due to its simplicity and scalability.
REST APIs are widely used for various purposes, including mobile app development, web applications, and integration between different services.
Key principles of a REST API include:
-
Resources
: In REST, everything is considered as a resource, which can be a piece of data or an object. Each resource is uniquely identified by a URL (Uniform Resource Locator).https://api.example.com/users https://api.example.com/products/123
-
HTTP Methods
: REST APIs use standard HTTP methods to perform CRUD (Create, Read, Update, Delete) operations on resources. The four main HTTP methods used in REST are:-
GET
: Used to retrieve data from the server.GET /api/products
-
POST
: Used to create new resources on the server.POST /api/users Request Body: { "username": "john_doe", "email": "john@example.com", "password": "secure_password" }
-
PUT
: Used to update existing resources on the server.PUT /api/products/123 Request Body: { "name": "New Product Name", "price": 29.99 }
-
DELETE
: Used to remove resources from the server.DELETE /api/users/456
-
-
Stateless
: Each request from a client to a server must contain all the necessary information to understand and process the request. The server does not store any client context between requests, making each request independent. -
Representations
: Resources can have multiple representations, such as JSON, XML, HTML, or others. Clients can specify the representation format they prefer through the HTTPAccept
header. REST APIs often use JSON (JavaScript Object Notation) as the data interchange format because of its simplicity and widespread support. Data is usually sent in the request body for POST and PUT operations in JSON format.
Data is returned in the response body in JSON format.// Request POST /api/users Request Body: { "username": "john_doe", "email": "john@example.com", "password": "secure_password" } // Example (response to a GET request for a user): { "id": 123, "username": "john_doe", "email": "john@example.com" }
-
Status Codes
: HTTP status codes are used to indicate the success or failure of an API request. Some common status codes include:-
200 OK
: The request was successful. -
201 Created
: The resource was successfully created. -
204 No Content
: The request was successful, but there is no data to send in the response. -
400 Bad Request
: The request was malformed or invalid. -
404 Not Found
: The requested resource could not be found. -
500 Internal Server Error
: An error occurred on the server.
-
-
Uniform Interface
: REST APIs should have a consistent and standardized interface, making it easier for clients to understand and use the API. -
HATEOAS
(Hypermedia as the Engine of Application State):This principle suggests that the API responses should include hypermedia links that allow clients to navigate the API dynamically. These links provide the next possible actions a client can take based on the current state. For example, if you have a REST API for a blog platform, you might use the following URLs and methods:-
GET /posts
: Get a list of all blog posts. -
POST /posts
: Create a new blog post. -
GET /posts/{post_id}
: Get a specific blog post. -
PUT /posts/{post_id}
: Update a specific blog post. -
DELETE /posts/{post_id}
: Delete a specific blog post.
GET /accounts/12345 HTTP/1.1 Host: bank.example.com
HTTP/1.1 200 OK { "account": { "account_number": 12345, "balance": { "currency": "usd", "value": 100.00 }, "links": { "deposits": "/accounts/12345/deposits", "withdrawals": "/accounts/12345/withdrawals", "transfers": "/accounts/12345/transfers", "close-requests": "/accounts/12345/close-requests" } } }
In this example, the response contains hypermedia links for deposits, withdrawals, transfers and close-requests actions for the account with account_number 12345.
-
Security is a critical aspect of any API, especially when dealing with sensitive data or performing actions that require user authentication. REST APIs commonly use various authentication methods such as API keys, OAuth tokens, JWT (JSON Web Tokens), or Basic Authentication. Authorization mechanisms ensure that users have the necessary permissions to perform specific actions. Example (Using JWT for authentication):
POST /api/login
Request Body:
{
"username": "john_doe",
"password": "secure_password"
}
Example (Using API Key for authentication):
GET /api/products?api_key=YOUR_API_KEY
REST APIs should provide meaningful error messages and appropriate HTTP status codes when something goes wrong. Proper error handling helps clients understand and react to issues effectively.
Example (Error response for an invalid request):
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": "Invalid request data"
}
As APIs evolve over time, it is essential to have versioning mechanisms to maintain backward compatibility for existing clients while introducing new features or changes.
GET /api/v1/products
To prevent abuse and ensure fair usage of API resources, rate limiting can be implemented. It restricts the number of requests a client can make within a specific time window.
Example (Response headers indicating rate limiting):
HTTP/1.1 200 OK
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1630123600
Caching responses can improve API performance by reducing server load and minimizing network latency. Common caching mechanisms include ETags, Last-Modified headers, and caching proxies.
Input validation ensures that the data sent to the server is of the expected format and meets specific criteria. Input sanitization helps prevent security vulnerabilities like SQL injection and Cross-Site Scripting (XSS) attacks.
CORS allows servers to specify which domains are allowed to access their resources. It prevents unauthorized cross-origin requests and helps improve security.
Webhooks enable real-time communication from the server to the client. Instead of the client constantly polling for updates, the server can notify the client when relevant events occur.
Filtering allows clients to specify criteria to narrow down the data they want to retrieve from the server. Clients can pass query parameters in the API request to filter the results based on specific attributes or conditions.
Example (Filtering products by category and price range):
GET /api/products?category=electronics&min_price=100&max_price=500
In this example, the API is designed to accept query parameters like category
, min_price
, and max_price
. The server filters the products based on the specified criteria and returns only those that match the conditions.
There are different approaches for implementing filtering in REST API URLs. Each approach has its pros and cons, and the choice depends on the specific requirements and complexity of your API.
-
LHS Brackets: Example Usage: To find all items where the price is greater than or equal to 10 and less than or equal to 100, the client would make the following API request:
GET /items?price[gte]=10&price[lte]=100
Benefits:
- Ease of use for clients with libraries that support nested JSON objects and square brackets.
- Flexibility in defining multiple operators.
- No need to escape special characters in filter values for literal filter terms. Downsides:
- May require custom parsing on the server-side to group filters.
- Special characters in variable names can be awkward.
- Hard to manage custom combinational filters (AND vs. OR).
-
RHS Colon: Example Usage: To achieve the same filtering as in the LHS Brackets example, the client would make the following API request:
GET /items?price=gte:10&price=lte:100
Benefits:
- Easiest to parse on the server-side without custom binders for non-duplicate filters.
- No need for special handling of literal filter values. Downsides:
- Literal values may need special handling.
- Hard to manage custom combinational filters (AND vs. OR).
-
Search Query Param: Example Usage: If the API supports full-text search and advanced filtering, the client can use the search query parameter as follows:
GET /items?q=title:red chair AND price:[10 TO 100]
In this example, the client is searching for items where the title contains "red chair" (
title:red chair
) and the price falls within the range of 10 to 100 (price:[10 TO 100]
).
Benefits:- Most flexible queries for API users.
- Little parsing required on the backend if integrated with search engines or databases. Downsides:
- Harder for beginners to start working with the API due to the need to understand Lucene syntax.
- Full-text search may not make sense for all resources.
Sorting allows clients to specify the order in which the results should be returned. Clients can include sorting parameters in the request to determine whether the results should be sorted in ascending or descending order based on specific attributes.
To support sorting, APIs often use a sort or sort_by URL parameter that takes the field name as its value.
Example (Sorting products by price in descending order):
GET /api/products?sort=price&order=desc
In this example, the API uses the sort
parameter to specify the attribute to sort (price), and the order
parameter to specify the sorting order (descending). The server returns the products sorted by price in descending order.
Here are some example formats for enabling sorting in API requests:
-
Using "asc" and "desc" keywords: Example Usage: To sort users by email in ascending order:
GET /users?sort_by=asc(email)
To sort users by email in descending order:
GET /users?sort_by=desc(email)
This format clearly indicates the desired order for the specified field.
-
Using "+" and "-" symbols: Example Usage: To achieve the same sorting as in the previous example:
GET /users?sort_by=+email
GET /users?sort_by=-email
-
Using field name and order as separate parameters: Example Usage: To sort users by email in ascending order:
GET /users?sort_by=email&order_by=asc
To sort users by email in descending order:
GET /users?sort_by=email&order_by=desc
This approach separates the field name and order into distinct parameters.
When dealing with multi-column sorting, it's crucial to ensure that the field names and their corresponding orderings are correctly paired to avoid ambiguity. Here's an example of how multi-column sorting can be encoded in the API request:
Example Usage: To sort users by last modified date in descending order, and then by email in ascending order:GET /users?sort_by=desc(last_modified),asc(email)
GET /users?sort_by=-last_modified,+email
Pagination helps manage large datasets by splitting the results into smaller, manageable chunks or pages.
Clients can include pagination parameters in the request to specify the page number and the number of items per page.
Example (Fetching the second page of products with 10 items per page):
GET /api/products?page=2&limit=10
In this example, the API uses the page
parameter to specify the page number (2), and the limit
parameter to specify the number of items per page (10). The server returns the second set of 10 products.
There are several pagination strategies commonly used in APIs. Let's explore each of them with example usage:
-
Offset Pagination Example Usage: To retrieve the first 20 items, the client would make the following API request:
GET /items?limit=20&offset=0
To fetch the next page of 20 items, the client would use an offset of 20:
GET /items?limit=20&offset=20
Benefits:
- Easy to implement with standard SQL databases that support LIMIT and OFFSET.
- Stateless on the server. Downsides:
- Not performant for large offset values, as the database needs to scan and skip rows.
- Not consistent when new items are inserted, leading to page drift.
-
Keyset Pagination: Example Usage: Assuming the API is ordered by created date descending, the client would make the following requests:
GET /items?limit=20
To get the next page, the client would use the created date of the last item from the previous response as a filter:
GET /items?limit=20&created:lte=2021-01-20T00:00:00
Benefits:
- Works with existing filters without additional backend logic.
- Consistent ordering even when newer items are inserted.
- Consistent performance even with large offsets.
Downsides:
- Tight coupling of paging mechanism to filters and sorting.
- Does not work well for low cardinality fields.
-
Seek Pagination: Example Usage: Assuming the API is ordered by created date ascending, the client would make the following requests:
GET /items?limit=20
To get the next page, the client would use the ID of the last item from the previous response as a starting point:
GET /items?limit=20&after_id=20
To handle custom sorting, additional queries are needed to obtain the pivot values.
Benefits:
- No coupling of pagination logic to filter logic.
- Consistent ordering and performance.
Downsides:
- More complex for the backend to implement relative to other pagination strategies.
- May require additional queries for custom sorting.
Clients can combine filtering, sorting, and pagination to get precisely the data they need from the API.
Example (Filtering, sorting, and paginating products):
GET /api/products?category=electronics&min_price=100&max_price=500&sort=price&order=asc&page=1&limit=20
In this example, the client is requesting electronic products with prices between 100 and 500, sorted by price in ascending order, and fetching the first page with 20 items per page.