How should endpoints i.e. the resources that our API allows the API consumers to use, be named? What features and thus endpoints should be included in the same API? To version or not and how?
There are no actual standards for how endpoints etc. should be named. There are some conventions and best practices that help the APIs to be RESTful. These conventions make the API easy to understand by humans as well as programming and integration tools. Design with the next phase, API Audit criteria in mind. When designing REST APIs, use the REST API style guide as your guideline.
At first, add only the endpoints and data attributes that you know are necessary. This reduces the need for versioning, support and maintenance. When an API is versioned the API consumers are at risk of having to make changes. There are many APIs that have succeeded in avoiding breaking changes.
Our goal is consistency, maintainability, and best practices across applications. APIOps aim to balance a truly RESTful API interface with a positive developer experience (DX).
Use the most recent OpenAPI version supported by the API management platform to describe your API, unless you are developing your API using GraphQL, AsyncAPI, gRPC or some other standard. OpenAPI Specification (Wikipedia) originally known as the Swagger Specification, is a specification for machine-readable interface files for describing, producing, consuming, and visualizing RESTful Web services.
Information about supported versions:
Use examples-attribute with JSON schemas (validated) to provide automatically generated documentation and smart mock data to help use the API.
The Accept-header should be used to support localized strings and possible localized logic. All timestamps should be in ISO format which contains timezone information. All dates and clock times with no specific timezone information associated should be informed in UTC +0.
All money values should be informed in specific currency and currency information should be contained in a custom x-companyname-currency header (in both request and response). Currency values should default to some provider or consumer based base currency if no specific currency has been requested.
Private or confidential data should not be passed in URI, Query or header parameters as they are logged and cached. Security constraints are defined in API Product level, but privacy and security should be considered when splitting requirements to APIS and endpoints, as security schemes are easier to implement on API level than endpoint level or by reflecting authorization in the allowed operations or response payloads.
Private or confidential data should not be passed in URI, Query or header parameters as they are logged and cached. Security constraints are defined in API Product l
Each API consumer needs to know which version of the API they are using and to be able to subscribe and use the version they need. There are mixed opinions about the way the versioning is indicated: whether API version should be included in the URL or in the header.
The common convention is to have the version in the URL of APIs. The reason is to ensure that the browser is able to explore the resources across versions.
In some API management systems, the version does not need to be in the URI nor in the header because each API product has its own version and each API consuming client application is only able to use 1 version of the API at a time. If the same client used multiple versions of the same API at a time, they would need different subscriptions. This versioning strategy works with all clients and is suited for caching and HATEOAS.
Versioning in - Azure API Management
When the version number is used it should always be in the URI since not all clients (for example marketing tools) can set headers and using version number as a query parameter might cause slowness as query parameters are not cached. Also, most API management platforms require that the URIs are unique if multiple versions of the same API are deployed at the same time.
The URI should include /vN with the major version (N) as a prefix. Having the letter v in front of the number is important to separate the version number from a resource identifier.
When APIs are upgraded with a breaking change, it may lead to breaking existing products or services using upgraded APIs.
Privacy and security should be considered when splitting requirements to APIs and endpoints, as security schemes are easier to implement on API level than endpoint level or by reflecting authorization in the allowed operations or response payloads.
In case of breaking changes making a new version of the updated API is mandatory.
URI Template
/v{version}/
https://domain.com/v1/apis
If there is any major breaking update, the new set of APIs is named as v (version number as integer).
In any URI, the first noun (which may be singular or plural, depending on the situation) should be considered a “namespace”. Namespaces should reflect the customer’s perspective on how the product works, not necessarily hierarchy in the company.
Namespace separates different logical APIs from each other, which is useful if you have lots of APIs with different purposes and they may end up using same resource or operation names.
URI Template
/{namespace}/{version}
Example /hardware/v1/
Try to use only one resource level, absolutely avoid using more than two levels to keep the URLs short to allow room for using variables.
URI Template
/{namespace}/{version}/{resource}/{resource-id}/{sub-resource}/{sub-resource-id}
Resource endpoints should follow at least View and CRUD (Create, Read, Update, Delete) operations. These should be handled by using the same URI but using different HTTP verbs (POST/GET/PUT/PATCH/DELETE, more details about each verb in ( https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html ) ).
Use nouns in the plural as resource names e.g. /products.
All used methods and their parameters have to be described in generated documentation endpoint by endpoint.
The GET method requests data from the resource and should not produce any side effect. The possible parameters are sent as part of the URL or as query parameters.
The POST method requests the server to create a resource in the database. The payload is sent in the request message body.
POST is a non-idempotent operation which means that multiple requests targeted to the same endpoint with the same payload will have a different outcome.
The PUT method requests the server to update a resource, but it can also create it. The payload is sent in the request message body.Normally it is not possible to create a resource with PUT method, because resources are referenced with :id. In case resource with :id does not exist, a response with 404 Resource not found is sent unless you give a resource name (like file name) in the PUT request. Use POST to create a new resource and POST or PATCH to do partial updates.
PUT is an idempotent operation which means multiple requests with the same payload targeted to the same endpoint will have the same effect and outcome, either successful update or resource not found.
DELETE method requests that the resource, or its instance, should be removed from the database. The operation is irreversible.
Just like an HTML error page shows a useful error message to a visitor, an API should provide a useful error message in a known consumable format. The representation of an error should be no different from the representation of any resource, just with its own set of fields.
The API should always return sensible HTTP status codes. API errors typically break down into 2 types: 400 series status codes for client issues & 500 series status codes for server issues. At a minimum, the API should standardize that all 400 series errors come with consumable JSON error representation. If possible (i.e. if load balancers & reverse proxies can create custom error bodies), this should extend to 500 series status codes.
A JSON error body should provide a few things for the developer - a useful error message, a unique error code (that can be looked up for more details in the docs) and possibly a detailed description.
JSON output representation for something like this would look like:
{ "code" : 1234, "title" : "Organization is not found", "detail" : "Organization with specified ID is not found" }
Validation errors for PUT, PATCH and POST requests will need a field breakdown. This is best modeled by using a fixed top-level error code for validation failures and providing the detailed errors in an additional errors field, like so:
{ "code" : 1024, "title" : "Validation Failed", "detail" : [ { "code" : 5432, "title" : "first_name", "detail" : "First name cannot have fancy characters" }, { "code" : 5622, "title" : "password", "detail" : "Password cannot be blank"} ] }
Paging
Pages of results should be referred to consistently by the query parameters page and pageSize, where pageSize refers to the number of results per request, and page refers to the requested page.
Fields like totalItems and totalPages help provide context to paged results. Use the same fields with all resources to be consistent.
Hypermedia links
Hypermedia links are high value in navigating paged resource collections, as page/pageSize query parameters can be maintained while navigating pages of results.
Links should be provided with reels of next, previous, first, last wherever appropriate.
Time selection
startTime or {propertyName}After, endTime or {propertyName}Before query parameters should be provided if time selection is needed. All time values in the parameters and in the data have to be in the ISO format including timezone.
Sorting
sortBy and sortOrder can be provided to allow for collection results to be sorted. sortBy should be a field in the individual resources, and sortOrder should be asc or desc.
URI Template
GET /{namespace}/{version}/{resource}
Example Request
GET /hardware/v1/products
A list of all of the given resources, including any related metadata. The array of resources should be in the items field to help handle other fields than the actual resources being returned in the response.
Plan for security and provide a list of only those resources the requesting party is allowed to see.
If the resource response is really big, provide a possibility to include only those fields the client requires. Also add only those fields in the response, that you consider absolutely necessary. It’s easier to add more later when needed instead of removing that would be a breaking change.
A single resource, typically derived from the parent collection of resources (often more detailed than the collection resource items).
All identifiers for sensitive data should be non-sequential, and preferably non-numeric. In scenarios where this data might be used as a subordinate to other data, immutable string identifiers should be utilized for easier readability and debugging (i.e. “nameOfValue” vs 1421321).
GET /{namespace}/{version}/{resource}/{resource-id}
GET /hardware/v1/products/6438313255314
Great APIs need skilled people and a good method, which let's you create APIs as products - fast.
APIOps Cycles method is vendor & technology-neutral.
Read the free e-book "The 8 wastes of lean in API development". Learn quick tips on how to remove the wastes using the APIOps Cycles method.