Contribute: # REST API guidelines

Rationale

When writing new REST APIs, there are multiple ways to achieve the same feature.

Robustness principle

Try to follow the Robustness Principle:

Be conservative in what you do, be liberal in what you accept from others

REST API call = desired state, when possible

Example:

# Delete a user
DELETE /user/12
> 204
# Delete the same user again
DELETE /user/12
> 204, not 404

Generalization: do not raise an error if the desired state of a resource is already attained.

PUT response = no body

When receiving a PUT query, do not send the resource back in response.

Pros:

  • less bandwidth
  • still available in edit event and query body
  • generally unused

Cons:

  • body may be useful
  • resource may be deleted right after the PUT and won't be available by GET

What is in GET /status?

Each component in a daemon must be able to add values inside the body of /status.

Example body

{
  "ari": {
    "status": "ok"
  },
  "bus_consumer": {
    "status": "ok"
  },
  "service_token": {
    "status": "ok"
  },
  "plugins": {
    "voicemails": {
      "cache_items": 12,
      "status": "ok"
    },
    "bad_plugin": {
      "status": "fail"
    }
  }
}

Conventions

  • Each key MAY have a status subkey. Each value associated to the status subkey MUST contain a string. Conventional values for this string are ok and fail. Other values are acceptable too, depending on the status being reported.

  • If the key does not have a status value, the status SHOULD be considered ok.

  • Key names must use _ (underscore) as word separators.

Target audience

GET /status is intended for an administrator of the Wazo Platform instance. It MAY include technical details that MUST NOT be available to users or tenant-restricted admins.

REST API status codes

Invalid token = 401 Invalid tenant for the token = 401 Insufficient ACL = 403

Errors in REST API

Rationale

Errors should be as informative as possible when presented to the user. Hence, the REST API must give as much information as possible, and this information must be structured. A simple error message is not enough: it can't be translated easily, it does tell a GUI what field caused the error, etc.

Error structure

When an error occurs during a HTTP request on a REST API, the error returned must be in JSON format, with the following structure:

{
    "error_id": "not-found",  # this field serves as a "sub-status-code", e.g. to distinguish between two different 400 status codes that don't have the same cause
    "message": "No such user ID: 'abcdefg-1234'",  # this should be human-readable
    "resource": "user",  # this helps abstracting the client-side logic, giving back the context of the request
    "resource_id": "abcdefg-1234",  # idem. This field is optional. The value may be a dictionary.
    "timestamp": 1500908147.0837858,  # the timestamp when the error occured
    "details": {
        # as many details as we want about this error, usually what field is invalid and why
    }
}

Error details structure for invalid request

When returning a 400 status code, the error details should have this structure:

{
    ...
    "details": {
        "field1": {
            "constraint_id": "regex",
            "constraint": "[a-z]+",
            "message": "field1 must be lowercase alphabetic"
        },
        "field2": {
            ...
        }
    }
}

In case of a nested request, the details should be nested as well. Example:

Request:

{
    "config": {
        "url": "invalid"
    }
}

Response:

    "error_id": "invalid-data",
    "message": "Invalid request",
    "resource": "subscription",
    "resource_id": "abcdefg-1234",
    "timestamp": 1500908147.0837858,
    "details": {
        "config": {
            "url": {
                "constraing_id": "url",
                "constraint": {
                    "schemes": ["http", "https"]
                },
                "message": "Invalid URL"
            }
        }
    }

Pagination and collection in REST API

Parameters

  • direction: Sort list of items in 'asc' (ascending) or 'desc' (descending) order.
  • limit: Maximum number of items to return in the list.
  • offset: Number of items to skip over in the list.
  • order: Name of the field to use for sorting the list of items returned.
  • recurse: Should the query include sub-tenants.
  • search: Search term for filtering a list of items. Only items with a field containing the search term will be returned.

Collection result

  • items: Result of objects filtered
  • filtered: Number of object filtered by the filtering keys except from limit and offset
  • total: Number total of objects without filters
{
    ...
    "items": [
        {
            "uuid": "00000000-0000-0000-0000-aaaaaaaaaaaa",
            "name": "My object"
        },
        {
            "uuid": "00000000-0000-0000-0000-bbbbbbbbbbbb",
            "name": "Other object"
        }
     ],
     "filtered": 2,
     "total": 4
    }
}

OpenAPI convention in Rest API

Endpoints parameters order

  1. All type HEADER
  2. All type PATH
  3. All type BODY

Community Supported

Wazo Platform is supported by its community. Use our various channels to reach out.

Publications

Video @ Kamailio World: Dangerous Demos

Video @ the Telecom Application Development Summit: What can you do with Wazo?

Video @ the Telecom Application Development Summit: WAZO Keynote: xCPaaS

Get Connected, Contribute & Build value!

Designed with by Xiaoying Riley for developersCopyright 2016-2023 The Wazo Authors (see the AUTHORS file)