API Standards (evolving)
Baseline API Standards for OPG teams to use when building new APIs.
Adopt these standards if there is no reason not to, but you may break any of them if you have a compelling need.
Infrastructure
Design
- Use JSON for request and response bodies
- Use lowerCamelCase for keys
- Prefer flat structure, we don’t have a standard response format and should keep things as minimal as possible (e.g. don’t use something like JSON:API, or have all responses like
{"data": ...}
) Use RFC3339 to format dates
Examples of RFC3339 formatted dates:
- 2023-06-16
- 2023-06-16T09:04:38Z
- 09:04:46Z
Naming
REpresentational State Transfer (REST) is the defacto API architecture standard and the guidance below is on the assumption that REST will be used. The primary data representation in REST is a resource, which is a mapping to a set of entities. This dictates how REST APIs should be designed and the following princples should guide how the resources are addressed:
- Resources are represented by nouns. Resource names can be “real” nouns or abstract collections e.g.
/users
or/user-management
. - A resource can be a singleton or a collection. Collections are pluralised and singletons are addressed by ID. e.g.
/users/1
, whereusers
is a collection and1
is the singleton. - Resources are hierarchical, with resources containing other resources. These relationships are denoted with forward slashes. e.g.
/teams/1/users/2
. - A URI addresses the resource, not the action. HTTP methods should be used to indicate the action being performed. e.g.
HTTP POST /users
, not/users/create
. - Use query parameters to filter a resource collection instead of creating a new URI. e.g.
/users?role=admin
. - Use hyphens to improve readability. Avoid underscores and other separators. e.g.
/device-management/os-versions
. - Use lower case only. Case sensitivity is dependent on the browser, server, and host OS, so mixed-case should be avoided.
- Do not use file extensions in URIs. If this information needs to be communicated, use the
Content-Type
header.
Although we should strive to follow the standard as best practice wherever possible, there are situations where this isn’t possible, e.g. executing scripts via an API call. In these instances, it is necessary to provide adequate documentation so consumers are aware it is not addressing a resource.
Versioning
- Avoid versioning until there is a definite requirement
- Use SemVer to provide meaning and context to version changes
- Encode version in the header via Content Negotiation (
Accept
header) e.g.Accept: application/vnd.opg-data.v1+json
- Prefer additive changes over destructive ones
- Provide concrete deadlines and documentation to consumers
- Ensure APIs and network traffic is well-monitored
For further information, see the OPG Data versioning strategy
Documentation
- Use the OpenAPI Specification for documenting APIs
- This may be used by your API’s consumers to automatically generate mocks using tools like Prism
- Store in the repo at
/docs/openapi/openapi.yml
Authentication
- Use JSON Web Tokens (JWTs) to authenticate requests between OPG services
- Each JWT must contain the following claims:
- sub: Either an identifier of the user making the request (e.g. email address) or a service identifier if not user is involved
- iat: The timestamp of when the token was issued
- exp: The timestamp of when the token will expire
- iss: The service that issued the token
- APIs must validate “exp”, “iat” and “iss” claims, and the “nbf” claim if provided
- Each JWT must contain the following claims:
- Where APIs only have consumers inside OPG, use infrastructure tools (e.g. AWS IAM) to restrict access to those services
Performance
- We have no departmental performance requirements, but you should discuss as a team if you can set any for yourselves.
- Monitor realtime performance of your production services with the tools provided by AWS, such as CloudWatch Metrics and X-Ray
- Consider alternative techniques for slow-running transactions such as using asynchronous request/response patterns, or queuing onerous processes to execute after the response has been sent