RESTful API Design Patterns

Purpose

The purpose of this document is guidance for designing and building RESTful APIs.

Introduction

[Introduction statement here…]

RESTful API Patterns

Intro To REST

In 2000, Roy Fielding proposed Representational State Transfer (REST) as an architectural approach to designing web services.

REST APIs are designed around resources, which are any kind of object, data, or service that can be accessed by the client. A resource has an identifier, which is a URI that uniquely identifies that resource.

Clients interact with a service by exchanging representations of resources. Most web APIs use JSON as the exchange format.

REST APIs use a uniform interface, which helps to decouple the client and service implementations. For REST APIs built on HTTP, the uniform interface includes using standard HTTP verbs to perform operations on resources. The most common operations are GET, POST, PUT, PATCH, and DELETE.

REST APIs also use a stateless request model. 

Organize the API Around Resources

Focus on the business entities that the web API exposes. Resource URIs should be based on nouns (the resource) and not verbs (the operations on the resource). Use plural nouns for URIs that reference collections.

A resource does not have to be based on a single physical data item. While it can represent a data item, avoid creating APIs that simply mirror the internal structure of a database. Also avoid introducing dependencies between the web API and the underlying data sources.

It is also best to avoid resource URIs more complex than “/collection/item/collection”.

Define Operations in Terms of HTTP Methods

The HTTP protocol defines several methods that assign semantic meaning to a request. The common HTTP methods used by most RESTful web APIs are:

  • GET retrieves a representation of the resource at the specified URI. The body of the response message contains the details of the requested resource.
  • POST creates a new resource at the specified URI. The body of the request message provides the details of the new resource. Note that POST can also be used to trigger operations that don’t actually create resources.
  • PUT either updates or replaces the resource at the specified URI. The body of the request message specifies the resource to be updated or replaced.
  • PATCH performs a partial update of a resource. The request body specifies the set of changes to apply to the resource.
  • DELETE removes the resource at the specified URI.

Conform to HTTP Semantics

GET

  • A successful GET method typically returns HTTP status code 200 (OK).
  • If the resource cannot be found, return 404 (Not Found).

POST

  • Create a new resource, return HTTP status code 201 (Created).
  • Does processing but does not create a new resource, return HTTP status code 200 and include the result of the operation in the response body.
  • No result to return, return HTTP status code 204 (No Content) w/no response body.
  • Invalid data in the request, return HTTP status code 400 (Bad Request).

PUT

  • Update an existing resource, return either 200 (OK) or 204 (No Content).
  • Create a new resource, return HTTP status code 201 (Created).
  • Invalid data in the request, return HTTP status code 400 (Bad Request).

DELETE

  • If successful, return HTTP status code 204 (No Content).
  • If the resource doesn’t exist, return HTTP 404 (Not Found).

Filter And Paginate Data

GET requests over collection resources can potentially return a large number of items. Therefore the API should be designed to limit the amount of data returned by any single request. Also the API should be designed to allow passing of a filter in the query string of the URI.

Consider supporting query strings that specify the maximum number of items to retrieve and a starting offset into the collection.

Example: /orders?limit=25&offset=50

Use HATEOAS To Aid with Navigation

One of the primary motivations behind REST is that it should be possible to navigate the entire set of resources without requiring prior knowledge of the URI scheme.

Each HTTP GET request should return the information necessary to find the resources related directly to the requested object through hyperlinks included in the response, and it should also be provided with information that describes the operations available on each of these resources.

HATEOAS = Hypertext as the Engine of Application State.

NOTE: Currently there are no standards or specifications that define how to model the HATEOAS principle.

Example: GitHub @ https://api.github.com/

Versioning a RESTful web API

It is important to version APIs. There are many approaches to versioning APIs. Here are some examples:

No Versioning
            https://adventure-works.com/customers/3

URI Versioning
            https://adventure-works.com/v2/customers/3

Query String Versioning
            https://adventure-works.com/customers/3?version=2

Header Versioning
            GET https://adventure-works.com/customers/3 HTTP/1.1
            Custom-Header: api-version=1

Media Type Versioning
            GET https://adventure-works.com/customers/3 HTTP/1.1
            Accept: application/vnd.adventure-works.v1+json

General Guidance

Use nouns and NOT verbs
            GOOD = /products
            BAD = /getAllProducts

Use Plurals
            GOOD = /products
            BAD = /product

Use proper HTTP methods: GET, POST, PUT, PATCH, DELETE

User proper HTTP Response Codes: 200, 201, 204, 400, 404, 500

Use Query String Parameters (for filtering)
            /products?name=ABC should be preferred over /getProductsByName        

/products?type=xyz should be preferred over /getProductsByType

Provide Pagination

Version your APIs

Use forward slash (/) in URIs to indicate a hierarchical relationship

Do NOT use a training forward slash (/) in URIs

Use hyphens (-) to improve readability of URIs

Do NOT use underscores (_) in URIs

Use lowercase letters in URIs

Do NOT use file extensions (in URIs)

Never use CRUD function names in URIs

Do not expose the internal business objects or database objects; use DTOs

Query string parameters and object properties should use “camelCase

Example: GET

GET /customers

  • retrieve all customers

GET /customers/{customerId}

  • retrieve customer with id={customerId}

GET /customers/{customerId}/orders

  • retrieve all orders for customer with id={customerId}

GET /customers/{customerId}/orders/{orderId}

  • retrieve order with id={orderId} from customer with id={customerId}

GET /customers?lastnameStartsWith=smith&pageSize=25&pageIndex=100&orderby=FirstName

  • retrieves all customers with LastName starting with “smith”, sorted by FirstName and starting with record 101 and returning up to 25 records

Example: POST

POST /customers

  • create new customer

POST /customers/{customerId}/orders

  • create new order for customer with id={customerId}

Example: PUT

PUT /customers/{customerId}

  • full update of customer with id={customerId}

PUT /customers/{customerId}/orders/{orderId}

  • full update of order with id={orderId} on customer with id={customerId}

Example: PATCH

PATCH /customers/{customerId}

  • partial update of customer with id={customerId}

PATCH /customers/{customerId}/orders/{orderId}

  • partial update of order with id={orderId} on customer with id={customerId}

Example: DELETE

DELETE /customers/{customerId}

  • delete customer with id={customerId}

DELETE /customers/{customerId}/orders/{orderId}

  • delete order with id={orderId} from customer with id={customerId}

Appendix

API Design @ https://docs.microsoft.com/en-us/azure/architecture/best-practices/api-design

RESTfulAPI.net @ https://restfulapi.net/   

API Gateway @ https://docs.microsoft.com/en-us/azure/architecture/microservices/design/gateway

REST Security Cheat Sheet @ https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html

Solution Architecture Guidance