General API Considerations
Protocol, Encoding, and Constraints
All services communicate exclusively over HTTP on port 80, using UTF-8 encoded JSON data transferred according to REST conventions, including the HATEOAS hypermedia constraint.
All clients and servers follow the same set of API conventions, which in their most terse form can be summed up as “
GET resource, ignore excess, follow hyperlinks”.
The somewhat longer and partly repetitive version is this:
- Resources have unique URIs
- Every resource in the system – users, shopping carts, items, searches, etc – has its own basic URI from which a JSON resource representation is obtained through an HTTP
GET. Documentation describes all such resource URIs and the HTTP methods they support.
- Resources are hypermedia
- They can link to any URI and any type of content, not just JSON, but any type of text or binary format. API resource representations are in JSON, but they can link to anything anywhere on the internet.
- Excess data in resources should be ignored
- This allows APIs to evolve without upping the version number when data fields and/or methods are added to resource without affecting the existing contract, which is most of the time. However...
- Excess data in resources must be preserved
- If a resource contains an unspecified data field, it should be preserved unchanged when updating the resource. Resources should be treated as a whole and updated as a whole, with all the data previously received preserved in the interim.
- Resources always contain a
- This, the URI mentioned above, is used as an URL in requests and as an URN in databases.
- Resources contain hyperlinks for possible next steps
- Resources contain named hyperlinks to URIs representing the next possible steps in handling them. Documentation for a resource describes all available hyperlinks. Not all of them might be present at the same time in resources which have state. Clients use only the embedded hyperlinks in order to manipulate a resource.
- Hyperlinks are opaque
- Query arguments may be added to some URIs, but the URIs themselves are opaque. No conclusions may be drawn from parsing hyperlinks. This frees developers from having to learn conventions for constructing URIs. All they need to know are the public API entry points for each resource. The concept of named hyperlinks also allows the server to modify the URI scheme without the clients having to be updated. This is extremely important as the APIs evolve.
- Clients may not construct URIs except initially to obtain the basic resource
- To be fair, nothing prevents a client from constructing URLs by concatenating strings, but clients that do so are on their own, as secondary URLs are subject to change at any time without previous notice. By using the main resource entry point to discover data and the available operations on them via their embedded dynamic hyperlinks, a very high degree of decoupling is achieved. This reduces client development costs and increases client life.
- Clients may save links persistently
- Services will handle detection of legacy links and will upgrade them transparently. This is also how external partners' computer systems store references to resources in our API: they are simply represented by the
selfhyperlink URI, stored in the external system as a URN. External partners must never decompose any such URI in order to obtain a shorter or simpler ID; they must always store the whole
selfhyperlink URI as a string, for the purpose of later manipulating the resource. This includes the URI protocol, query args, anchors, etc.
The following are the main HTTP methods in Ocean:
POSTto the collection URI of a resource creates a new resource and returns its JSON representation. The operation is not idempotent.
GETrequests are use to obtain a JSON resource representation of a resource member or collection.
GEToperations should always be idempotent and may be cached.
HEADrequest is treated as a
GETbut the response contains only headers.
- Used to update all the attributes of a resource at the same time, i.e., to completely change its state. The operation is idempotent by definition: subsequent
PUTrequests with the same data should put the resource in exactly the same state and have no other side effects (e.g., a
PUTrequest to an API endpoint designed to add something to a collection must only add it once and must not generate an error for subsequent, identical requests).
- In Ocean, however,
PUTcan be used to only set some attributes of a resource. Ocean services will generate an error if required attributes aren't supplied, but optional attributes can be left out, in which case the semantics become exactly like those of
PATCHand idempotency no longer holds. It's up to you to ensure that all attributes are included in the
- Used to update some (or all) attributes of a resource. Ocean treats
PATCHis not idempotent unless all attributes are set.
- This method is used to destroy a resource. It is by definition an idempotent operation, as multiple
DELETErequests to the same URL always produce the same state.
- Ocean services can use the
PURGEmethod to expire single URIs in the Varnish cache.
PURGErequests are only allowed from the local network.
- Ocean services can use the
BANmethod to expire multiple URIs in the Varnish cache.
BANrequests are only allowed from the local network.
Date and Time
All datetimes are expressed as strings in UTC/GMT, Greenwich Mean Time, expressed unambiguously in ISO-8601 format:
It is up to the client to submit datetime strings in a parseable, unambiguous standard ISO format. Times should be in GMT/UTC. If in other time zones, they will be converted to GMT wherever possible. Conversely, clients are also expected to convert GMT time strings to a user-readable format in the local time zone when presenting them to end users.
All resources are versioned. The version number is part of the URI (URL, URN). All clients should specify the exact version of each resource when first requesting them. After sending the request to create, obtain, update or delete a resource, the client should completely ignore the version of the resource and treat the URI as opaque, as the API may transparently upgrade it.
Thus, you may request a resource of version
v1 but receive the resource in
v8 or any later version. Resources are guaranteed to be backward compatible. Similarly, you may
PUT a resource of a certain version but receive the same updated resource in a more recent version. In this way, the API is able to evolve transparently. At any point in time, resources of later versions than available at the time of writing a client can, may, and will float around in your client's data structures. In fact, you will always get Resources of the latest version when you create (
POST) or update (
This is the reason for the oft repeated rule in these docs to never draw any conclusion from the structure of any URI you are given by the API. It may change without any notice. Don't build URLs except for the public ones.
Unified URI structure
Ocean uses a unified URI structure for all API endpoints:
As you can see, the format is the standard HTTP URI format, with the added convention that the URI path always begins with a resource version followed by the name of the resource in plural.
- The version is always a string starting with a lowercase
v, followed by a positive integer, e.g.
v3and so forth.
- The resource name is always in plural and in all lowercase:
groups, etc. Underscores may be used, e.g.
Here's an example:
This URI represents the collection of all Services available in an Ocean system. It could be used as a URL in an HTTP request to retrieve the representation of all Services, like so:
GET /v3/services HTTP/1.1
Or it could be used as a URN and stored in a database for later use as a URL in a request.
API descriptions give only the Public URIs supported for a service, that is, its entry points. A client should always start with one of these, and then use its embedded hyperlinks to discover what can be done with the resource and any related resources. All URLs necessary for further manipulation, or further discovery of related resources, will be given in the Resource Representation returned by requests to a Public URI.
As an example, a User Management service may define a resource called a User, with a particular URI for a specific user. The representation returned will always contain a link to the User object itself – its universal ID – but it might also contain hyperlinks to an Address resource, a Phone resource, an Employer resource, and so on. It could also contain these resources embedded in itself; if so, the embedded resource representations will be self-contained, each representation having at least a