foreword
What is a REST API? REST is short for Representational State Transfer - an almost meaningless description of the most commonly used web services technology. A REST API is a way for two computer systems to communicate using HTTP technology in a web browser and server.
Sharing data between two or more systems has always been a fundamental requirement of software development. For example, consider buying auto insurance. Your insurance company has to get information about you and your vehicle, so they ask for data from car registries, credit agencies, banks and other systems. All of this happens transparently in real-time to determine if an insurer can offer a competitive policy.
APIs (Application Programming Interfaces) facilitate this type of communication by providing an interface for dialogue between systems. REST is just a widely adopted API style that we use to communicate internally and externally in a consistent and predictable way. It can be likened to the way we used to send letters with stamps, addresses and envelopes to ensure that letters were delivered and read.
REST is a common way people interact with web systems. For example, retrieving and updating account information in a social media application.
REST API example
Open the following link in your browser to request a random computer question from the Open Trivia Database :
https://opentdb.com/api.php?amount=1&category=18
This is a public API implemented as a RESTful web service (it follows REST conventions). Your browser will present a single Q&A question in JSON format with the answer attached. For example:
{
"response_code": 0,
"results": [
{
"category": "Science: Computers",
"type": "multiple",
"difficulty": "easy",
"question": "What does GHz stand for?",
"correct_answer": "Gigahertz",
"incorrect_answers": [
"Gigahotz",
"Gigahetz",
"Gigahatz"
]
}
]
}
You can use any HTTP client to request the same URL and get a response, for example using curl :
curl "https://opentdb.com/api.php?amount=1&category=18"
HTTP client libraries are available in all popular languages and runtimes, including JavaScript, Fetch in Node.js and Deno, and file_get_contents() in PHP. JSON responses are machine-readable, so they can be parsed and used before outputting HTML or other formats.
REST APIs and Rest
Various data communication standards have been developed over the years. Choices you may have come across include CORBA , SOAP , or XML-RPC . Most have established strict messaging rules.
REST was defined by Roy Fielding in 2000 and is much simpler than others. It is not a standard, but a set of recommendations and constraints for RESTful web services. These include:
- Client-Server Split Mode (Client-Server): System A makes an HTTP request to a URL hosted by System B and returns a response. This works the same way as a browser. A browser makes a request to a specific URL, and the request is forwarded to a web server, which usually returns an HTML page. The page may contain references to images, style sheets, and JavaScript, resulting in further requests and responses.
- Stateless : REST is stateless: the client request should contain all the information needed for the response. In other words, it should be possible to make two or more HTTP requests in any order and receive the same response (unless the API is designed to return random responses).
- Cacheable : The response should be defined as cacheable or not. Caching can improve performance because there is no need to regenerate a response for the same URL. Private data specific to a user for a certain period of time is generally not cached.
- Layered : The requesting client does not need to know if it is communicating with the actual server, proxy, or any other middleman.
Create a RESTful web service
A RESTful web service request includes:
- Endpoint URL . An application implementing a RESTful API will define one or more URL endpoints with a domain name, port, path, and/or query string, for example,
https://mydomain/user/123?format=json
. - HTTP method . Different HTTP methods can be used on any endpoint, and these methods map to the application's create, read, update, and delete (CRUD) operations:
| HTTP方法 | CRUD | 行为 |
| --- | --- | --- |
| GET | 读取 | 返回请求数据 |
| POST | 创建 | 创建一个新记录 |
| PUT 或者 PATCH | 更新 | 更新已存在的记录 |
| DELETE | 删除 | 删除已存在的记录 |
比如:
- 对`/user/`的GET请求返回系统中的注册用户列表。
- 对`/user/`的POST请求使用`body`对象创建了一个ID为`123`的用户。该响应会返回ID。
- 对`/user/123`的PUT请求使用`body`对象更新用户`123`。
- 对`/user/123`的GET请求返回用户`123`的详情。
- 对`/user/123`的DELETE请求删除用户`123`。
- HTTP headers . Authentication tokens or
cookies
etc. information can be included in HTTP request headers. - Body object . Data is usually transferred in the HTTP body in the same way that HTML
<form>
submits or sends a separate JSON-encoded data string, etc.
REST API response
The payload of the response can be anything practical: data, HTML, images, audio files, etc. Data responses are usually JSON encoded, but XML, CSV, simple strings, or any other format can also be used. You can allow the return format to be specified in the request. For example, /user/123?format=json
or /user/123?format=xml
.
The appropriate HTTP status code should also be set in the response header. 200 OK
for successful requests, although 201 Created
can also be returned when the record is created. The appropriate status code should be returned when an error occurs, such as 400 Bad Request
, 404 Not Found
, 401 Unauthorized
and so on.
Other HTTP headers that can be set include Cache-Control
or Expires
to specify how long a response can be cached before it is considered expired.
However, there are no hard and fast rules. Endpoint URLs, HTTP methods, body objects, and response types can be implemented as you like. For example, POST, PUT, and PATCH are often used interchangeably, and either can be used to create or update a record if necessary.
Hello World example
The following Node.js
code uses the Express
framework to create a RESTful web service. A single /hello/
endpoint responds to HTTP GET requests.
Make sure Node.js
is installed, create a new folder named restapi
. Create a new package.json
file in that folder with the following content:
{
"name": "restapi",
"version": "1.0.0",
"description": "REST test",
"scripts": {
"start": "node ./index.js"
},
"dependencies": {
"express": "4.18.1"
}
}
Run npm install
from the command line to pull the dependencies, and then create the index.js
file, including the following code:
// simple Express.js RESTful API
'use strict';
// initialize
const
port = 8888,
express = require('express'),
app = express();
// /hello/ GET request
app.get('/hello/:name?', (req, res) =>
res.json(
{ message: `Hello ${req.params.name || 'world'}!` }
)
);
// start server
app.listen(port, () =>
console.log(`Server started on port ${port}`);
);
Start the application from the command line with npm start
and open http://localhost:8888/hello/
in a browser. When responding to a GET request, the following JSON is displayed:
{
"message": "Hello world!"
}
The API also allows custom names, so http://localhost:8888/hello/everyone/
would return:
{
"message": "Hello everyone!"
}
Client REST requests and CORS
Consider launching the following HTML page in a browser, the URL is http://localhost:8888/
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>REST test</title>
</head>
<body>
<script>
fetch('http://localhost:8888/hello/')
.then((response) => {
return response.json();
})
.then((json) => {
console.log(json);
});
</script>
</body>
</html>
fetch
The call makes the same API request and the browser console shows { message: "Hello world!" }
as you would expect.
However, suppose your RESTful web service is now placed on the web with a domain name of http://mydomain.com/hello/
. The page's JavaScript fetch()
URL changed accordingly, but opening it in a browser http://localhost:8888/
now returns the console error Cross-Origin Request Blocked .
For security reasons, the browser only allows the client's XMLHttpRequest
and Fetch API
the same domain request where the calling page is located.
Fortunately, Cross-Origin Resource Sharing (CORS) allows us to circumvent this security restriction. Set the Access-Control-Allow-Origin
HTTP response header to tell the browser to allow the request. It can be set to a specific domain, or to all domains *
.
The web server API code can be changed to allow access from any client script running on any domain name:
// /hello/ GET request
app.get('/hello/:name?', (req, res) =>
res
.append('Access-Control-Allow-Origin', '*')
.json(
{ message: `Hello ${req.params.name || 'world'}!` }
)
);
Alternatively, the Express.js
middleware function can append the header to each endpoint request:
// enable CORS
app.use((req, res, next) => {
res.append('Access-Control-Allow-Origin', '*');
next();
});
// /hello/ GET request
// ...
Note that the browser makes two requests to the REST API:
- An HTTP
OPTIONS
request to the same URL determines if theAccess-Control-Allow-Origin
HTTP response header is valid. - The actual REST call.
When your server receives a OPTIONS
request method, it can set the Access-Control-Allow-Origin
HTTP response header to return a fake empty response to ensure work is not repeated.
REST API Challenge
Much of the success of REST is due to its simplicity. Developers are free to implement RESTful APIs, but this can lead to further challenges. For an in-depth look at implementation strategies, see 13 Best Practices for Building RESTful APIs .
Endpoint consensus
Consider the following endpoints:
-
/user/123
-
/user/id/123
-
/user/?id=123
All of these are valid options for getting data for the user 123
. The number of combinations increases further as you have more complex operations.
At the end of the day, it doesn't matter how you format the URL, but consistency across the API matters. This is a challenge for large codebases with many developers.
REST API Versioning
Changes to the API are inevitable, but URLs for endpoints should never be invalid, otherwise they will break the applications that use them.
To avoid compatibility issues, APIs are usually versioned. For example, /2.0/user/123
replaces /user/123
. Both new and old endpoints can remain active. Unfortunately, this makes it necessary to maintain multiple history APIs. Older versions can eventually be scrapped, but the whole process requires careful planning.
REST API Authentication
The test API shown above is open: any system can obtain data without authorization. This is not feasible for APIs that access private data or allow update and delete requests.
Client applications in the same domain as the RESTful API will send and receive cookies
just like any other HTTP request. (Note that Fetch()
in older browsers requires setting credentials
initial option). Therefore, an API request can be authenticated to ensure that a user is logged in and has the appropriate permissions.
Third-party applications must use alternate authorization methods. Common authentication options include:
- HTTP Basic Authentication . Pass an HTTP
Authorization
header containing the base64 encodedusername:password
string in the request headers. Because base64 is easily decoded, Basic authentication should only be used with other security mechanisms, such as HTTPS/SSL. - API key . Third-party applications gain permission to use the API by issuing a key, which may have specific permissions or be restricted to a specific domain. The key is passed in the HTTP header or query string in every request.
- OAuth . Obtain a token by sending a client ID and possibly client secret to the OAuth server before making any requests. The OAuth token is then sent with every API request until it expires.
- JSON Web Tokens (JWT) . Digitally signed authentication tokens are transmitted securely in request and response headers. JWT allows the server to encode access rights, so there is no need to call a database or other authorization system.
API authentication will vary depending on the context of use:
- In some cases, third-party applications are treated like any other logged-in user with specific rights and permissions. For example, a map API could return directions between two points to the calling application. It must confirm that the application is a valid client, but does not need to check user credentials.
- In other cases, third-party applications are requesting users' private data, such as email content. A REST API must identify users and their entitlements, but it may not care which application is calling the API.
REST API Security
RESTful APIs provide another way to access and manipulate your applications. Even if it's not a high-profile hacking target, a misbehaving client could send thousands of requests per second and crash your server.
Security is beyond the scope of this article, but common best practices include:
- Use HTTPS.
- Use robust authentication methods.
- Use CORS to restrict client calls to specific domains.
- Provides minimal functionality, ie don't create unwanted
DELETE
options. - Validate all endpoint URLs and body objects.
- Avoid exposing API tokens in client-side JavaScript.
- Block access from unknown domain names or IP addresses.
- Block unexpectedly large payloads.
- Consider rate limiting, that is, requests using the same API token or IP address are limited to N per minute.
- Respond with the appropriate HTTP status code and cache headers.
- Log requests and investigate failures.
Multiple requests and unnecessary data
RESTful APIs are limited by their implementation. The response may contain more data than you need, or a further request may be required to access all the data.
Consider a RESTful API that provides access to author and book data. To display data for the top 10 best sellers, the client can:
- Request details for the top 10
/book/
ordered by quantity sold (best selling first). The response contains a list of books with each author ID. - Form up to 10
/author/{id}
requests to get details about each author.
This is called the N+1 problem ; N API requests must be made for each result in the parent request.
To avoid unnecessarily large responses, the API can be adjusted to make the author's details optional. For example, ?author_details=full
. The number of options an API author needs to satisfy can become confusing.
Is GraphQL better?
The REST conundrum led Facebook to create GraphQL - a query language for web services. Think of it as SQL for web services: a single request defines the data you need and how you want it returned.
GraphQL addresses some of the challenges posed by RESTful APIs, although it introduces others. For example, it is difficult to cache GraphQL responses.
Your clients are unlikely to have similar issues as Facebook, so once a RESTful API grows beyond its practical limits, GraphQL might be worth considering.
REST API links and development tools
There are many tools to help with RESTful API development in all languages. Notable options include:
- Swagger : Various tools to help design, document, mock, test, and monitor REST APIs.
- Postman : A RESTful API testing application.
- Hoppscotch : An open-source, web-based alternative to Postman.
There are also tons of public REST APIs for jokes, currency conversion, geocoding, government data, and every topic you can think of. Many are free, although some require you to register an API key or use other authentication methods. The classified list includes:
Before implementing your own web service, try some RESTful APIs in your own project. Or consider following in the footsteps of Facebook, GitHub, Google, and many other giants and building a RESTful API of your own.
In the next article, I will translate and share 13 best practices for building RESTful APIs . Welcome to pay attention.
The above is all the content. If it is helpful to you, please like, collect and forward~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。