ARK2/API
API
ARK2 provides a new, standards-compliant, secure, complete API for query and update.
A number of popular API standards exits. ARK2 has chosen JSON:API as the default API standard, as this is the best suited to the full update functionality required by external apps. However, given the very large user base for JSON-LD within the heritage community, support will be added for it in read-only mode. The library used for JSON-LD will also provide HAL, JSON, and CSV standards support.
Background
An evolution of the ARK data model and API to try realise the full ARK vision will be based arround the Hypermedia concepts of REST and HATEOAS as developed by Roy Fielding in his doctoral thesis in 2000. These concepts include resources, relationships, state, and discoverability, and are closely related to the Semantic Web. ARK modules will evolve to represent Resources that can be linked in together in the current flat relationship structure, or organised into configurable hierarchies such as the default Site/Module/Item mostly used by ARK instances. These concepts will be most easily exposed through a RESTful API.
A RESTful API will be implemented using best practices which are outlined in the following articles:
- http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api
- http://blogs.mulesoft.com/dev/api-best-practices-series-intro/
In particular, the following rules will be applied:
- Full level 4 HATEOAS REST implementation
- JSON will be the only format supported
- The JSON API standard will be used to construct the response body, with JSON Schema standard defining the structure of the data payload.
- API versioning will be used to version the resource path structure, error messaging, and other API infrastructure. The actual data formats will be controlled by the JSON schema which will be available via a standard end-point.
- Authenticated access will only be available using HTTPS, API tokens, and OAuth2
- Read-only unauthenticated unencrypted access will be supported only if explicitly enabled
- Translation keys will be used, with the client downloading a translation catalogue for their required language
The general API URL structure will be as follows:
- /api/v2/<module>/<item>/<submodule>/<item>
e.g. for Site MNO12 and Context MNO12_1 the resource will be www.lparchaeology.com/ark/api/v2/sites/MNO12/contexts/1
A question remains over the structure for hosted ARK installs:
- www.arkhive.org/api/v2/arks/lamas/sites/ABC12/cxt/1 - Allows easy exposure of all instances for LD consumption
- lamas.arkhive.org/api/v2/sites/MNO12/cxt/1 - Easier for migration to stand-alone ARK, more 'private'
- www.arkhive.org/lamas/api/v2/sites/MNO12/cxt/1 - As for 2.
The following HTTP actions will be supported:
- GET - fetch resource
- POST - insert new resource with next available id, i.e. insert a new item with next item number
- PUT - insert or update resource with a specified id, i.e. insert a new item or update an existing item with a set item number
- PATCH - update part of a resource, i.e. update a single field or group
- DELETE - delete a resource
- OPTIONS - What HTTP verbs the current authenticated API user can perform on a resource
The following other endpoints will be supported:
- /filters - The global saved filters
- /filters/123 - The filter definition
- /filters/123/items - The filter result set
- /users - The users
- /users/jlayt - The user details
- /users/jlayt/filters - returns the the list of user filters, etc as per filters endpoint
- /actors - The global actors
- /actors/123 - The actor details
The JSON:API query values will be supported:
- ?filter - basic search in fields (use /filters for advanced search)
- ?sort - sorts results by fields
- ?fields - return selected fields
- ?page - pagination of results
- ?q - not standard, free-text search?
Notes:
- Updating a resource will require some kind of timestamp or last update key to prevent overwriting subsequent changes
- All security / OPTIONS / anon access will be controlled by user roles
JSO Schema Implementations:
- JSON Schema validation via PHP League (simple, complete, extendable) or Justin Rainbow (most widely used)
JSON-API Implementations:
- http://fractal.thephpleague.com/ PHP League Fractal library to serialize as JSON-API - nice, multi-format, but missing some needed features
- https://github.com/woohoolabs/yin - Very nice but PSR-7 and JSON Schema validation uses Rainbow, 5 contrib, 29 releases, last update 2 weeks
- https://github.com/tobscure/json-api - Good, clean, complete standard, agnostic, but no extras/schema/header handling. 17 contrib, 5 releases, last update 1 month, 2nd popularity rank
- https://github.com/neomerx/json-api - 7 contribs, 42 releases, last update 1 week
- https://github.com/nilportugues/php-json-api - 8 contribs, 63 releases, last update 3 weeks
- https://github.com/nilportugues/symfony-jsonapi - Symfony 2 bundle, last update 2 weeks
- https://github.com/mauro-moreno/silex-jsonapi - Silex provider for nilportugues, ast update 2 months
- https://github.com/lode/jsonapi - Simple, 2 contrib, 10 releasses, last update 3 weeks
- PHP Client: https://github.com/Art4/json-api-client
Not considered:
- https://github.com/matthiasbayer/json-api - 1 contrib, last update 1 year
- https://github.com/matthiasbayer/BayerJsonApiBundle - Symfony2 bundle,1 contrib, last update 1 year
- https://github.com/rstgroup/json-api-php - 3 contrib, last update 2 years
- https://github.com/GoIntegro/hateoas deep symfony integration, would be ideal but is driven by Doctrine ORM map and RAML
Query Parameters
The JSON:API standard does not specify how to structure filter/search query parameters, other than to define 'filter=' for this purpose. The following standard, based mainly on Google APIs, is used.
Operators (must be encoded where appropriate):
== Equals/ Exact match != Does not equal / Does not match > Greater than < Less than >= Greater than or equal to <= Less than or equal to =@ Contains substring !@ Does not contain substring =~ Contains a match for the regular expression !~ Does not match regular expression ! Not , Or ; And () Grouping [] In Literal string
For example:
&filter=foo==3,foo==5;bar=@bong;magic[this,that,other]
Calling functions, such as beginsWith() or intersects() could be added later, but advanced filter may be better served by a JSON format that can be persisted.