Basics
Data hosted on Invend is exposed as resources accessible through a uniform hypermedia API which allows retrieval and manipulation.
The API-entry-point is either the application’s ID as subdomain of invend.eu
— called API domain, or a DNS CNAME alias which of it:
{app ID}.invend.eu
The API follows the REST architectural model. Resources are acted upon with HTTP action methods (verbs) having the following purpose:
HTTP Method | Description |
---|---|
OPTION | Used for preflight requests in a CORS scenario (see XXX). |
HEAD</span> | Just get the HTTP header info. |
GET | Read a resource. |
POST |
|
PUT | Create or replace a resource with a given identifier. |
PATCH | Partially update a resource (add, remove or overwrite single properties of the resource). |
DELETE | Delete a resource. |
Resources reside on the server. Client and server exchange representations of these resources as HTTP body data. In the following, the term resource is used as abbreviation of resource representation.
Data Transport, Encoding and Format
HTTPS protected Transport
Data privacy is ensured by using the HTTP over TLS — the HTTPS protocol.
TLS is only available on the API domain and not on DNS aliases.
SPDY Extension
The SPDY protocol (baed on TLS, HTTP) used if supported by the client. SPDY is a precursor of HTTP 2.0 and yields better performance in terms of latency.
UTF-8 Data Encoding
Structured resources are UTF-8 encoded.
ISO Time and Date Format
If not specified otherwise, all date values are ISO-8601 formatted and represented in the UTC time zone: {YYYY}-{MM}-{DD}T{hh}:{mm}:{ss}.{SSS}{TZ}
.
An example date string: 2014-08-31T12:00:00.000Z
Internationalized Resource Identifiers
Resources itself and many other concepts such as types and classes are identified by Internationalized Resource Identifiers (IRI). An IRI in short is a generalized URI with a less restrictive character set.
IRIs are treated as RFC3986 URI reference and thus relative references are resolved according to the corresponding reference resolution rules. In general absolute and relative forms can be distinguished. Relative IRIs might be relative to a collection or the API domain (authority part of the IRI).
For reference resolution, the following ways to define the base IRIs, against which the relative reference is applied, are supported in order of precedence:
-
Base IRI embedded in content via the
@base
property for LD resources. -
IRI used to access the resource.
-
Default base IRI which is defined by in the resource model (API domain and
path
property).
The server validates client provided IRIs in cases where ambiguous may exist and informs the client accordingly.
Interacting with Resources through Operations
This section describes how to interact with resources through operations. The description of these affordances is based on Hydra Core — an emergeing vocabulary to describe Web APIs.
CRUD Operations
The basic operations to create, read, update and delete a resource are shared by all resource types. The following table provides an overview of the operations, mapping to HTTP methods and their modification semantics.
Operation | HTTP Method | Modification Semantics |
---|---|---|
RetrieveResourceOperation |
GET |
read |
AppendResourceOperation</span> |
POST |
create |
CreateOrReplaceOperation |
PUT |
create |
UpdateResourceOperation |
PATCH |
update |
DeleteResourceOperation |
DELETE |
delete |
Operations do not obsolete the HTTP methods like GET — they are just mapped to them to have a formal identifier for those operations which can be referred to.
Operations supported by a resource are announced in the operation
property.
For example a client having read and write access to an address resource receives this when getting a resource:
"operation": [ { "@type": "RetrieveResourceOperation", "method": "GET", "returns": "http://meta.invend.eu/classes/Address" }, { "@type": "AppendResourceOperation", "method": "POST", "expects": "http://meta.invend.eu/classes/Address" }, { "@type": "CreateOrReplaceOperation", "method": "PUT", "expects": "http://meta.invend.eu/classes/Address" }, { "@type": "UpdateResourceOperation", "method": "PATCH" }, { "@type": "DeleteResourceOperation", "method": "DELETE" } ]
Request Headers
The API applies content negotiation via the Accept
header.
When data is requested, the following content types will negotiate to application/ld+json
:
-
application/ld+json
-
application/json
-
/
.
Sending data requires the Content-Type
header to be set to application/ld+json
.
The following header is required in case of a cross origin request:
-
The origin URL:
Origin: {proto}{fqdn}/{area}
.
These headers are omitted in the following examples to keep them brief.
Response Codes
Responses carry a meaningful HTTP status code and a response body. API consumers must interpret the HTTP response code as outcome of the request and react accordingly. All supported status codes are listed in the following table:
HTTP Status Code | Description |
---|---|
200 OK | The operation was successful. |
204 No Content | The operation was successful but the server did not return any content. For resource updates: returned when the key already existed and the file was replaced with what you sent. |
301 Moved Permanently | The requested resource has been assigned a new permanent URI and any future references to this resource should use one of the returned URIs. |
303 See Other | The resource was created.
The Location header contains the URL to query the newly
created resource. |
400 Bad Request | The submitted data in the request body or the query string parameters are syntactically incorrect or invalid in terms of format. |
401 Unauthorized | No or invalid authentication credentials have been provided |
402 Payment Required | A payment according to the contract with the provider of Invend is required |
403 Forbidden |
|
404 Not Found | The requested resource could not be found. |
406 Not Acceptable | An unsupported response format was requested. |
415 Unsupported Media Type | Data has been sent in an unsupported format. |
409 Conflict | A resource with the provided ID already exists. |
413 Request Entity Too Large | Request size limit exceeded. |
429 Too Many Requests | Rate limit exceeded. |
500 Internal Server Error | An internal error on the server occurred. |
503 Service Unavailable | We are temporarily unable to return the representation. Try again in a reasonable amount of time. |
Error Responses
Client errors are denoted by a 4xx
status code, sever errors by a 5xx
.
For some errors, also the body should be interpreted to derive a cause.
A request yielding an error results in a response like this:
{ "@context": { "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "hydra": "http://www.w3.org/ns/hydra/core#", "dct": "http://www.w3.org/ns/hydra/core#", "Error": "hydra:Error", "date": "dct:created", "request": "dct:identifier", "statusCode": "hydra:statusCode", "title": "hydra:title", "description": "hydra:description", "seeAlso": { "@id": "rdfs:seeAlso", "@type": "@id" }, }, "@type": "Error", "date": "2014-03-13T19:43:18.139Z", "request": "4d32dd9f-311b-47c6-97a3-8babf9b2d0b1", "statusCode": 403, "title": "Forbidden", "description": "The provided authentication information were valid but permission based on your credentials is not granted to perform the requested operation.", "seeAlso": "https://dev.invend.eu" }
Content Negotiation
The API strictly adheres to the content negotiation principle of HTTP. While the content representation (via the content type headers) is defined above, this section deals with the negotiable aspects of the content itself.
Multilingual Resources
Subject to negotiation are the values of properties which have language variants.
Language tags are formatted according to the BCP 47 standard.
Typically they consist of locale and an optional territory specific variant suffix.
So a valid locale is for example: en-GB
.
If a suffix (GB
in this example) is given, the exact translation for this variant is tried to be resolved, if it does not exist, the base locale (en
in this example) is used;
The so-called fall back locale is only considered in the case of absence of both.
There are the following ways to specify the preferred locale of which only the first is real HTTP based content negotiation.
Accept Language Header
Locales specified in the accept-language
header are tried to be accorded to in the weighted order representing their priority.
The primary locale is the one with the highest priority and the second priority is the fall back locale.
If non of the primary locales can be resolved, the fall back locale is tried to be resolved.
For the value en-us,de-de;q=0.8
, en-US
is used as primary locale and through the variant based fall back also en
.
de-DE
as it is explicitly specified as second priority and thus the fall back locale.
Client based Caching
All resource types are returned with the last-modified
response header to enable clients to caching them.
Clients may remember this date and make a conditional request using the request header if-modified-since: {date}
for subsequent requests.
The last-modified date is derived from the date properties created
and modified
(both from the DC terms namespace) for LD resources.
For collections of resources, the most recently changed entry is used as last-modified date.
Etags are not used by this API.
Exceptions
-
Files ending with
.appcache
are delivered as not cacheable to force user agents to check for updates.
Cross Origin Resource Sharing
Cross Origin Resource Sharing (CORS) is supported by the API and may be controlled by the API owner.
The relevant header to denote the origin of a request is the origin
header which must have a value of the form {proto}{fqdn}
.
The following CORS requests exemplify the outcomes of typical cases.
Example
A simple and allowed cross origin request which does not involve a preflight request looks like this:
$ curl -v -H 'Origin: https://www.invend.eu' -H 'Access-Control-Request-Method: GET' https://app-x.invend.eu/addresses/ < Access-Control-Allow-Origin: https://www.invend.eu < Access-Control-Allow-Credentials: true < Access-Control-Expose-Headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, Link, Cache-Control, ETag, Last-Modified < Access-Control-Max-Age: 1728000
The client may cache the response for 20 days considering the Access-Control-Max-Age
header.
A preflight request with positive reply:
$ curl -v -X OPTIONS -H 'Origin: https://www.invend.eu' -H 'Access-Control-Request-Method: GET' https://app-x.invend.eu/addresses/ < HTTP/1.1 204 No Content < Access-Control-Allow-Origin: https://www.invend.eu < Access-Control-Allow-Credentials: true < Access-Control-Expose-Headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, Link, Cache-Control, ETag, Last-Modified < Access-Control-Max-Age: 1728000 < Access-Control-Allow-Methods: HEAD, GET, PUT, POST, DELETE, OPTIONS < Access-Control-Allow-Headers: Authorization, Content-Length, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since < Strict-Transport-Security: max-age=1728000; includeSubDomains
A preflight request with negative reply due to an invalid origin:
$ curl -v -X OPTIONS -H 'Origin: http://invalid-origin.tld' -H 'Access-Control-Request-Method: GET' https://app-x.invend.eu/addresses/ < HTTP/1.1 403 Forbidden
Limits
Certain limits are lined up to prevent abuse of the API.
Request Rate
The request rate is limited per IP address at a maximum of 180 within a time window of 15 minutes. The following HTTP headers inform about the current call quota status:
Header Name | Description |
---|---|
|
The maximum number of requests that the consumer is permitted to make within a 15 minute window. |
|
The number of requests remaining in the current rate limit window. |
|
The time at which the current rate limit window resets in UTC epoch seconds. |
If the call limit is hit, HTTP status code 429
is returned.
If you require a higher volume, please contact support@invend.eu.
Request Size
The size of an HTTP request body is limited depending on the type of the resource and the content type (content-type
header) as shown below.
If the limit is hit, HTTP status code 413
is returned and the request is cancelled.
Structured data resources:
-
application/*+json
: 5.0 MiB. -
application/x-www-form-urlencoded
: 512 kiB.
Object data resources:
-
/
: 5.0 GiB (object + meta data).
Seriously REST
In this section it is shown how some of the advanced aspects of REST are realized in the API.
Self-Descriptive Resources
Each resource corresponds to a type which is defined by means of JSON-LD’s feature to corece values to particular data types.
The @type
keyword is used to define the data type of:
-
a resource (graph node) — whose type is a concept typically defined as RDFS Class.
-
a value — whose type is a relation (or predicate) which is typically an RDFS Property or just a plain data type like XSD boolean.
For example obtaining the @type
of the resource https://meta.invend.eu/timezones/
yields http://www.w3.org/ns/hydra/core#PagedCollection
.
Picking the resource http://www.w3.org/2006/timezone-world#ZTZ
from this collection and inspecting its @type
tells the client that it is of the type http://www.w3.org/2006/timezone#TimeZone
.
Linked data and Semantic Web principles imply that a coerced type is an IRI which usually can be dereferenced. Type IRIs usually dereference to an entry in a formal vocabulary which define the unambiguous meaning of the class or property thus enabling a client to introspect a resource.
Hypermedia Support
Affordances (things that can be done with a resource or in the current state of the application) make an API a hypermedia — a nonlinear medium which can be browsed without prior knowledge. Hypermedia is the prerequisite to support REST’s HATEOAS constraint. Affordances can be differentiated in two types, hyperlinks and operations. How they materialize in the API is described in the following.
Hyperlinks
Resource interlinking a native feature of the JSON-LD data format which is used to represent resources.
The @id
keyword allows definition of links like this:
"website": { "@id": "http://www.invend.eu" }
This allows to distinguish links to other resources from data where IRIs are used exclusively as identifiers.
Property values can also be declared as hyperlink by the intrinsic semantics of the property.
For example the property type http://schema.org/url
denotes that its value is a URL.
A client may use this knowledge accordingly.
Machine Readable API Documentation
Machine Readable API Documentation
A machine readable API documentation expressed in the terms of Hydra Core, listing all availableresources and its operations is available through the corresponding resource.
Usually it is mapped to /apidoc/
.
Performance Tips
GZip Compression
An easy and convenient way to reduce the bandwidth needed for each request is to use Gzip compression. Although this consumes additional processing resources to uncompress data, the trade-off with reduced latencies usually makes it very worthwhile.
Data is generally served Gzip encoded, if the Accept-Encoding
header contains the associated token.
For example, a properly formed HTTP request header for receiving a Gzip encoded response is:
Accept-Encoding: gzip
To specify that multiple content encodings are acceptable, they can be concatenated as shown in RFC2616.