Skip to main content

Technical Policy – API Standard

17/05/22  |  All Guidelines and Documentation  |  C. Choosing the right technology

Version 1.0

The following web-based application programming interface (API) standards guidance will help teams deliver the best possible services to users.

API STANDARD

1. USE RESTFUL

Follow the industry standard and where appropriate build APIs that are RESTful, which use HTTP verb requests to manipulate data.  

When handling requests, you should use HTTP verbs for their specified purpose.

The following table illustrates the REST API Verbs:


REST Verb

Action
GETFetches a record or set of resources from the server
OPTIONSFetches all available REST operations
POSTCreates a new set of resources or a resource
PUTUpdates or replaces the given record
PATCHModifies the given record
DELETEDeletes the given resource

In some cases, it may not be applicable to build a REST API, for example, when you are building an API to stream data.

2. USE HTTPS

You should use HTTPS when creating APIs.

Adding HTTPS will secure connections to your API, preserve user privacy, ensure data integrity, and authenticate the server providing the API.

Secure APIs using Transport Layer Security (TLS) v1.2. Do not use Secure Sockets Layer (SSL) or TLS v1.0.  Make sure potential API users can establish trust in your certificates. Make sure you have a robust process for timely certificate renewal and revocation.

3. USE JSON

The first choice for all web APIs should be JSON where possible: 

  • create responses as a JSON object and not an array (JSON objects can contain JSON arrays) – arrays can limit the ability to include metadata about results and limit the API’s ability to add additional top-level keys in the future
  • document your JSON object to ensure it is well described, and so that it is not treated as a sequential array
  • use consistent grammar case for object keys – choose under_score or CamelCase and be consistent

Only use another representation to build something in exceptional cases, like when you:

  • need to connect to a legacy system, for example, one that only uses XML
  • will receive clear advantages from complying with a broadly adopted standard (for example, SAML)

4. USE UNICODE FOR ENCODING

The Unicode Transformation Format (UTF-8) standard is mandatory for use in government when encoding text or other textual representations of data.

5. LOG REQUESTS FOR PERSONAL DATA

If the API serves personal or sensitive data, you must log when the data is provided and to whom. This will help the team meet the requirements under the General Data Protection Regulation (GDPR), respond to data subject access requests, and detect fraud or misuse. 

6. AUTHENTICATION/AUTHORIZATION

Authentication is required when you want to identify clients for the purposes of:

  • authorization
  • auditing

Store all of your credentials (i.e., username & password, application IDs, database IDs, API Keys) in some type of Secrets Manager.

DO NOT under ANY CIRCUMSTANCES store your credentials in plain text, accessible via the code, deployment scripts, or version control (Git).

The API’s purpose will dictate the security requirements for your authentication solution.

APPLICATION-LEVEL AUTHORIZATION

Use application-level authorisation if you want to control which applications can access your API, but not which specific end users. The application-level authorisation is probably not suitable for APIs holding personal or sensitive data unless you trust your consumers, for example, another government department.

We recommend using OAuth 2.0, the open authorisation framework (specifically with the Client Credentials grant type). This service gives each registered application an OAuth2 Bearer Token, which can be used to make API requests on the application’s behalf.

USER-LEVEL AUTHORIZATION

Use user-level authorisation if you want to control which end users can access your API. This is suitable for dealing with personal or sensitive data.

For example, OAuth 2.0 is a popular authorisation method in government, specifically with the Authorisation Code grant type. Use OAuth 2.0 Scopes for more granular access control.

OpenID Connect (OIDC), which builds on top of OAuth2, with its use of JSON Web Token (JWT), might be suitable in some cases, for example a federated system.

If the client is supplying SSO Tokens, you will need to determine the LOA (Level of Assurance) of their token, and whether their token has the proper LOA to access the data they are requesting.

TOKENS AND PERMISSIONS

You should:

  • choose a suitable refresh frequency and expiry period for your user access tokens – failure to refresh access tokens regularly can lead to vulnerabilities
  • allow your users to revoke authority
  • invalidate an access token yourselves and force a reissue if there is a reason to suspect a token has been compromised.
  • use time-based one-time passwords (OTP) for extra security on APIs with application-level authorisation
  • use multi-factor authentication (MFA) and identity verification (IV) for extra security on APIs with user-level authorisation
  • ensure the tokens you provide have the narrowest permissions possible (narrowing the permissions means there’s a much lower risk to your API if the tokens are lost by users or compromised)

7. PROVIDE USERS WITH A TEST SERVICE

Your API consumers will want to test their application against your API before they go live. Provide them with a test service (sometimes referred to as a sandbox).

8. TEST API’s COMPLIANCE AND SECURITY

You should provide your development team with the ability to test your API using sample test data, if applicable. Testing your API should not involve using production systems and production data.

Validate everything that you receive and/or send (ex: Request Body, Content, Request Headers, Input Parameters, Character length). These are the values that malicious actors most frequently try to manipulate, to see if they can elicit a different type of response from an API.

Convert and map externally displayed identifiers to your internal identifiers. NEVER display the internal identifiers (ex: database ID, customer ID, etc.) to clients. Convert them to external identifiers (preferably in GUID/UUID formats) first, and display those. Otherwise, you run the risk of exposing your internal API data to the outside world.

Utilize any of the static code scanning tools to preemptively catch and refactor any vulnerable methods in your code before deploying to production.

Use dependency scans to scan and make sure that you are not using any compromised tools, libraries, or frameworks in your code that can end up being used as backdoors or attack vectors.

9. TEST API’s PERFORMANCE AND SCALABILITY

Performance is how fast an API can deal with a single request and create a response. Scalability is the number of concurrent requests an API can deal with before it slows down significantly.

As with user-facing services, you should test the capacity of your APIs in a representative environment to help make sure you can meet demand.  There are many tools available for each development environment that can help profile and monitor the API so that any performance and scalability issues can be detected during the development phase.  In addition, load test an API to ensure It will perform and scale when it goes into production. 

10. DOCUMENT THE API

To document an API:

  • use the OpenAPI 3 Specification where appropriate for generating documentation (recommended by the Open Standards Board)
  • provide sample code to illustrate how to call the API and to let users know what responses they can expect

The API documentation should include:

  • contextual/overview information – what the API does, who it might be used by and under what circumstances
  • business and data rules – under what circumstances is data available / not available
  • error scenarios – preconditions and outcomes – including error codes and messages
  • details on the test service – how to use it and how to simulate the various success and error scenarios
  • full details of request and response parameters, including meaning, data type and any other constraints. Give examples of valid values
  • rules on information handling, incident management and risk management
  • method of authentication
  • any authorisation rules, for example, use of OAuth 2.0 and specifically which scopes are required for this API
  • design changes (recent and planned) and versioning information
  • availability, latency, ownership, deprecation policies and status capability
  • approach to backwards compatibility
  • security information

REST API BEST PRACTICES

In addition to the API standards, while designing REST APIs, you need to focus on all these best practices to optimize the API design and readability to the team and other stakeholders. As a REST API developer, you should focus on security as well as the functionality of the API.

1. PREFER NOUNS OVER VERBS IN URI

Using nouns in your API URIs is the most conventional way to build descriptive API URIs.

In a RESTful API, the request verb (GET/ DELETE/ POST) tells us what the ‘operation’ is whereas the last noun in the URI tells us what type of object we are operating on.

Here are some examples which illustrate the operation and the object which is being operated on: 

  • GET  /users (our operation is to get/ list the user objects)
  • POST /users (our POST operation creates a new user)
  • GET  /users/1 (gets an individual user; user #1)
  • PUT  /users/1 (updates user #1)
  • GET  /users/1/orders (gets all orders for user #1)
  • POST /users/1/orders (creates a new order for user #1)

2. PREFER USING PLURAL NAMING CONVENTIONS

Another RESTful convention is using plural nouns for collections. The operations we are performing make more sense when the object names are pluralised.

You wouldn’t `GET` a list of `/user`

You would `GET` a list of `/users`

And because we want to build out our API like a tree we maintain the plural naming throughout.

`/users`

`/users/1`

`/users/1/orders`

`/users/1/orders/1`

`/users/1/orders/1/items`

`/users/1/orders/1/items/1`

3. UTILIZE RESOURCE NESTING EFFICIENTLY

Resource nesting should be carefully considered from the position of your API users. Sub-resources can be a powerful feature to allow your users to make fewer calls to your API but they often come at the price of greater server-side processing on the part of the API and increased complexity for the API URIs

For example:

`/users/1/orders/1/items` could be a useful endpoint. It could be used to show a user a summary of their order.

`/users/1/orders/1/items/1` could be used to show a summary of an item. But this doesn’t particularly benefit from being nested as your API will have other ways to look up items. In this case getting a list of items with `/users/1/orders/1` then making a request to `/items/1` for the item detail is probably the right choice.

4. DATA FILTERING OPTIONS

When dealing with large datasets it is a good practice to allow API users to retrieve only relevant data. This can be achieved by using a filter that will match data that satisfies the required criteria. Minimizing the data returned can save bandwidth between the API and the client and memory utilization by the API itself.

Common REST API filtering options include:

Filtering
Sorting
Paging
Field Selection

FILTERING

Using this you can filter results that satisfy your required conditions. You can use search parameters like country, creation, date, etc for this.

GET /users?country=CY
GET /users?creation_date=2021-10-11
GET /users?creation_date=2021-10-11

You should only allow query strings to be used in GET requests for filtering the values returned from an individual resource, for example, /users?state=active or /users?page=2.

You should never use query strings in GET requests for identification purposes, for example, avoid using the query string /users?id=1.

Query strings should not be used for defining the behaviour of your API, for example /users?action=getUser&id=1

SORTING

You can provide your users with the option to specify the sort order of their results in ascending and descending order using this option.

GET /users?sort=birthdate_date:asc
GET /users?sort=birthdate_date:desc

OFFSET-BASED PAGINATION

Using the ‘limit’ option, you can narrow down the results to the required number. You can also use ‘offset’ to show the part of the overall results displayed.

GET /users?limit=120
GET /users?offset=3

Query ParameterTypeDefault
offsetInteger0The (zero-based) offset of the first item in the collection to return
limitIntegerDepends on APIThe maximum number of entries to return. If the value exceeds the maximum, then the maximum value will be used.

FIELD SELECTION

Using the field selection function, you can request a specific subset of the data fields available for that object rather than receiving all the fields (which should be the default behaviour).

For example, while our `user` object may have any number of fields such as ‘email’, ‘telephone number’, ‘address’, ‘birth date’ or ‘creation date’ you might want to retrieve just the birth date and email to automate birthday wishes. You could use a query like this:

For a specific user:

GET /users/123?fields=name, birthdate, email

For a full list of users:

GET /users?fields=name, birthdate, email

5. USE OF ENUMS

Enums, or enumerated types, are variable types that have a limited set of possible values. Enums are popular in API design, as they are often seen as a simple way to communicate a limited set of possible values for a given property. It is a good practice to use enums when necessary to provide a complete set of possible returned or given values for a given property thus making data handling an easier task. 

6. HTTP STATUS CODES

There are many ways in which REST developers can tackle error handling. As a best practice, HTTP status codes must be based on the request result. For example, if a request has no content the appropriate “204 – No Content” HTTP status is sent. Or if a new record is being created the appropriate “201 – Created” HTTP status is sent.

So, standardized error codes along with the provision of proper documentation are also recommended good practices in API development.

For example, 

Successful responses from the API must return standardized status codes. 

HTTP statusDescription
    200 SuccessStandard response for successful HTTP requests. The actual response will depend on the request method used.
standardized status codes

Use appropriate status codes for different categories of errors.

HTTP statusDescription
400 Bad RequestThe server rejected the request as invalid.
401 UnauthorizedThe authentication associated with the request is invalid
403 ForbiddenAuthentication is valid, but user is not allowed to perform this operation
404 Not FoundA required object for this operation was not found
500 Internal ServerErrorThe server encountered an unexpected error while processing the request
Error categories
#printfriendly .pf-primary-img { display: none !important; } #printfriendly #pf-date { display: none !important; } #printfriendly { font-family: 'Roboto', sans-serif !important; }