APIOps® Cycles

REST API Design Guide

General guidelines

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).

In a nutshell:

  • Keep APIs’ functionalities as simple as possible. The endpoints do only one thing, but they do it well.
  • Avoid overlapping functionalities between different APIs.
  • In error case include in the API response verbose description.
    • include also a description about erroneous parameter value, if it is feasible.
  • Implement in each API (or bundle of APIs) ability to generate of its own machine readable document about it’s functionality.
  • API must have support for the OPTIONS endpoint, which is needed for example in preflight request in SwaggerUI

Minimum developer experience

  • Each API must have descriptive title
  • The description of API must be sufficient.
  • Each API must have documentation, either a swagger file or open API specification.
  • Each API must have own logo
  • Each API should have getting started section to provide low learning curve and fast 1st positive experience for the consumer

Format of API specification

Use the most recent OpenAPI version supported by the API management platform for describing your API. 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.

Naming standards

  • All URI parts including resource names are written in small letters.
  • Use only camelCase in all attribute (field) names.
  • Do not use special characters in URI or in attribute names.
  • Use English only in OpenAPI specification.
  • Use common legally used or industry specific (not company specific) words about resources and attributes. Refer to ISO standards as primary source, then use WTO, EU or other trade area specific vocabularies, http://schema.org/ or industry specific vocabularies for naming. As last resort refer to company specific vocabularies before inventing your own.
  • Avoid using general names like “type”, “status” etc. without specifying what type, what status or better yet, avoiding those words all together.
  • Use ISO standard or other generally used (see above) values for attribute values such as languages, country names etc. Avoid using magic numbers as values or provide also the human language alternative, preferrably according to the Accept-Language header in the request.

Localization support

Accept-Language header should be used to support localized strings and possible localized logic. All time stamps 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.

Privacy & Security

Private or confidendial 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 thought of when spliting 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.

URI Components


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 around about the way the versioning is indicated: whether API version should be included in the URL or in a header.

Common convention is to have the version in the URL of APIs. The reason is to ensure browser explorability of 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 it’s own version and each API consuming client application is only able to use 1 version of the API at a time. If same client would use multiple versions of the same API at a time, they need to do different subscriptions. This versioning strategy works with all clients and is suited for caching and HATEOAS.

Versioning in - Azure API Management

When 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.

Examples of breaking changes

  • renaming fields or resource paths or endpoints
  • changing field type (e.g. from string to a list of strings)
  • changing structure of payload (removing/renaming/retyping fields)
  • altering HTTP verbs
  • changing response HTTP codes

In case of breaking changes making a new version of the updated API is mandatory.

URI Template



If there is any major breaking update, the new set of APIs is named as vx .


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 the company’s hierarchy.

Namespace separates different logical APIs from each other, which is usefull if you have lots of APIs with different purposes and they may end up using same resource or operation names.

Namespaces in different API management solutions:

  • IBM API Connect uses organizations, catalogues and spaces to organize publishing of APIs. These are usefull when there are multiple teams in charge of different APIs. Organization and catalogue form the name space of the API and those are always added automatically before version number or anything defined in the OpenAPI document basepath value or path-variable of each operation. 
  • Azure API management requires you to define a URI template when adding a new operation or by setting it for all operations in the OpenAPI document basepath value (required).

URI Template




Resource References

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


Collection Resources

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 plural as resource names e.g. /products.

Verb Usage Notes
GET Read

  Standard use does not include a request body for GET -requests. Most standard based tools and coding libraries do not support having a body. Some older systems can’t make GET -requests at all (only POST). Search queries with lots of search filters may end up having too long URLs (what is too long depends on the application limits, such as browsers).

POST Create

Supported by most (but not all) API consumers. Can be used as alternative for all other verbs if you need to support old or exotic clients or run out of URL length with GETs.

PUT Create

Theory says this should only be used when client gives the resource identifier, usually e.g. file with a client given unique name. Use with care, as all clients do not support PUT. Support those clients by implementing POST and not requiring identifier so new resource will be created and identifier returned to the client in the response body

PUT Update

Only for entire resource update, not partial, see above

PATCH Update

Used with JSON Patch message format. Use with care, as all clients do not support PATCH. Support those clients by implementing POST which can handle partial inputs, otherwise uses normal POST request body


Do not implement for collections if not absolutely sure to avoid accidental removal of multiple resources. DELETE has no request body, so identifiers can only be passed in the url. Should be repeatable with positive response.

Use HTTP methods in details (verbs)

All used methods and their parameters must be described in generated documentation endpoint by endpoint.

GET (read)

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.

  • E.g GET /users
    • returns list of all users
  • E.g GET /users?limit=10&skip=30
    • returns list containing 10 users after skipping 30 users

POST (create)

The POST method requests the server to create a resource in the database. The payload is sent in request message body.

POST is a non-idempotent operation which means that multiple requests targeted to same endpoint with same payload will have different outcome.

  • E.g POST /organizations/:id/managers
    • First attempt creates a new Manager of Organization identified with :id. (If it did not exist already).
  • E.g POST /organizations/:id/managers
    • Second attempt with same payload fails (because manager already existed) and an error response (4xx, manager already exists) is returned.

PUT (update)

The PUT method requests the server to update a resource. The payload is sent in 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. Use POST to create a new resource.

PUT is an idempotent operation which means multiple requests with same payload targeted to same endpoint will have the same effect and outcome, either successful update or resource not found.

  • E.g. PUT /organizations/:id

    • First attempt will request the server to update the resource (identified with :id) in Organizations collection.
      • A successful response with 2xx is returned, if resource is found.
      • In case resource is not found, an error response with 4xx is returned.
  • E.g. PUT /organizations/:id

    • Second attempt (with same payload) will request the server to update the resource (identified with :id) in Organizations collection.
      • A successful response 2xx is returned, if resource is found.
      • In case resource is not found, an error response with 4xx is returned.

DELETE (delete)

DELETE method requests that the resource, or its instance, should be removed from the database. Operation is irreversible.

  • E.g DELETE /apis/:id
    • Will request the server to delete the API identified with :id from Apis collection.
      • In a successful case a response with 204 is returned (no payload included).
      • In an unsuccessful case a response with 4xx is returned.

Error handling

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 than 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"}

Collection Resource

A list of all of the given resources, including any related metadata. 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 which the requesting party is allowed to see.

If the resource response is really big, provide possibility to include only those fields which the client requires. Also do add only those fields in the response, which you are absolutely sure are needed. It’s easier to add more later when needed than to remove which would be a breaking change.



Pages of results should be referred to consistently by the query parameters page and pageSize, where pageSize refers to the amount of results per request, and page refers to the requested page.

Fields like totalItems and totalPages help provide context to paged results. Use same fields with all resources to be consistant.

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 rels of nextpreviousfirstlast wherever appropriate.

Time selection

startTime or {propertyName}AfterendTime or {propertyName}Before query parameters should be provided if time selection is needed. All time values in the parameters and in the data must be in the ISO format including timezone.


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

Read Single Resource

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).

URI Template

GET /{namespace}/{version}/{resource}/{resource-id}

Example Request

GET /hardware/v1/products/6438313255314