API: Spec - QutEcoacoustics/baw-server GitHub Wiki

API: Spec

The purpose of this specification is to have a public, reliable, non-generated, document that reliably describes the baw-server rest API.

Previous development efforts left the API with redundancy. This spec defines an ideal state the API should strive to achieve.

A full list of available endpoints can be found here at the swagger endpoints for our APIs. For example the staging SwaggerDoc is at https://api.staging.ecosounds.org/api-docs/index.html.

You can also see the Swagger definition at swagger.yaml.

API standards

Inspired by: https://speakerdeck.com/jeremiahlee/good-to-great-api-design-patterns-beyond-rest

Casing

  • All segments of URLs for endpoints should be in snake_case
  • All querystring parameters should be accepted by the server either in camelCase or snake_case
  • All JSON responses will have their fields encoded in snake_case

Data Types

  • All numbers should be encoded bare (as in 123.345 and not "123.345")
  • All dates should be encoded as strings in the ISO8601 format
    • Offset or Zulu notation should never be omitted
  • Where units are not specified, SI units should be assumed
    • Non-SI units are extremely discouraged

Naming and routing

  • Resources should represent one logical entity
  • A base resource should be pluralised (e.g. audio_events)
  • HATEOAS is encouraged
  • Chatty API encouraged
    • Only the following information should be returned:
      • Information directly associated with the resource
      • Links to associated resources
      • Keys to associated resources
    • Exception:
      • if only one additional field is needed (other than any relevant keys) it may be included
  • Nested resources should be used sparingly
    • Only use nested resources for direct and logical associations
    • Entities with many associations should not be nested (i.e. no/too many logical parent association[s])
  • Similarly: array values are discouraged
    • especially where they could hold large numbers of items
      • the relationship should instead be expressed as a nested route/sub-entity
    • especially where editing the array is possible
      • we don't have a reliable method for updating parts of an array
      • the only option is to replace the entire value
      • the recommended method is to express the collection as a nested route/sub-entity

Standard Response format

All API requests should have a standard response format. This includes:

  • named meta data objects (described in following sections)
    • must contain at least status and message properties.
  • response data, either an array or single object ( [...] | {...} )
{
    "meta": {
        "status": 200,
        "message": "OK"
    },
    "data": []
}

Errors

Errors must:

  • return an appropriate response code
  • return a content type that matches what was requested

APIs may optionally return an 'error details object', which may include links designed to go straight into the page e.g. <a href="{value}">{key}</a>:

"error": {
    "details": "You aren't allowed access, but you can get permission",
    "links": { 
        "sign in": "...",
        "request permissions": "...",
        "confirm your account": "..."
    }
}

Standard CRUD patterns

Each of the following is implemented by standard on an API endpoint. Exceptions should be denoted.

  • GET: /resource
    • returns many 'resource' objects in an array body
  • GET: /resource/{key}
    • returns a single resource uniquely identified by key
  • GET: /resource/new
    • returns a single resource with defaults
  • POST: /resource
    • creates a new resource
    • the newly created resource is returned
  • PUT: /resource/{key}
    • a resource uniquely identified by key is updated
    • it is expected the entire resource is sent
    • the updated resource is returned
  • PATCH: /resource/{key}
    • Updates a subset of the properties uniquely identified by key
  • DELETE: /resource/{key}
    • deletes a resource that is uniquely identified by key
    • See API: Archiving for full semantics of soft-deleteable resources

See API: Media Types.

Specialized patterns

Each of the following is optionally implemented on a standard API endpoint.

If you need a resource that supports remote prodcedure calls (RPCs) then consider

a) Redesigning your resource or b) following the pattern in API: Actions document.

Delayed Response

NOT IMPLEMENTED

- For any sort of endpoint
- For requests by browsers
    - either leave request open
    - or present with retry html page
- For API requests
    - Return `retry-after` header
    - Response should include 'delayed response object`, which may include an indication of high load
"delayed_response": {
    "retry_after": 22.0,
    "average_response_time": 13.0,
    "current_average_response_time": 25.0 
}

Sorting (for /resource)

- for query string parameter:
   - `orderBy`=`<field name>`
   - `direction`=`[desc|asc]`
- Response should include 'sorting details object'
"sorting": {
    "orderBy": "field",
    "direction": "desc"
}

Paging (for /resource)

- for query string parameters (all optional):
   - `page` = `<integer greater than 0>` (default 1)
   - `items` = `<integer greater than 0>` (default 25)
   - `disable_paging` = `<boolean>` (default `false`, mutually exclusive with `page` and `items`)
- Response should include 'paging details object'
"paging": {
    "page": 1,
    "items": 25,
    "total": 262,
    "max_page": 11,
    "current": "http:\/\/baw.ecosounds.org\/audio_recordings\/filter?items=25&page=1",
    "previous": null,
    "next": "http:\/\/baw.ecosounds.org\/audio_recordings\/filter?items=25&page=2"
}

Projection (for /resource)

- QSP: `projection_exclude`: comma separated list of resource fields (suggestion, not implemented)
- QSP: `projection_include`: comma separated list of resource fields (suggestion, not implemented)
- Response should include 'projection details object'
"projection": {
    "include": [
        "(resource field 1)",
        "(resource field 2)"
    ]
}

"projection": {
    "exclude": [
        "(resource field 1)",
        "(resource field 2)"
    ]
}

the options pattern

  • any additional parameters that control a resource are considered an option
  • they must not affect filtering, projection, paging, or sorting
  • they should affect the shape of the data
  • when options are included in a QSP they are not prefixed (e.g. ?bucket_size=86400)
  • when options API filter request body they are nested under the options key

Currently there is one proposed option: bucket_size

"options": {
   "bucket_size": 86400
}

Some routes may need to return summary statisitcs, or aggregates over data. See API: Stats

Capabilities are defined in the API: Capabilties document.

Arbitrary filter functions are defined in the API: Filtering document.

⚠️ **GitHub.com Fallback** ⚠️