The full article contains 6,953 words. It takes 8 minutes to read and 2 minutes to speed read. Translated from: RingStack article 10 Best Practices for Writing Node. Js REST APIs | @ RisingStack, English good students can directly read the original, have abridged translation from the original,.

In addition to writing WEB applications, Node.js can also be used to write API services. In this article, we will cover best practices for writing Node.js Rest apis, including naming routes, authentication, and testing, as summarized below:

  1. Use HTTP Method and routing correctly
  2. Use HTTP status codes correctly
  3. Use HTTP headers to send metadata
  4. Pick the right framework for your REST API
  5. Do a black box test on the API
  6. Use a JWT-BASED stateless authentication mechanism
  7. Learn to use conditional request mechanisms
  8. Hug interface call frequency limit (rate-Limiting)
  9. Write good API documentation
  10. Keep an eye on API technology evolution

1. Use the HTTP Method and routing correctly

Imagine that you are building an API to create, update, acquire, and DELETE users. For these operations, the HTTP specification already has operations: POST, PUT, GET, and DELETE. It is recommended to use them directly to describe the behavior of the interface.

As for naming routes, use nouns or nominal phrases as resource identifiers. For example, in the user management example above, routes should look like this:

  • POST /users or PUT /users/:id is used to create new users.
  • GET /users is used to GET a list of users.
  • GET /users/:id is used to obtain a single user.
  • PATCH /users/:id Updates user information.
  • DELETE /users/:id Is used to DELETE users.

2. Use the HTTP status code correctly

If the server fails to process the request, you must set the correct response status code as follows:

  • 2xx: indicates that everything is normal.
  • 3xx: indicates that the location of the resource has been changed.
  • 4xx: indicates that the request cannot be processed because of a client error, for example, the parameter verification fails.
  • 5xx, indicating that the request cannot be processed because of a server error, such as an exception thrown by the server.

If you use Express, setting the status code is very simple: res.status(500).send({error: ‘Internal server error happend’}), similarly if restify is used: res.status(201).

To see the full HTTP status code, click here.

3. Use HTTP headers to send metadata

If you want to send metadata about the response body data, you can use headers. Common types of metadata that headers can contain include the following:

  • Paging information;
  • Frequency limit information;
  • Authentication information;

If you need to send custom metadata in a Header, it is best to prefix the Header name with an X. For example, if you need to send a CSRF Token, the actual Header name should be: X-csrf-token. However, this Header is deprecated in RFC 6648. For example, in order to achieve this purpose, OpenStack prefixes all API custom headers with OpenStack prefix:

OpenStack-Identity-Account-ID  
OpenStack-Networking-Host-Name  
OpenStack-Object-Storage-Policy
Copy the code

Note that although Header size is not specified in the HTTP specification, Header size is limited to 80KB in Node.js. The official text reads as follows:

Do not allow HTTP headers, including the status code line, to be larger than HTTP_MAX_Header_SIZE in order to defend against header-based DDOS attacks. Click here to

4. Pick the right framework for the REST API

It is important to choose the right framework for your actual scenario. The framework in Node.js is described as follows:

Express, Koa, HAPI

Express, Koa, and HAPI are primarily used to build browser WEB applications because they all support server-side template rendering, although this is only one of their many features. If your application needs to provide a user interface, these three are good choices.

Restify

Restify is specifically designed to create services that conform to the REST specification. It was created to help you build strictly maintainable API services. Restify comes with built-in DTrace support for all request handlers. It has been used by NPM and Netflix to provide important services in production environments.

5. Black-box API testing

The best way to test aN API is to black-box them. Black-box testing is a method of testing that doesn’t care about the internal structure or how the application works, and no part of the system should be mocked.

Supertest is one of the modules that can be used to perform a black box test on an interface. Here is a test case written based on the testing framework Mocha. The purpose of this test case is to check whether the interface can return a single piece of user data:

const request = require('supertest')

describe('GET /user/:id', function() {
  it('returns a user', function() {
    // newer mocha versions accepts promises as well
    return request(app)
      .get('/user')
      .set('Accept', 'application/json')
      .expect(200, {
        id: '1',
        name: 'John Math'
      }, done);
  });
});
Copy the code

One might ask: how is data written to the database that the API service connects to?

In general, when you write tests, you want to make as few assumptions as possible about the state of the system, but in some cases, you need to know exactly what the state of the system is in order to add more assertions to improve test coverage. If you have this requirement, you can try the following method to prepopulate the database:

  • Select a subset of production environment data to run black-box tests;
  • Populate the database with manually constructed data before running black box tests.

In addition, having black-box tests does not mean that unit tests are not needed; unit tests for apis still need to be written.

6. Use jWT-BASED stateless authentication

Because Rest apis must be stateless, authentication mechanisms need to be stateless as well, and JWT (JSON Web Token) -based authentication is the best solution for stateless authentication.

JWT’s certification mechanism consists of three parts:

  1. Header: contains the token type and hash algorithm.
  2. Payload: Contains declaration information.
  3. Signature: JWT does not actually encrypt the payload, it just signs it.

Adding JWT-BASED authentication to the API is also very simple, as shown in the following code:

const koa = require('koa');
const jwt = require('koa-jwt');

const app = koa();

app.use(jwt(
  secret: 'very-secret'
}));

// Protected middleware
app.use(function*() 
  // content of the token will be available on this.state.user
  this.body = { secret: '42' }
});
Copy the code

With the code above, your API is protected by JWT. To access this protected interface, use the Authorization Header to provide tokens, such as:

curl --Header "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cB ab30RMHrHDcEfxjoYZgeFONFh7HgQ" my-website.comCopy the code

As you may have noticed, the JWT module does not rely on any data storage layer. This is because tokens themselves can be verified individually. The payload inside the token can even contain the signature time and validity period of the token.

Also, you need to make sure that all API interfaces can only be accessed through more secure HTTPS links.

7. Learn to use conditional requests

A conditional request mechanism is a mechanism that behaves differently based on different headers. You can think of these headers as prerequisites for how a request should be handled. If the conditions are met, the request will be handled differently.

You can use these headers to check whether the version of the resource on the server matches the specific version of the resource. The values of these headers can be as follows:

  • When the resource was last modified;
  • The label of the resource (which changes with the resource);

To be specific:

  • Last-modified: indicates when the resource was Last Modified.
  • Etag: Indicates the tag that identifies the resource.
  • 9. if-modified-since: used in conjunction with the last-modified Header;
  • If-non-match: used with Etag.

Let’s look at a practical example:

The client does not know any version of the doc resource, so the request cannot provide either if-modified-since or if-non-match headers. The server then adds the Etag and Last-Modified headers to the response.








Then, when a client requests the same resource again, it can carry the if-modified-since and if-non-match headers, and then If the server checks to see If the resource has changed, If it hasn’t, Returns the 304-Not Modified status code without repeating the contents of the resource.








8. Embrace interface call frequency limit (rate-limiting)

Frequency limits are used to control the number of times a caller can make a request to the interface. To let your API users know how much balance they have left, set the following Header:

  • X-rate-limit-limit: indicates the maximum number of requests allowed within a specified period.
  • X-rate-limit-remaining indicates the number of Remaining requests in a specified period.
  • X-rate-limit-reset: specifies the time when the request frequency Limit is Reset.

Most WEB frameworks support these headers, but if you don’t have built-in support for them, you can find plug-ins to do so. For example, if you use KOA, you can use koa-rate-limit.

It is important to note that the time window for frequency limits can vary widely between API service providers, such as GitHub’s 60 minutes and Twitter’s 15 minutes.

9. Write good API documentation

Apis are written for others to use and benefit from, of course, and providing good interface documentation is critical. Here are two open source projects that can help you create API documentation:

  • API Blueprint
  • Swagger

If you prefer to use a third-party document service, consider Apiary.

10. Keep an eye on API technology evolution

In the last few years, two new query languages have emerged in the API technical solution space, Facebook’s GraphQL and Netflix’s Falcor. Why do you need them?

Just think this API interface request: / org / 1 / space / 2 / docs / 1 / collaborators? Include =email&page=1&limit=10. Situations like this can get the API out of control quickly. If you want all interfaces to return similar response formats, GraphQL and Falcor can help you out.

About GraphQL:

GraphQL is a query language for apis and a runtime that processes data queries based on existing data. GraphQL provides a complete and understandable description of the data in your API, enabling users to ask exactly what they need, making it easier to evolve the API over time, and has powerful development tool support. Read more here.

About Falcor:

Falcor is the innovative data platform that underpins Netflix’s UI. Falcor allows you to model all backend data as a single virtual JSON object for the Node.js service. On the client side, you can use familiar JavaScript operations to manipulate remote JSON objects. If you know your data, you know what your API looks like. Read more here.

Good API design that inspires

If you’re developing Rest apis or looking to improve on older versions, here’s a collection of apis that are available online, well designed, and very straightforward to borrow from:

  • GitHub API
  • Twilio API
  • Stripe API
  • Digital Ocean API

Hopefully those of you reading this have a better understanding of how to write good apis in Node.js, and if you have any suggestions, feel free to post them in the comments.

One More Thing

Want to subscribe directly in wechat front weekly? Scan the QR code on the cover of this article to pay attention to the front weekly subscription number. Want to talk to me face to face? Please add FeWeekly as a friend.

Happy Hacking


Did this article help you? Welcome to join the front End learning Group wechat group: