1. OVERVIEW

RESTful APIs started being widely adopted for systems interoperability and integration in the mid-2000s, maybe earlier.

Two decades later, many APIs in production today, that claim to be “RESTful”, violate basic REST principles, creating confusion, frustration, and unnecessary complexity.

Take for instance:

  • POST /accountSearchByNumber
  • POST /accountSearchByLogin
  • POST /DeleteEvent
  • Lack of security, either at the protocol level or allowing data access to users/personas not related to it.
  • Operation in the request body.
  • Inconsistent Resource Naming.
  • Often times, level 0 from the Richardson Maturity Model code.
  • No documentation.

This blog post is revised regularly to keep the recommendations for building scalable and secure REST APIs up-to-date.

RESTful API Guidelines RESTful API Guidelines


2. Naming Resources/URIs

  • Nouns to represent resources instead of verbs in the URI
  • Plural nouns
  • Lowercase
  • Hyphens (-) to separate words in the URI
  • Nested resources
  • Use forward slashes (/) for hierarchy but not trailing forward slash (/)

Do:

  • /accounts
  • /accounts/1234
  • /account-roles
  • /api/blogs/12/posts
  • /api/products/100/reviews

Don’t:

  • /getAccount/1234
  • /createUser
  • /accounts/1234/
  • /account_roles
  • /AccountRoles
  • /accountSearchByNumber
  • /accountSearchByLogin


3. HTTP Methods

  • GET: Retrieves a resource or collection of resources
    Should not change the data/state of resources, idempotent

  • POST: Creates or updates a resource
    Not required to be idempotent

  • PUT: Replaces the resource identified by the URI
    Idempotent, multiple invocations leave the server in the same state

  • DELETE: Deletes the resource identified by the URI
    Idempotent, multiple invocations leave the server in the same state

  • PATCH: Partially updates the resource identified by the URI
    Not idempotent

  • OPTIONS: Retrieves available communication options for the resource identified by the URI

  • HEAD: Retrieves metadata without a response body about the resource(s) identified by the URI
    headers only, such as size, modification date, etc.


4. Versioning

  • URI Versioning
    • POST /api/v1/accounts
    • POST /api/v2/accounts
  • Header Versioning
    • Accept: vnd-asimio-tech-provisioning-v1+json
    • Custom Header (Capitalize-Case)
      • Asimio-Tech-Provisioning: 1.0
        Industry moving away from the “X-” prefix used to denote non-standard/experimental HTTP Headers


5. Path Variables

  • /accounts/{accountId}
  • /articles/{articleId}/comments


6. Query Parameters for Filtering, Sorting, Paging, and Field Selection

  • Filtering
    • GET /api/customers?firstName=Blah
    • GET /api/customers?firstName=Blah&lastName=Meh
    • GET /api/accounts?role=ROLE1&role=ROLE2
  • Paging
    • GET /api/accounts?page=3&size=2
    • GET /api/accounts?cursor=abc123&size=2
  • Sorting
    • GET /api/customers?sort=lastName&direction=asc
    • GET /api/customers?sort=lastName,asc


7. Common HTTP Status Codes

  • 2xx group: Successful responses
    • 200 OK: The request succeeded
      A resource was retrieved, or an update was successful

    • 201 CREATED: A new resource has been created, its URI is in the Location Header

    • 204 NO CONTENT: The request was successful, the response has no body
      A resource was deleted

  • 3xx group: Redirection responses
    • 304 NOT MODIFIED: The response has not been modified, client can continue to use its cached version
  • 4xx group: Client error responses
    • 404 NOT FOUND: There is no resource for the requested URI

    • 400 BAD REQUEST: The server cannot process the request
      Invalid attributes, input out of range, etc., return a list of errors in the response body

    • 401 UNATHORIZED: Unauthenticated, the client must authenticate to access the resource(s) represented by the URI

    • 403 FORBIDDEN: The client doesn’t have the privileges to access the resource(s) represented by the URI

    • 405 METHOD NOT ALLOWED: The server doesn’t support the requested method
      A DELETE request for a resource known to the server, a GET request that accepts a JSON-formatted response, but the server produces XML instead

  • 5xx group: Server error responses
    • 500 INTERNAL SERVER ERROR: An error the server doesn’t now how to handle or recover from
      DB connection issue, etc.
      Don’t send the stacktrace as part of the response


8. Authentication and Authorization

  • Authentication: Verifies the identity of users or applications accessing the API
  • Authorization: Verifies if an authenticated party as the privileges/roles/permissions to access the API


8.1. Common Authentication Schemes:

  • Basic
  • Digest
  • Bearer (Token-based)
    • OAuth 2.0
    • JWT
  • Mutual


8.2. Other (Web)

  • Form-based


8.3. Basic Authentication

  • No session management, the user must authenticate with each request.

  • Sequence Flow

HTTP Basic Authentication Sequence Diagram

  • Web browser’s happy path flow

    1. Web HTTP Basic Authentication Login popup
      Web HTTP Basic Authentication Login popup

    2. Web HTTP Basic Authentication Success Login page
      Web HTTP Basic Authentication Success Login page

    3. Web HTTP Basic Authentication Header
      Web HTTP Basic Authentication Header

  • RESTful API Basic Authentication unhappy path flow

curl -v http://localhost:8080/api/samples
> GET /api/samples HTTP/1.1
...
< HTTP/1.1 401
< WWW-Authenticate: Basic realm="Access to Web and API protected resources via Basic Auth"
...
  • RESTful API Basic Authentication happy path flow
curl -v -H "Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=" http://localhost:8080/api/samples
GET /api/samples HTTP/1.1
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
...
HTTP/1.1 200
...
["Sample 1","Sample 2","Sample 3","Sample 4"]


8.4. Digest Authentication

  • Uses a nonce token
  • nonce = base64(expirationTime + “:” + md5Hex(expirationTime + “:” + key))
    expirationTime: Date and Time when the nonce expires in millis
    key: Private key to prevent nonce modification

  • Should not be used. Server needs to store the password in plaintext or in MD5 format, considered cryptographically weak nowadays

  • Sequence Flow

HTTP Digest Authentication Sequence Diagram

  • RESTful API Digest Authentication unhappy path flow
curl -v http://localhost:8080/api/samples
> GET /api/samples HTTP/1.1
...
< HTTP/1.1 401
< WWW-Authenticate: Digest realm="Access to Web and API protected resources via Digest Auth", qop="auth", nonce="MTc0MzUyMjI5Mzk0MTowNzZlODY0ODBkNmVhMDkwZjhiZWI5NGQxZTgzZmI3Mw=="
...
  • RESTful API Digest Authentication happy path flow
curl -v --digest --user username:password http://localhost:8080/api/samples
> GET /api/samples HTTP/1.1
...
< HTTP/1.1 401
< WWW-Authenticate: Digest realm="Access to Web and API protected resources via Digest Auth", qop="auth", nonce="MTc0MzYwNzMyMjkzOTpkYTc0MTY0Y2JhYjE4YjNkYmU4MmZlMjhmNDIyNWU0Nw=="
...
<
* Ignoring the response-body
* Issue another request to this URL: 'http://localhost:8080/api/samples'
* Server auth using Digest with user 'username'
...
> GET /api/samples HTTP/1.1
> Authorization: Digest username="username", realm="Access to Web and API protected resources via Digest Auth", nonce="MTc0MzYwNzMyMjkzOTpkYTc0MTY0Y2JhYjE4YjNkYmU4MmZlMjhmNDIyNWU0Nw==", uri="/api/samples", cnonce="MmI5OTM1M2M1NTRkNjdiNDg5MWIzMzgzMDBjNmZlM2U=", nc=00000001, qop=auth, response="9bb095bf3a1f3ac9f00734eb5ed0e984"
...
< HTTP/1.1 200
...
["Sample 1","Sample 2","Sample 3","Sample 4"]


8.5. API Security

  • Adopt Token-based auth like OAuth 2.0, JWT
  • Refresh Tokens
  • Always use HTTPS (SSL+TLS)
  • ACL (Access Control List)
  • RBAC (Role-Based Access Control)

Authorization: Api-Key Authorization: Bearer


9. Documentation and Testing Tools

  • OpenAPI/Swagger
  • Postman, Insomnia


10. Richardson Maturity Model

Richardson Maturity Model Level 0 The Swamp of POX Single URI Single HTTP Method (Usually POST) Level 1 Resources Multiple URIs Single HTTP Method /users, /orders Level 2 HTTP Verbs Multiple URIs Multiple HTTP Methods GET, POST, PUT, DELETE Level 3 Hypermedia HATEOAS Self-describing Discoverability → Progression to a better REST Architecture → Level 0: The Swamp of POX (Plain Old XML) • Single endpoint URL (e.g., /api) • All operations through POST requests • Action defined in request body • RPC-style communication Level 1: Resources • Multiple resource endpoints (/users, /orders, /products) • Still using single HTTP method (usually POST) • Resources identified by URIs Level 2: HTTP Verbs • Proper use of HTTP methods • GET for retrieval, POST for creation • PUT for updates, DELETE for removal • HTTP status codes for responses Level 3: Hypermedia Controls (HATEOAS) • Responses include links to related resources • Self-describing API responses • Client can discover available actions • Loose coupling between client and server Examples: Level 0: POST /api with XML body containing operation Level 1: POST /users, POST /orders (separate resources) Level 2: GET /users/123, PUT /users/123, DELETE /users/123 Level 3: Response includes {"links": {"self": "/users/123", "orders": "/users/123/orders", upsell: {rooms: /rooms?type=suite}}}
  • HATEOAS: Hypermedia as the Engine of Application State. A REST principle that includes hypermedia links in the response
  • HAL: Hypertext Application Language. A format that implements the HATEOAS principle


11. Download RESTful API Guidelines PDF