01 logo

Consolidated Design Rules and Standards for Great REST API - Part 2

HTTP Methods Rules

By Haitham RaikPublished about a year ago Updated about a year ago 21 min read
Like
Consolidated Rules and Best Practices for Designing REST APIs

In the previous part, we covered the generic rules that apply to all HTTP methods. In this part, we will address each HTTP method separately.

GET HTTP Method Rules

Rule 100: Use GET for retrieval only, and it should always be safe and idempotent. The resource state after sending the GET request must be precisely the same as the resource state before sending the GET request.

Rule 101: Don't use get for unsafe operations; in case of network failures, consumers should be able to resubmit the request safely.

Rule 102: Use Get to perform safe non-CRUD actions (e.g., validate, calculate, search, compare, etc.) and use query parameters to pass inputs. For such activities, use a verb as a sub-source. /users/compare

Rule 103: Don't use GET on the same URI to perform multiple operations. The below examples are not allowed (the below technique is called Tunneling, which is not recommended at all)

#Request 1

GET /users

Content-Type: application/json

{op="validate", users=[]}

#Request 2

GET /users

Content-Type: application/json

{op="calc", users=[]}

Rule 104: If the consumer didn't provide or provided invalid or expired credentials (In the Authorization header), return the HTTP Status code (401 Unauthorized), and it is recommended to return the WWW-Authenticate header to tell the client what kind of authentication is expected

Rule 105: If the consumer provided un-authorized credentials, return HTTP status code (403 Forbidden)

Rule 106: if the requested resource (collection or object) doesn't exist and the server doesn't know if the resource was there before or not, return the HTTP Status code (404 Not Found)

Rule 107: if the requested resource doesn't exist and the server knows that the resource was there before, return the HTTP Status code (405 Gone). This is applicable in case an old version of API has been removed, and the server doesn't know if there is a newer version.

Rule 108: if the requested object resource doesn't exist and the server knows it was there before, return (405 Gone). This is applicable in this case a logical delete mechanism is implemented at the level of the object.

Rule 109: if the requested resource has moved to a different location, return the HTTP Status code (301 Moved Permanently) with the Location header value pointing to the new URI. This applies if a client requests an old API version and the server knows where the new version is (see Rule#25).

Rule 110: If the request has a payload but doesn't include a Content-Type header. Return status code (400 Bad Request).

Rule 111: If the request has an unsupported media type defined in the Content-Type header, return status code (415 Unsupported Media Type)

Rule 112: If the request has a body, but it doesn't match the media type defined in the Content-Type header, return status code (400 Bad Request)

Rule 113: If the request has a body and it matches the media type defined in the Content-Type header, but the message structure or values are invalid, return status code (400 Bad Request)

Rule 114: In response, return the payload using the same format used in the request payload (e.g., request Content-Type). If the request has no payload, use the Accept header to allow the consumer to negotiate for his preferred data format (e.g., JSON, XML, etc.). If no Accept header is provided in the request, use the default data format (e.g., JSON).

Rule 115: if the client sends Accept header with a media type that can't be supported by the server, return (406 Not Acceptable)

Rule 116: In case of abnormal failures, return HTTP status code 5XX

Rule 117: In case of errors or failure, return an error report in the response body describing the issue.

Rule 118: Content-Type header must be used in the response and must match the response body payload (for example: don't return application/json while the response payload is XML-based)

Rule 119: Query parameters can be used for filtration, sorting and pagination:

  1. Filtration example; get all active users: /users?active=true
  2. Pagination example; get page 5 where the page size is 10: /users?pageId=5&pageSize=10

Rule 120: Return status code (200 OK) for a successful response to the GET request

Rule 121: Don't use the Status code (200 OK) and there is an error in the response body

Rule 122: Avoid range requests using the Range header for implementing pagination (e.g., Range: 1–100)

Rule 123: Return the Last-Modified header to inform the consumer when was the last update of the resource

Rule 124: Return the ETag header to inform the consumer about the latest version of the resource. ETag can be generated using MD5 hash value

Rule 125: Allow conditional GET requests by supporting If-Modified-Since and If-None-Match (if provided by the client):

  1. Client propagate If-Modified-Since with previously retrieved Last-Modified Or Client propagate If-None-Match with previously retrieved ETag
  2. The server validates the value, if the condition is true, that means the resource has been updated, and the server must return a fresh representation for the resource with HTTP Status Code (200 OK)
  3. If the condition is false, that means the resource is not updated, and the server must return the HTTP Status code (304 Not Modified)

Rule 126: If response integrity is important, make sure to sign the response payload (see Rule#81)

Rule 127: Allow caching for successful GET response using all of the below headers in the response:

  1. For Legacy HTTP1.0 use Date:<start-date> and Expires:<cache-end-date> headers
  2. For HTTP1.1 and above use Cache-Control: max-age=<Seconds>, must-revalidate

Rule 128: For critical data that are not supposed to be cached, disallow caching using all of the below headers in the response:

  1. For Legacy HTTP1.0 use Pragma: no-cache and Expires:0 headers
  2. For HTTP1.1 and above, use Cache-Control: no-cache

OPTIONS HTTP Method Rules

Rule 129: Use OPTIONS to retrieve the resource's allowed methods. It is good to support it, although it is not popularly used.

Rule 130: Use OPTIONS for retrieval only, and it should always be safe and idempotent. The resource state after sending the OPTIONS request must be exactly the same as the resource state before sending the OPTIONS request.

Rule 131: Return Allow header with a list of supported HTTP methods in response to the OPTIONS request. if we send the following request, we would get the following HTTP header in the response: OPTIONS /users

Allow: GET, HEAD, PUT, POST, DELETE

Rule 132: When a resource supports the PATCH method, add an Accept-Patch header listing the media types supported for PATCH requests:

#Request

OPTIONS /customers/1

#Response

HTTP/1.1 204 No Content

Allow: POST, GET, PATCH

Accept-Patch: application/json

Rule 133: Add a Link header in the response containing a human-readable document that describes the resource

Rule 134: PATCH request and response should not contain a body

Rule 135: Return HTTP Status Code (204 No Content) in case of success

Rule 136: if the requested resource (collection or object) doesn't exist and the server doesn't know if the resource was there before or not, return the HTTP Status code (404 Not Found)

Rule 137: if the requested resource doesn't exist and the server knows that the resource was there before, return the HTTP Status code (405 Gone). This is applicable in case an old version of API has been removed, and the server doesn't know if there is a newer version.

Rule 138: if the requested object resource doesn't exist and the server knows it was there before, return (405 Gone). This is applicable in this case a logical delete mechanism is implemented at the level of the object.

Rule 139: if the requested resource has moved to a different location, return the HTTP Status code (301 Moved Permanently) with the Location header value pointing to the new URI. This applies if a client requests an old API version and the server knows where the new version is (see Rule#25).

Rule 140: In case of abnormal failures, return HTTP status code 5XX

Rule 141: In case of errors or failure, return an error report in the response body describing the issue.

POST HTTP Method Rules

Rule 142: Use POST to create new parent objects. In the below example, a new user will be created:

POST /users

Rule 143: Use POST to execute unsafe non-CRUD operations (such as lock, unlock, merge, copy, duplicate, process, etc.). Such activities are sometimes called tasks, and the resources handling tasks are called controllers or processors. For such tasks, use a verb as a sub-source.. For example:

  1. To merge the addresses of user Id 121, use: /users/121/addresses/merge
  2. To lock a user with id 121, use: POST /users/121/lock

Rule 144: Don't use POST on the same URI to perform multiple operations. The below examples are not allowed (the below technique is called Tunneling, which is not recommended at all)

#Request 1

POST /users

Content-Type: application/json

{op="async", users=[]}

#Request 2

POST /users

Content-Type: application/json

{op="lock", users=[]}

Rule 145: If the consumer didn't provide or provided invalid or expired credentials (In the Authorization header), return the HTTP Status code (401 Unauthorized), and it is recommended to return the WWW-Authenticate header to tell the client what kind of authentication is expected

Rule 146: If the consumer provided un-authorized credentials, return HTTP status code (403 Forbidden)

Rule 147: if the requested collection resource doesn't exist and the server doesn't know if the resource was there before or not, return the HTTP Status code (404 Not Found)

Rule 148: if the requested collection resource doesn't exist and the server knows that the resource was there before, return the HTTP Status code (405 Gone). This is applicable in case an old version of API has been removed, and the server doesn't know if there is a newer version or not.

Rule 149: if the requested collection resource has moved to a different location, return the HTTP Status code (301 Moved Permanently) with the Location header value pointing to the new URI. This applies if a client requests an old API version and the server knows where the new version is (see Rule#25).

Rule 150: If the request has a payload but doesn't include a Content-Type header. Return status code (400 Bad Request).

Rule 151: If the request has an unsupported media type defined in the Content-Type header, return status code (415 Unsupported Media Type)

Rule 152: If the request has a body, but it doesn't match the media type defined in the Content-Type header, return status code (400 Bad Request)

Rule 153: If the request has a body and it matches the media type defined in the Content-Type header, but the message structure or values are invalid, return status code (400 Bad Request)

Rule 154: if the client sends Accept header with a media type that can't be supported by the server, return (406 Not Acceptable)

Rule 155: In case of abnormal failures, return HTTP status code 5XX

Rule 156: Return an error report in the response body describing the issue in case of errors or failure.

Rule 157: Content-Type header must be used in the response and must match the response body payload (for example: don't return application/json while the response payload is XML-based)

Rule 158: After creating the resource, return the HTTP response code (201 Created) and use one of the following headers:

  1. Use the Location header pointing to the newly created object if the response payload is empty
  2. Use the Content-Location header pointing to the newly created object if the response payload contains the representation of the newly created resource. This will inform the client that the content can also be retrieved by calling this URI.

Rule 159: Avoid returning a success code with an error in the body.

Rule 160: Return the Last-Modified header for the newly created resource

Rule 161: Return the ETag header for the newly created resource. ETag can be generated using MD5 hash value

Rule 162: For bulk creation performed synchronously, return the HTTP status code (200 OK) and return a collection of the newly created URLs.

Rule 163: For bulk posting performed synchronously (for unsafe non-CRUD actions), return the HTTP status code (200 OK) and return in the response body a collection of the execution results.

Rule 164: For long processing activities (such as creating a huge bulk of objects), support async processing by using a special purpose resource (let's call it /async-tasks). Upon receiving a POST request, create a new resource of /async-tasks and return the HTTP status code (202 Accepted) along with a Location header that includes the URL for the newly created /async-tasks object. For example:

#Request

POST /users/async-tasks

{

"Users": []

}

#Response

HTTP/1.1 202 Accepted

Content-Type: application/json

Location: /users/async-tasks/1

Rule 165: For Async processing /async-tasks resource must support GET request (refer to GET HTTP method rules for a full list of applicable rules) to allow the consumer to inquire about the current state of the original request and should return one of the following:

  1. For still processing state: Return HTTP status code (200 OK) with a response payload indicating that the request is still under processing
  2. For successfully completed state: Return HTTP status code (303 See Other) and Location header pointing for the creation results.
  3. Return the HTTP status code (200 OK) for a failed processing state with an error report indicating the reason for the failure.

Rule 166: If request integrity is important, ask your client to send the signature in the header and make sure to validate it (see Rule#81). If the signature is not provided or is not valid. return HTTP status code (403 Forbidden) and an error report in the response body describing the issue.

PUT HTTP Method Rules

Rule 167: Use PUT to update an existing object. Following example updates already exist user with id 121: PUT /users/121

Rule 168: insert a sub-object for an existing parent object. The following example inserts a new address under existing user id 121: PUT /users/121/addresses

Rule 169: If the consumer didn't provide or provided invalid or expired credentials (In the Authorization header), return the HTTP Status code (401 Unauthorized), and it is recommended to return the WWW-Authenticate header to tell the client what kind of authentication is expected

Rule 170: If the consumer provided un-authorized credentials, return HTTP status code (403 Forbidden)

Rule 171: if the requested resource (collection or object) doesn't exist and the server doesn't know if the resource was there before or not, return HTTP Status code (404 Not Found)

Rule 172: if the requested resource doesn't exist and the server knows that the resource was there before, return the HTTP Status code (405 Gone). This is applicable in case an old version of API has been removed, and the server doesn't know if there is a newer version.

Rule 173: if the requested object resource doesn't exist and the server knows it was there before, return (405 Gone). This is applicable in this case a logical delete mechanism is implemented at the level of the object.

Rule 174: if the requested resource has moved to a different location, return the HTTP Status code (301 Moved Permanently) with the Location header value pointing to the new URI. This applies if a client requests an old API version and the server knows where the new version is (see Rule#25).

Rule 175: If the request has a payload but doesn't include a Content-Type header. Return status code (400 Bad Request).

Rule 176: If the request has an unsupported media type defined in the Content-Type header, return status code (415 Unsupported Media Type)

Rule 177: If the request has a body, but it doesn't match the media type defined in the Content-Type header, return status code (400 Bad Request)

Rule 178: If the request has a body and it matches the media type defined in the Content-Type header, but the message structure or values are invalid, return status code (400 Bad Request)

Rule 179: in case of abnormal failures, return HTTP status code 5XX

Rule 180: in case of errors or failure, return an error report in the response body describing the issue.

Rule 181: Return status code (204 No Content) for a successful response and don't return a payload in the response body

Rule 182: Avoid returning a success code with an error in the body.

Rule 183: Return Last-Modified header to inform the consumer of the new last update date time

Rule 184: Return the ETag header to inform the consumer about the latest version of the resource. ETag can be generated using MD5 hash value

Rule 185: Allow conditional PUTrequest by supporting If-Unmodified-Since and If-Match headers to prevent concurrent update conflicts:

  1. The client can propagate If-Unmodified-Since with previously retrieved Last-Modified Or can propagate If-Match with previously retrieved ETag
  2. The server validates the value; if the condition is true, that means the resource has not been updated, there is no conflict, and the server must return HTTP Status Code (204 No Content)
  3. If the condition is false, that means the resource is updated, and there is a conflict. In this case, the server must return the HTTP Status code (412 Precondition Failed) along with the updated values of ETag and Last-Modified headers.

Rule 186: If request integrity is important, ask your client to send the signature in the header and make sure to validate it (see Rule#81). If the signature is not provided or is not valid. return HTTP status code (403 Forbidden) along with an error report in the response body describing the issue

DELETE HTTP Method Rules

Rule 187: Use DELETE to delete an existing object. The following example deletes already existing user with id 121: DELETE /users/121

Rule 188: If the consumer didn't provide or provided invalid or expired credentials (In the Authorization header), return the HTTP Status code (401 Unauthorized), and it is recommended to return the WWW-Authenticate header to tell the client what kind of authentication is expected

Rule 189: If the consumer provided un-authorized credentials, return HTTP status code (403 Forbidden)

Rule 190: if the requested resource (collection or object) doesn't exist and the server doesn't know if the resource was there before or not, return HTTP Status code (404 Not Found)

Rule 191: if the requested resource doesn't exist and the server knows that the resource was there before, return the HTTP Status code (405 Gone). This is applicable in case an old version of API has been removed, and the server doesn't know if there is a newer version.

Rule 192: if the requested object resource doesn't exist and the server knows it was there before, return (405 Gone). This is applicable in this case a logical delete mechanism is implemented at the level of the object.

Rule 193: if the requested resource has moved to a different location, return the HTTP Status code (301 Moved Permanently) with the Location header value pointing to the new URI. This applies if a client requests an old API version and the server knows where the new version is (see Rule#25).

Rule 194: If the request has a payload but doesn't include a Content-Type header. Return status code (400 Bad Request).

Rule 195: If the request has an unsupported media type defined in the Content-Type header, return status code (415 Unsupported Media Type)

Rule 196: If the request has a body but it doesn't match the media type defined in the Content-Type header, return status code (400 Bad Request)

Rule 197: If the request has a body and it matches the media type defined in the Content-Type header, but the message structure or values are invalid, return status code (400 Bad Request)

Rule 198: in case of abnormal failures, return HTTP status code 5XX

Rule 199: in case of errors or failure, return an error report in the response body describing the issue.

Rule 200: Return status code (204 No Content) for a successful response and don't return a payload in the response body

Rule 201: Avoid returning the success code with an error in the body.

Rule 202: Return Last-Modified header to inform the consumer of the new last update date time

Rule 203: Allow conditional DELETE requests by supporting If-Unmodified-Since and If-Match headers to prevent deletion based on an invalid state:

  1. The client can propagate If-Unmodified-Since with previously retrieved Last-Modified Or can propagate If-Match with previously retrieved ETag
  2. The server validates the value; if the condition is true, that means the resource has not been updated, there is no conflict, and the server must return HTTP Status Code (204 No Content)
  3. If the condition is false, that means the resource is updated, and there is a conflict. In this case, the server must return the HTTP Status code (412 Precondition Failed)

Rule 204: If request integrity is important, ask your client to send the signature in the header and make sure to validate it (see Rule#81). If the signature is not provided or is not valid. return HTTP status code (403 Forbidden) along with an error report in the response body describing the issue

PATCH HTTP Method Rules

Rule 205: Use PATCH to update an existing object partially. Following example updates already exist user with id 121: PATCH /users/121

Rule 206: PATCH is relatively new and may not yet be supported by old tools and network devices.

Rule 207: With PATCH, it is recommended to use the standard patch format RFC6902. For example:

{ "op": "add", "path": "/a/b/c", "value": "foo" }

Rule 208: Advertise support for the PATCH via the allow header of the OPTIONS response.

#Request

OPTIONS /customers/1

#Response

HTTP/1.1 204 No Content

Allow: POST, GET, PATCH

Accept-Patch: application/json

Rule 209: If the consumer didn't provide or provided invalid or expired credentials (In the Authorization header), return the HTTP Status code (401 Unauthorized), and it is recommended to return the WWW-Authenticate header to tell the client what kind of authentication is expected

Rule 210: If the consumer provided un-authorized credentials, return HTTP status code (403 Forbidden)

Rule 211: if the requested resource (collection or object) doesn't exist and the server doesn't know if the resource was there before or not, return the HTTP Status code (404 Not Found)

Rule 212: if the requested resource doesn't exist and the server knows that the resource was there before, return the HTTP Status code (405 Gone). This is applicable in case an old version of API has been removed, and the server doesn't know if there is a newer version.

Rule 213: if the requested object resource doesn't exist and the server knows it was there before, return (405 Gone). This is applicable in this case a logical delete mechanism is implemented at the level of the object.

Rule 214: if the requested resource has moved to a different location, return the HTTP Status code (301 Moved Permanently) with the Location header value pointing to the new URI. This applies if a client requests an old API version and the server knows where the new version is (see Rule#25).

Rule 215: If the request has a payload but doesn't include a Content-Type header. Return status code (400 Bad Request).

Rule 216: If the request has an unsupported media type defined in the Content-Type header, return status code (415 Unsupported Media Type)

Rule 217: If the request has a body but it doesn't match the media type defined in the Content-Type header, return status code (400 Bad Request)

Rule 218: If the request has a body and it matches the media type defined in the Content-Type header, but the message structure or values are invalid, return status code (400 Bad Request)

Rule 219: in case of abnormal failures, return HTTP status code 5XX

Rule 220: in case of errors or failure, return an error report in the response body describing the issue(s).

Rule 221: Return status code (204 No Content) for a successful response and don't return a payload in the response body

Rule 222: Avoid returning a success code with an error in the body.

Rule 223: Return Last-Modified header to inform the consumer of the new last update date time

Rule 224: Return the ETag header to inform the consumer about the latest version of the resource. ETag can be generated using MD5 hash value

Rule 225: Allow conditional PUTrequest by supporting If-Unmodified-Since and If-Match headers to prevent concurrent update conflicts:

  1. The client can propagate If-Unmodified-Since with previously retrieved Last-Modified Or can propagate If-Match with previously retrieved ETag
  2. The server validates the value; if the condition is true, that means the resource has not been updated, there is no conflict, and the server must return HTTP Status Code (204 No Content)
  3. If the condition is false, that means the resource is updated, and there is a conflict. In this case, the server must return the HTTP Status code (412 Precondition Failed) along with the updated values of ETag and Last-Modified headers.

Rule 226: If request integrity is important, ask your client to send the signature in the header and make sure to validate it (see Rule#81). If the signature is not provided or is not valid. return HTTP status code (403 Forbidden) along with an error report in the response body describing the issue

REST API Design Process

  1. Find the nouns in the user story and model them as Resources
  2. Assign the Resources unique URIs. Use URL naming rules
  3. For Resources that can exist only as part of another Resource, define them as sub-resources. For example: /users/{user-id}/addresses
  4. Build schemas for the resource representations using JSON Schema and/or XML Schema. Use Data Model Rules
  5. Define the relationships between the models
  6. Build Hyper-medias to link the resources and include them in the resources schemas. Use Hypermedia rules.
  7. Find the verbs in the user story, try to map them to the CRUD operations, and associate them with the resources. Use POST Method Rules
  8. Find the non-CRUD verbs and define them as sub-resources. Use POST Method Rules
  9. Build Hyper-medias for workflows activities and include them in the schemas
  10. Build Hyper-medias for pagination and include them in the schemas
  11. Build a special-purpose resource for Async Tasks (/async-tasks)
  12. Describe the API using Open API Specs and use $ref to include the representations schemas

References

The above list of rules has been collected and consolidated from the following references:

  1. www.arcitura.com
  2. RESTful Web APIs, by Leonard Richardson
  3. REST API Design Rulebook, by Mark Masse
  4. Designing Web APIs - Building APIs that developers love, by Brenda Jin
  5. Restful Web Services Cookbook, by Subbu Allamaraju
  6. W3C Activity Stream Vocabulary
  7. Dublin Core
  8. Schema.org
  9. Microformats Wiki
  10. http://xmlns.com/foaf/spec/
  11. https://tools.ietf.org/html/rfc8288
  12. https://www.iana.org/assignments/link-relations/link-relations.xhtml
  13. https://tools.ietf.org/html/rfc6570
  14. https://tools.ietf.org/html/rfc7807
  15. https://tools.ietf.org/html/rfc6906
  16. https://tools.ietf.org/html/rfc5005
  17. https://tools.ietf.org/html/rfc4685
  18. https://tools.ietf.org/html/rfc5829
  19. https://tools.ietf.org/html/rfc7946
  20. https://tools.ietf.org/html/rfc6902
  21. https://tools.ietf.org/html/rfc3339
  22. https://www.iso.org/iso-3166-country-codes.html
  23. https://en.wikipedia.org/wiki/ISO_4217
  24. https://datatracker.ietf.org/doc/html/draft-ietf-httpapi-deprecation-header-02
  25. https://www.rfc-editor.org/rfc/rfc8594.html
  26. https://www.rfc-editor.org/rfc/rfc6648

how to
Like

About the Creator

Haitham Raik

I have 20 years of experience in Software development and Software Architecture. In this page, I will share with you topics based on my expertise related to software development and architecture

Reader insights

Be the first to share your insights about this piece.

How does it work?

Add your insights

Comments

There are no comments for this story

Be the first to respond and start the conversation.

Sign in to comment

    Find us on social media

    Miscellaneous links

    • Explore
    • Contact
    • Privacy Policy
    • Terms of Use
    • Support

    © 2024 Creatd, Inc. All Rights Reserved.