Performance

Embedding resources

In order to reduce the number of requests, optional embedding of subresources may be used.

Embedded subresources MUST be put in a JSON object named embedded at root level of the JSON document. In this object, each property key is the URI and the value the full JSON representation of the subresource. The URI MUST be the same as the href value by which the subresource is referenced in the representation of the main resource.

Embedded resources are returned at the client’s request if the embed query parameter is specified. The name of the JSON property referencing the subresource can be used as value of the embed parameter.

This way of embedding resources limits the changes required when a clients starts to use it, and only impacts the JSON Schema type of the root document. It also works well when there are multiple occurrences of the same subresource, and when embedding resources more than one level deep.

In JSON Schema, additionalProperties can be used to specify the data types allowed in embedded. Note that it not possible to specify more than one data type this way in OpenAPI, so the only restriction that can be specified is type: object when there are multiple embedded data types.

GET http://myrestapi/family/32456?embed=children&embed=parents

{
  "self": "http://myrestapi/family/32456",
  "family": {
    "parents": [{
      "ssin": "12345678901",
      "href": "http://myrestapi/people/12345678901"
    }],
    "children": [{
      "ssin": "98765432101",
      "href": "http://myrestapi/people/98765432101"
    }]
  },
  "embedded": {
    "http://myrestapi/people/12345678901": {
      "self": "http://myrestapi/people/12345678901",
      "ssin": "12345678901",
      "givenName": "Jane",
      "lastName": "Doe"
    },
    "http://myrestapi/people/98765432101": {
      "self": "http://myrestapi/people/98765432101",
      "ssin": "98765432101",
      "givenName": "Bobby",
      "lastName": "Doe"
    }
  }
}

JSON data type

Family:
  description: A family
  type: object
  properties:
    parents:
      type: array
      items:
        $ref: '#/definitions/PersonRef'
    children:
      type: array
      items:
        $ref: '#/definitions/PersonRef'
    embedded:
      type: object
      additionalProperties:
        $ref: 'person.yaml#/definitions/Person'

GET {API}/employer/409536968?embed=employees(address)

Caching

HTTP caching SHOULD be considered for resource types for which the same resources are repeatedly retrieved by clients.

The following schema shows a decision tree for the caching setup for a given resource:

http cache decision tree

Conditional requests

Conditional requests are those where the client can ask the server if it has an updated copy of the resource. The client will send some information about the cached resource it holds and the server will determine whether updated content should be returned or the client’s copy is already up to date. In the latter case, an HTTP status of 304 Not Modified is returned.

conditional

Though conditional requests do invoke a call across the network, unmodified resources result in an empty response body – saving the cost of transferring the resource back to the end client. The backend service is also often able to very quickly determine a resource’s last version or modification date without accessing the resource which itself saves non-trivial processing time.

Time-based

A time-based conditional request is based on the the last modified time of the resource. If the cached copy’s last modification time is still the most recent one, the server returns the 304 response code. To enable time-based conditional requests, the application specifies the last modified time of a resource via the Last-Modified response header.

Last-Modified: Mon, 03 Jan 2011 17:45:57 GMT

The next time the browser requests this resource it will only ask for the contents of the resource if they’re unchanged since this date using the If-Modified-Since request header

If-Modified-Since: Mon, 03 Jan 2011 17:45:57 GMT

If the resource hasn’t changed since Mon, 03 Jan 2011 17:45:57 GMT the server will return with an empty body with the 304 response code.

The Last-Modified header doesn’t allow subsecond precision, which may lead to incorrect cache hits if there are two updates within a second.

Because of this, the ETag SHOULD be preferred over the Last-Modified header.

Content-based

The ETag (or Entity Tag) works in a similar way as the Last-Modified header except its value is a free-form tag identifying a resource version. Valid ETags can be a MD5 hash, a version number or a modification timestamp, allowing more precision than when using a Last-Modified-header.

This allows the server to identify if the cached contents of the resource are different to the most recent version.

ETag: "15f0fff99ed5aae4edffdd6496d7131f"

On subsequent browser requests, the If-None-Match request header is sent with the ETag value of the last requested version of the resource.

If-None-Match: "15f0fff99ed5aae4edffdd6496d7131f"

As with the If-Modified-Since header, if the current version has the same ETag value as the browser’s cached copy, then an HTTP status of 304 is returned.

Client caching directives

Cache-Control header

An HTTP client cache may cache server responses and decide to not even contact the server when the resource is requested again, saving the round trip to the server. The Cache-Control response header specifies directives for the client under which conditions and how long it should cache the response contents. This is useful for resources which don’t change frequently, and a client doesn’t need to be always synchronized with the latest version of the resource.

Cache-Control:public, max-age=86400

The response data may be cached by clients and intermediary servers as it is public, and should expire from the cache after 1 day (86400 seconds).

Vary header

The Vary response header describes which request headers, aside from the method, Host header field, and request target, influence the origin server’s process for selecting and representing this response. It is used to prevent unwanted cache hits.

See Best Practices for Using the Vary Header for more guidelines on the usage of the Vary header.

Vary: Accept

This avoids using a cached XML response when a second request asks for JSON.

Never use Vary: * as it will result in a cache hit of 0.

Increasing Application Performance with HTTP Cache Headers
Google HTTP Caching
Best Practices for Using the Vary Header