Skip to content

Latest commit

 

History

History
547 lines (425 loc) · 31.3 KB

File metadata and controls

547 lines (425 loc) · 31.3 KB

API design, security, and documentation

gear Follow these design principles and guidelines for simple, consistent, and expressive APIs that reduce maintenance costs, boost adoption, and encourage reuse.

Table of contents

1. Conventions used in this guide

The requirement level keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" used in this document are to be interpreted as described in RFC 2119 link-external.

2. Resource Oriented Design

We follow resource-oriented design. Resource-oriented design consists of three core components: resources, collections, and URIs.

2.1. Definitions

Resource
A data model link-external that represents a fact (or facts) in time. Resources can have zero or more nested sub-resources or collections.
Collection
A list of the same kinds of resources.
URI
An identifier for a network location of a resource or collection

2.2. Methods

Our APIs perform CRUD link-external operations on resources and collections using HTTP request methods.

Operation HTTP Method Description
Create POST
Read GET
Update (replace) PUT Replace all values in a resource or collection
Update (modify) PATCH Replace a subset of specific values in a resource or collection
Delete DELETE Remove all values associated with a unique resource or collection

info We use a few more HTTP request methods, too, as you'll see below.

2.3. URI paths are resource names

  1. URI pathnames match properties of resources and collections.

    Why:

    ⌦ This is a very well-known design to developers (your main API consumers). Apart from readability and ease of use, it allows us to write generic libraries and connectors without even knowing what the API is about.

  2. Use kebab-case for URIs.

  3. Use camelCase for parameters in the query string or resource fields.

  4. Use plural kebab-case for resource names in URIs.

  5. Always use a plural nouns collections, e.g., /users.

    Why:

    ⌦ Consistency and legibility. read more...

  6. Always use a singular concept that starts with a collection and ends to an identifier:

    /students/245743
    /airports/kjfk
  7. Avoid URIs like this:

    GET /blogs/:blogId/posts/:postId/summary

    Why:

    ⌦ This is not pointing to a resource but to a property instead. You can pass the property as a parameter to trim your response.

  8. Keep verbs out of your resource URIs.

    Why:

    ⌦ Because if you use a verb for each resource operation you soon will have a huge list of URIs and no consistent pattern which makes it difficult for developers to learn. Plus we use verbs for something else.

  9. Use verbs for non-resources. In this case, your API doesn't return any resources. Instead, you execute an operation and return the result. These are not CRUD (create, retrieve, update, and delete) operations:

    /translate?text=Hallo

    Why:

    ⌦ Because for CRUD we use HTTP methods on resource or collection URIs. The verbs we were talking about are actually Controllers. You usually don't develop many of these. read more...

  10. The request body or response type is JSON then please follow camelCase for JSON property names to maintain the consistency.

    Why:

    ⌦ This is a JavaScript project guideline, Where Programming language for generating JSON as well as Programming language for parsing JSON are assumed to be JavaScript.

  11. Even though a resource is a singular concept that is similar to an object instance or database record, you should not use your table_name for a resource name and column_name resource property.

    Why:

    ⌦ Because your intention is to expose Resources, not your database schema details.

  12. Again, only use nouns in your URI when naming your resources and don’t try to explain their functionality.

    Why:

    ⌦ Only use nouns in your resource URIs, avoid endpoints like /addNewUser or /updateUser . Also avoid sending resource operations as a parameter.

  13. Explain the CRUD functionalities using HTTP methods:

    How:

    GET: Retrieve a representation of a resource.

    POST: Create new resources and sub-resources.

    PUT: Replace existing resources.

    PATCH: Update existing resources. It only updates the fields that were supplied, leaving the others alone.

    DELETE: Delete existing resources.

  14. For nested resources, use the relation between them in the URI. For instance, using id to relate an employee to a company.

    Why:

    ⌦ This is a natural way to make resources explorable.

    How:

    GET /schools/2/students , should get the list of all students from school 2.

    GET /schools/2/students/31 , should get the details of student 31, which belongs to school 2.

    DELETE /schools/2/students/31 , should delete student 31, which belongs to school 2.

    PUT /schools/2/students/31 , should update info of student 31, Use PUT on resource-URI only, not collection.

    POST /schools , should create a new school and return the details of the new school created. Use POST on collection-URIs.

  15. Use a simple ordinal number for a version with a v prefix (v1, v2). Move it all the way to the left in the URI so that it has the highest scope:

    http://api.domain.com/v1/schools/3/students

    Why:

    ⌦ When your APIs are public for other third parties, upgrading the APIs with some breaking change would also lead to breaking the existing products or services using your APIs. Using versions in your URI can prevent that from happening. read more...

  16. Response messages must be self-descriptive. A good error message response might look something like this:

    {
      "code": 404,
      "level": "ERROR",
      "logger": "[http-logger]",
      "message":
        "No resource found at URI /archetypes/v1/locales/iso-country-codes/BS",
      "timestamp": 1504878062000
    }

    or for validation errors:

    {
      "code": 400,
      "logger": "[registration-form-logger]",
      "level": "ERROR",
      "timestamp": 1504878062000,
      "message": "Validation Failed",
      "stack": [
        {
          "code": 1233,
          "field": "email",
          "message": "Invalid email"
        },
        {
          "code": 1234,
          "field": "password",
          "message": "No password provided"
        }
      ]
    }

    Why:

    ⌦ Developers depend on well-designed errors at the critical times when they are troubleshooting and resolving issues after the applications they've built using your APIs are in the hands of their users.


    shield Keep security exception messages as generic as possible. For instance, instead of saying ‘incorrect password’, you can reply back saying ‘invalid username or password’ so that we don’t unknowingly inform user that username was indeed correct and only the password was incorrect.


  17. Use only these 8 status codes to send with you response to describe whether everything worked, The **client app did something wrong** or The **API did something wrong**.

    Which ones:

    200 OK response represents success for GET, PUT or POST requests.

    201 Created for when new instance is created. Creating a new instance, using POST method returns 201 status code.

    304 Not Modified response is to minimize information transfer when the recipient already has cached representations.

    400 Bad Request for when the request was not processed, as the server could not understand what the client is asking for.

    401 Unauthorized for when the request lacks valid credentials and it should re-request with the required credentials.

    403 Forbidden means the server understood the request but refuses to authorize it.

    404 Not Found indicates that the requested resource was not found.

    500 Internal Server Error indicates that the request is valid, but the server could not fulfill it due to some unexpected condition.

    Why:

    ⌦ Most API providers use a small subset HTTP status codes. For example, the Google GData API uses only 10 status codes, Netflix uses 9, and Digg, only 8. Of course, these responses contain a body with additional information.There are over 70 HTTP status codes. However, most developers don't have all 70 memorized. So if you choose status codes that are not very common you will force application developers away from building their apps and over to wikipedia to figure out what you're trying to tell them. read more...

  18. Provide total numbers of resources in your response.

  19. Accept limit and offset parameters.

  20. The amount of data the resource exposes should also be taken into account. The API consumer doesn't always need the full representation of a resource.Use a fields query parameter that takes a comma separated list of fields to include:

    GET /student?fields=id,name,age,class
  21. Pagination, filtering, and sorting don’t need to be supported from start for all resources. Document those resources that offer filtering and sorting.

3. Security

shield These are some basic security best practices.

  1. Don't use basic authentication unless over a secure connection (HTTPS). Authentication tokens must not be transmitted in the URI: GET /users/123?token=asdf....

    Why:

    ⌦ Because Token, or user ID and password are passed over the network as clear text (it is base64 encoded, but base64 is a reversible encoding), the basic authentication scheme is not secure. read more...

  2. Tokens must be transmitted using the Authorization header on every request: Authorization: Bearer xxxxxx, Extra yyyyy.

  3. Authorization Code should be short-lived.

  4. Reject any non-TLS requests by not responding to any HTTP request to avoid any insecure data exchange. Respond to HTTP requests by 403 Forbidden.

  5. Consider using Rate Limiting.

    Why:

    ⌦ To protect your APIs from bot threats that call your API thousands of times per hour. You should consider implementing rate limit early on.

  6. Setting HTTP headers appropriately can help to lock down and secure your web application. read more...

  7. Your API should convert the received data to their canonical form or reject them. Return 400 Bad Request with details about any errors from bad or missing data.

  8. All the data exchanged with the ReST API must be validated by the API.

  9. Serialize your JSON.

    Why:

    ⌦ A key concern with JSON encoders is preventing arbitrary JavaScript remote code execution within the browser... or, if you're using node.js, on the server. It's vital that you use a proper JSON serializer to encode user-supplied data properly to prevent the execution of user-supplied input on the browser.

  10. Validate the content-type and mostly use application/*json (Content-Type header).

    Why:

    ⌦ For instance, accepting the application/x-www-form-URIencoded mime type allows the attacker to create a form and trigger a simple POST request. The server should never assume the Content-Type. A lack of Content-Type header or an unexpected Content-Type header should result in the server rejecting the content with a 4XX response.

4. Documentation

  1. Fill the API section in the README for "API".

  2. Authentication examples. Describe API authentication methods with a code sample.

  3. URI structure. Explaining The URI Structure (path only, no root URI) including The request type (Method). For each endpoint explain:

  4. URI Params. If URI Params exist, specify them in accordance with name mentioned in URI section:

    Required: id=[integer]
    Optional: photo_id=[alphanumeric]

    light-bulb POST method types

    If the request's method type is POST, provide working examples. URI Params rules apply here too. Separate the section into Optional and Required.

  5. Success Responses. What should be the status code and is there any return data? This is useful when people need to know what their callbacks should expect:

    Code: 200
    Content: { id : 12 }
  6. Error Responses. Most endpoints have many ways to fail. From unauthorized access to wrongful parameters etc. All of those should be listed here. It might seem repetitive, but it helps prevent assumptions from being made. For example:

    • HTTP status code

      404 Not Found
    • Response body

      {
        "code": 404,
        "level": "ERROR",
        "logger": "[http-logger]",
        "message":
          "No resource found at URI /archetypes/v1/locales/iso-country-codes/BS",
        "timestamp": 1504878062000
      }
    • Response headers

      accept-ranges: bytes
      access-control-allow-headers: Authorization
      access-control-allow-methods: GET, HEAD, OPTIONS
      access-control-allow-origin: *
      cache-control: public, no-transform, must-revalidate
      connection: keep-alive
      content-encoding: gzip
      content-language: en-US
      content-length: 149
      content-type: application/json
      date: Fri, 08 Sep 2017 06:41:02 GMT
      last-modified: Tue, 1 Oct 2014 10:10:10 GMT
      server: nginx/1.12.1
      vary: Accept-Encoding
  7. Use API design and documentation tools. There are lots of open source tools for good documentation such as: