# Swagger API Specification for Drafter
swagger: '2.0'
info:
title: 'Publish My Data: Drafter API'
description: |
This document serves as a specification for Drafter's
API. Drafter is a backend service used by Publish My Data to
support PMD's publication workflow. It describes how clients
including the PMD application, control data publishing through the
use of Draftsets.
The API described in these documents is for manipulating data at
graph-level, and guiding it through the drafting process. It will
accept any valid RDF graph contents.
For display and edit purposes, PublishMyData makes additional
assumptions about the contents of graphs used for datasets and
vocabularies.
Future additions to these APIs will provide mechanisms for
creating and validating this data conforms to PMD's conventions.
## Draftset API Overview
Draftsets are essentially private working copies, or branches of
work, that contain changes to RDF data. When a user creates a
draftset they effectively create a 'virtual copy' of the live
sites data in which they can safely make, review and query changes
before publishing them to the live site.
When a user creates a draftset they are given a private endpoint
which they can use to insert, remove or query RDF data through
standard operations.
After creating a draftset by `POST`ing to `/draftsets` the client
is redirected to a REST resource representing the endpoint.
Once the client knows the draftsets identity it can access a
number of API endpoints to perform specific tasks or actions.
These endpoints include:
- `/query` which is a [SPARQL 1.1](http://www.w3.org/TR/sparql11-protocol/)
compliant query endpoint bespoke to the current draftset. By default the
draftset only includes changes which have been made in the
draftset, however you can set the optional `union-with-live`
query parameter to `true` to also include data from the live
sites endpoint. If `union-with-live` is true, graphs changed
in the draftset shadow live graphs of the same name.
- `/data` which can be used to `POST` (append), `DELETE` or
`GET` quads from the draftset.
- `/submit-to` to relinquish ownership of the drafset and either
assign ownership to another user, or make it available to
users in a given role. The user which takes ownership of the
draftset may depending on their role then choose to make
further ammendments, `/publish` or submit the draftset to a
new owner.
- `/publish` which can be used by clients with the `publisher`
role to publish a reviewed draftset to the live site.
- `/claim` which a user must call on Draftset's submitted to
them before they can perform any actions upon them. Claiming
a Draftset puts it under the exclusive control of the claiming
user. A list of all Draftsets that the current user can lay
claim to is available under the `/claimable` route. Users who
have submitted a Draftset may withdraw it by claiming it back
providing it has not yet been claimed by another user.
In addition to these routes there are routes available to list all
Draftset's in the system and access metadata about an individual
Draftset.
## Long Running Jobs
Some API actions such as publishing can result in long running
batch operations. In these cases an AsyncJob object is returned.
AsyncJob's contain a path to a `finished-job` route that can be
polled for notification of the jobs completion.
Polling this route will result in a HTTP 404 status code until the
job is finished, at which point it will return a HTTP 200. Once a
200 is received the application should inspect the returned JSON
object to see whether the job completed successfully or resulted
in an error.
The server does not store the set of finished-jobs in long term
persistent storage, so the set of finished-jobs may be lost in
certain circumstances such as after the service has been
restarted. In order to prevent applications waiting forever for a
lost job to finish, applications should remember and compare
restart-id's after every poll request. The server assigns itself
a new restart-id whenever it is restarted, so if the restart-id
changes between poll cycles applications can know that the job
they are awaiting has been lost.
## Authentication & Security
This API is designed to be run over HTTPS/TLS and will use HTTP
[Basic Auth](https://en.wikipedia.org/wiki/Basic_access_authentication)
(RFC 2617) for authentication.
For example a user `admin@opendatacommunities.org` could attempt
to authenticate every request to the service described here by
prefixing the Base64 encoded value of
`admin@opendatacommunities.org:yourpmdapikey` with the string
`Basic` followed by a space. For example:
````
Authorization: Basic YWRtaW5Ab3BlbmRhdGFjb21tdW5pdGllcy5vcmc6eW91cnBtZGFwaWtleQ==
````
## Roles
Users in Drafter and PMD are assigned to a role which authorises
them to perform various actions associated with the role and all
of the roles ranked beneath it. The roles are currently:
| rank | role | Description |
|------|-----------------|--------------------------------------------------------------------------------------|
| 1 | editor | Can acess the admin panel and create and edit draftsets. |
| 2 | publisher | Can do everything an editor can, but also publish to the live site. |
| 3 | manager | Can do everything a publisher can, but also manage user accounts (not via this API) |
Roles are also what users use to exchange Draftsets. Users submit
a Draftset to a role, which puts it in that roles pool of
claimable Draftsets. Draftsets are then only claimable out of the
role's pool by users with a role of an equal or higher rank. In
addition to this the user who submitted the draftset to the role
can also withdraw it from submission by claiming it back -
regarldess of their role's rank.
Draftsets *must* be claimed before they can be reviewed, published
or edited.
version: 1.0.0
securityDefinitions:
basic-auth:
type: basic
description: HTTP Basic Authentication
jws-auth:
type: apiKey
name: Authorization
in: header
basePath: /v1
tags:
- name: Draftsets
description: The publication lifecycle
- name: Updating Data
description: Editing Draftset contents
- name: Metadata
description: Draftset metadata
- name: Querying
description: Accessing Data in Draftsets
- name: Users
description: Querying users
- name: SPARQL Endpoints
description: SPARQL query endpoints
- name: Jobs
description: Async jobs
produces:
- application/json
consumes:
- application/json
paths:
/draftsets:
post:
summary: Create a new Draftset
tags:
- Draftsets
description: |
Creates a new draftset in the database.
Optionally accepts query string parameters for a name and a description.
security:
- jws-auth: []
parameters:
- $ref: '#/parameters/display-name'
- $ref: '#/parameters/draftset-description'
responses:
'303':
description: Upon the creation of a new draftset the caller is redirected to its representation.
get:
summary: List available Draftsets
description: |
Lists draftsets visible to the user. The include parameter can
be used to filter the result list to just those owned by the
current user, or those not owned which can be claimed by the
current user. By default all owned and claimable draftsets are
returned.
security:
- jws-auth: []
parameters:
- $ref: '#/parameters/include'
tags:
- Draftsets
responses:
'200':
description: An array of Draftsets
schema:
type: array
items:
$ref: '#/definitions/Draftset'
/draftset/{id}:
get:
summary: Get information about a Draftset
description: |
Returns metadata about the draftset.
NOTE
security:
- jws-auth: []
parameters:
- $ref: '#/parameters/id'
tags:
- Metadata
responses:
'200':
description: The Draftset.
schema:
$ref: '#/definitions/Draftset'
put:
summary: Set metadata on Draftset
description: |
Sets metadata properties on the draftset, allowing updates to
the draftsets title and description.
security:
- jws-auth: []
parameters:
- $ref: '#/parameters/id'
- $ref: '#/parameters/display-name'
- $ref: '#/parameters/draftset-description'
tags:
- Metadata
responses:
'200':
description: The Draftset.
schema:
$ref: '#/definitions/Draftset'
delete:
summary: Delete the Draftset and its data
description: Deletes the draftset and its contents.
security:
- jws-auth: []
parameters:
- $ref: '#/parameters/id'
#- $ref: '#/parameters/messagenonote'
tags:
- Draftsets
responses:
'202':
description: |
The request to delete the Draftset was accepted.
Applications should poll for the completion of the
AsyncJob.
schema:
$ref: '#/definitions/AsyncJob'
/draftset/{id}/graph:
put:
summary: Copy a graph from live into this Draftset
description: |
Copies the contents of the specified live graph into this
Draftset.
If the specified graph does not exist in live then a 422 error
will be returned.
security:
- jws-auth: []
parameters:
- $ref: '#/parameters/id'
- $ref: '#/parameters/livegraph'
tags:
- Updating Data
responses:
'202':
description: The graph was deleted successfully
schema:
$ref: '#/definitions/AsyncJob'
delete:
summary: Delete the contents of a graph in this Draftset
description: |
Schedules the deletion of the specified graph from live and
deletes its contents from the Draftset. At publication time
the specified graph will be removed from the live site.
If you wish to undo changes you have made in a draftset you
should not use this route, and should use
`DELETE /draftset/{id}/changes` instead.
If the silent is true the request will always complete successfully,
otherwise if the specified graph does not exist in live then a 422 error
will be returned.
security:
- jws-auth: []
parameters:
- $ref: '#/parameters/id'
- $ref: '#/parameters/reqgraph'
- $ref: '#/parameters/silent'
tags:
- Updating Data
responses:
'200':
schema:
$ref: '#/definitions/Draftset'
description: The graph was deleted successfully
'422':
description: The graph does not exist in live and the silent is false
/draftset/{id}/changes:
delete:
summary: Remove all the changes to a named graph from the Draftset
description: |
Removes all of the changes to the specified graph from the
Draftset.
This route is different to `DELETE /draftset/{:id}/graph` in
that it is about undoing changes you have made and not about
scheduling deletions against live.
This route is equivalent to explicitly deleting all the
triples from a named graph within the draftset with `DELETE
/draftset/{:id}/data`, the benefit to using this route is that
you don\'t need to list all the triples contained within the
graph.
security:
- jws-auth: []
parameters:
- $ref: '#/parameters/id'
- $ref: '#/parameters/reqgraph'
tags:
- Updating Data
responses:
'200':
description: |
The request to remove the graph and its changes from the
Draftset was accepted. Applications should poll for the
completion of the AsyncJob.
schema:
$ref: '#/definitions/Draftset'
/draftset/{id}/data:
put:
summary: Append the supplied RDF data to this Draftset
description: |
Appends the supplied data to the Draftset identified by this
resource.
If the RDF data is supplied in a quad serialisation then the
graph query parameter can be ommited. If quads are uploaded
and a graph parameter is specified the graph parameter will
take precedence, causing all quads to be loaded into the same
graph.
If a graph parameter is supplied then
the RDF data can be supplied in a triple serialisation.
security:
- jws-auth: []
parameters:
- $ref: "#/parameters/id"
- $ref: '#/parameters/rdfdata'
- $ref: '#/parameters/graph'
#- $ref: '#/parameters/messagenonote'
consumes:
- application/n-quads
- application/trig
- application/trix
- application/n-triples
- application/rdf+xml
- text/turtle
produces:
- application/json
tags:
- Updating Data
responses:
'202':
description: |
The request to append data to the Draftset was accepted.
Applications should poll for the completion of the
AsyncJob.
schema:
$ref: '#/definitions/AsyncJob'
delete:
summary: Remove the supplied RDF data from this Draftset
description: |
Removes the supplied data from the Draftset identified by this
resource.
If the RDF data is supplied in a quad serialisation then the graph query parameter can be ommited, and the supplied quads will be removed from this Draftset.
If quads are uploaded and a graph parameter is specified all quads will be treated as if they are triples in the specified graph, and will be removed from it.
If a graph parameter is supplied then
the RDF data can be supplied in a triple serialisation. The supplied triples will be removed from the Draftset.
security:
- jws-auth: []
parameters:
- $ref: "#/parameters/id"
- $ref: '#/parameters/rdfdata'
- $ref: '#/parameters/graph'
#- $ref: '#/parameters/messagenonote'
consumes:
- application/n-quads
- application/trig
- application/trix
- application/n-triples
- application/rdf+xml
- text/turtle
produces:
- application/json
tags:
- Updating Data
responses:
'202':
description: |
The request to append data to the Draftset was accepted.
Applications should poll for the completion of the
AsyncJob.
schema:
$ref: '#/definitions/AsyncJob'
get:
parameters:
- $ref: "#/parameters/id"
- $ref: '#/parameters/graph'
- $ref: '#/parameters/union-with-live'
- $ref: '#/parameters/timeout'
summary: Access the quads inside this Draftset
description: |
Request the contents of this draftset in any supported RDF
serialisation.
If the chosen serialisation is a triple based one then the
graph query string parameter must be provided. If a quad
based serialisation is chosen then the graph parameter must be
omitted or a 415 error will be returned.
security:
- jws-auth: []
produces:
- application/n-quads
- application/trig
- apllication/trix
- application/n-triples
- application/rdf+xml
- text/turtle
tags:
- Querying
responses:
'200':
description: The Data in the draftset.
schema:
type: file
/draftset/{id}/submit-to:
post:
summary: Submit a Draftset to a user or role
description: |
Submits this draftset for review and potential publication.
Draftsets are submitted directly to a user, or into a pool for
users of a given role.
Users with a role greater than or equal to the role the
draftset was submitted to can then lay claim to it.
security:
- jws-auth: []
parameters:
- $ref: '#/parameters/id'
- $ref: '#/parameters/role'
- $ref: '#/parameters/submit-user'
# - $ref: '#/parameters/message'
# - $ref: '#/parameters/note'
tags:
- Draftsets
responses:
'200':
description: The Draftset was successfully submitted.
schema:
$ref: '#/definitions/Draftset'
'422':
description: The submit request could not be processed.
/draftset/{id}/claim:
put:
summary: Claim this draftset as your own
description: |
Sets the Draftset's `current-owner` to be the same as the user
performing this operation. This is necessary to prevent
other's from making changes to the data contained within the
Draftset.
Each role in the system has a pool of 0 or more claimable
draftsets associated with it. Claimable draftsets are
draftsets in a pool where the rank of the pools role is less
than or equal to the user's role's rank.
security:
- jws-auth: []
parameters:
- $ref: '#/parameters/id'
#- $ref: '#/parameters/messagenonote'
tags:
- Draftsets
responses:
'200':
description: You were successfully set to be the `current-owner` of this draftset.
schema:
$ref: '#/definitions/Draftset'
/draftset/{id}/publish:
post:
summary: Publish the specified Draftset
description: |
Requests that this Draftset is published asynchronously to the live site. If a job is successfully scheduled then an AsyncJob object will be returned.
security:
- jws-auth: []
parameters:
- $ref: '#/parameters/id'
#- $ref: '#/parameters/messagenonote'
tags:
- Draftsets
responses:
'202':
description: The Draftset is successfully scheduled for publication.
schema:
$ref: '#/definitions/AsyncJob'
/draftset/{id}/query:
get:
summary: Query this Draftset with SPARQL
description: |
Query this Draftset via the SPARQL query language and protocol.
Please consult the SPARQL query protocol specification http://www.w3.org/TR/sparql11-protocol/ for a description of this endpoint.
security:
- jws-auth: []
consumes:
- application/sparql-query
produces:
- application/n-triples
- application/rdf+xml
- text/turtle
- application/sparql-results+xml
- application/sparql-results+json
- text/csv
parameters:
- $ref: '#/parameters/id'
- $ref: '#/parameters/query'
- $ref: '#/parameters/union-with-live'
- $ref: '#/parameters/timeout'
tags:
- Querying
responses:
'200':
description: The query results returned according to the SPARQL specification.
schema:
type: file
post:
summary: Query this Draftset with SPARQL
description: |
Query this Draftset via the SPARQL query language and protocol.
Please consult the SPARQL query protocol specification http://www.w3.org/TR/sparql11-protocol/ for a description of this endpoint.
security:
- jws-auth: []
consumes:
- application/x-www-form-urlencoded
produces:
- application/n-triples
- application/rdf+xml
- text/turtle
- application/sparql-results+xml
- application/sparql-results+json
- text/csv
parameters:
- $ref: '#/parameters/id'
- $ref: '#/parameters/post_query'
- $ref: '#/parameters/union-with-live'
- $ref: '#/parameters/timeout'
tags:
- Querying
responses:
'200':
description: The query results returned according to the SPARQL specification.
schema:
type: file
/sparql/live:
get:
summary: Queries the published data with SPARQL
description: |
Query the live data via the SPARQL query langauge and protocol.
Please consult the SPARQL query protocol specification http://www.w3.org/TR/sparql11-protocol/ for a description of this endpoint.
consumes:
- application/x-www-form-urlencoded
produces:
- application/n-triples
- application/rdf+xml
- text/turtle
- application/sparql-results+xml
- application/sparql-results+json
- text/csv
parameters:
- $ref: '#/parameters/query'
- $ref: '#/parameters/timeout'
tags:
- SPARQL Endpoints
responses:
'200':
description: The query results returned according to the SPARQL specificiation.
schema:
type: file
post:
summary: Queries the published data with SPARQL
description: |
Query the live data via the SPARQL query langauge and protocol.
Please consult the SPARQL query protocol specification http://www.w3.org/TR/sparql11-protocol/ for a description of this endpoint.
consumes:
- application/x-www-form-urlencoded
produces:
- application/n-triples
- application/rdf+xml
- text/turtle
- application/sparql-results+xml
- application/sparql-results+json
- text/csv
parameters:
- $ref: '#/parameters/post_query'
tags:
- SPARQL Endpoints
responses:
'200':
description: The query results returned according to the SPARQL specificiation.
schema:
type: file
/users:
get:
summary: Gets all users
description: |
Returns a JSON document containing an array of summary
documents, one for each known user.
security:
- jws-auth: []
tags:
- Users
responses:
'200':
description: Users found.
schema:
type: array
items:
$ref: '#/definitions/User'
/status/finished-jobs/{jobid}:
get:
summary: Poll to see if asynchronous job has finished
description: |
Poll this route until the AsyncJob is finished. Whilst the
job is ongoing this route will return a 404 until it is
finished. When the job finishes, through either successful
completion or an error this route will return a 200 with a
JSON object indicating the success or failure of the task.
The server does not store the set of finished-jobs in
persistent storage, so in exceptional circumstances the set of
finished-jobs may be lost such as after the service has been
restarted.
In order to prevent applications waiting forever for a lost
job to finish, applications should remember and compare
restart-id's after every poll request.
The server assigns itself a new unique restart-id when it is
started, so if an application detects a change in the
restart-id between poll cycles they know that the job they are
awaiting has been lost, and that they should propogate an
appropriate error.
parameters:
- $ref: "#/parameters/jobid"
tags:
- Jobs
responses:
'404':
description: The job is not yet finished.
'200':
description: The job has finished. To determine whether the job finished successfully or through a failure you will need to inspect the returned JSON object.
schema:
$ref: '#/definitions/FinishedJob'
/status/writes-locked:
get:
summary: Poll to see if the system is accepting writes
description: |
During a publish operation operations that create writes such
as creating a draftset and updating it are temporarily
disabled and will cause a 503.
You can poll this route to see if the application is available
for writes.
This route exists to give users & user interfaces information
as to whether the system is available for writes or not. It
is not necessary (or desirable) for applications to check this
route before performing an operation. Any operation that
creates writes may 503.
Returns a boolean true if the system is locked for writes and
false if it isn't.'
tags:
- Jobs
responses:
'200':
description: The request returned the status of the writes lock successfully.
schema:
$ref: '#/definitions/WritesLocked'
parameters:
id:
name: id
description: ID of the Draftset
in: path
required: true
type: string
display-name:
name: display-name
description: The name of the Draftset
in: query
required: false
type: string
draftset-description:
name: description
description: A description of the Draftset
in: query
required: false
type: string
role:
name: role
description: The role to submit the draftset to
in: query
required: false
type: string
enum:
- editor
- publisher
- manager
submit-user:
name: user
description: The username of the user to submit the draftset to.
in: query
required: false
type: string
include:
name: include
in: query
description: which visible draftsets to include in the results
required: false
type: string
enum:
- owned
- claimable
- all
default: all
timeout:
name: timeout
in: query
description: Request a desired timeout in seconds after which the query/operation will be aborted. You may be granted less than you ask for.
required: false
type: integer
# message:
# name: message
# description: |
# A log message to be associated with the performed action. The
# message parameter differs from the note parameter in that it is
# intended for fine grained log and audit trails.
# in: query
# required: false
# type: string
# messagenonote:
# name: message
# description: |
# A log message to be associated with the performed action.
# in: query
# required: false
# type: string
# note:
# name: note
# description: |
# A note to a reviewer / submitter. This parameter differs from
# the message parameter in that notes are meant to enable
# communication between reviewers and submitters.
# in: query
# required: false
# type: string
jobid:
name: jobid
description: ID of the Draftset
in: path
required: true
type: string
rdfdata:
name: data
description: |
RDF data in a supported serialization format. If the format is a triple
based serialisation then the graph parameter must be specified.
in: body
required: true
schema:
type: string
graph:
name: graph
description: |
The URI of the named graph that the operation should be
performed on. This is only required if the supplied RDF data is
in triples format. If quads are provided then all the quads are
assumed to be in this graph.
in: query
required: false
type: string
reqgraph:
name: graph
description: |
The URI of the named graph that the operation should be
performed on.
in: query
required: true
type: string
livegraph:
name: graph
description: |
The URI of the live graph that the operation should be
performed on.
in: query
required: true
type: string
query:
name: query
description: URI Encoded SPARQL Query
in: query
required: true
type: string
post_query:
name: query
description: URI Encoded SPARQL Query in the HTTP body
in: formData
required: true
type: string
union-with-live:
name: union-with-live
description: Whether or not the query should run against the union of this draftset with the live site.
in: query
required: false
type: boolean
default: false
silent:
name: silent
in: query
required: false
type: boolean
allowEmptyValue: true
default: false
definitions:
Graph:
type: object
description: A graph object
properties:
status:
type: string
enum:
- created
- updated
- deleted
User:
type: object
required: [username, role]
properties:
username:
type: string
description: Username of the user
role:
type: string
description: role of the user
example:
username: user@example.com
role: publisher
Draftset:
type: object
required: [id, changes, updated-at, created-at, created-by]
properties:
id:
type: string
format: uuid
description: 'Unique identifier representing this draftset'
created-by:
type: string
description: The user who created this Draftset
changes:
type: object
additionalProperties:
$ref: '#/definitions/Graph'
display-name:
type: string
description: Display name of the Draftset
current-owner:
type: string
description: The current owner of this Draftset
submitted-by:
type: string
description: The owner who submitted this Draftset for review
claim-role:
type: string
enum:
- editor
- publisher
- manager
description: The required role for users who can claim this Draftset
claim-user:
type: string
description: The user who can claim this Draftset
description:
type: string
description: A description of the Draftset
updated-at:
type: string
format: date-time
description: IS0 8601 DateTime representing the time the draftsets metadata was last updated
created-at:
type: string
format: date-time
description: IS0 8601 DateTime representing the time the draftset was created
# note:
# type: string
# description: |
# A note that can be used by users to communicate the status
# of a submission, why a draftset was returned etc.
example:
id: de305d54-75b4-431b-adb2-eb6b9e546014
changes:
'http://opendatacommunities.org/graph/homelessness/households-accommodated/temporary-housing-types': {'status': 'updated'}
'http://opendatacommunities.org/data/labour-force/employment-rate/employment-rate-by-age': {'status': 'deleted'}
display-name: New Temporary Housing Figures
description: Quarterly updates for Q4 2015
updated-at: 2016-01-04T13:35:21+00:00
created-at: 2016-01-01T13:35:21+00:00
current-owner: admin@opendatacommunities.org
submitted-by: editor@opendatacommunities.org
Error:
type: object
required: [type, error-type, exception]
properties:
type:
type: string
enum:
- error
error-type:
type: string
description: String representing the class of error that occurred
exception:
type: object
required: [message]
properties:
message:
type: string
description: An error message relating to the specific exception
WritesLocked:
type: boolean
description: |
True when the system is unavailable for write operations, and false
when it is accepting them.
AsyncJob:
type: object
description: A successfully submitted Asynchronous Job.
required: [type, finished-job, restart-id]
properties:
type:
type: string
enum:
- ok
- error
finished-job:
type: string
restart-id:
type: string
example:
type: ok
restart-id: b1b26596-2dca-4e52-883c-7fdcb8b4be97
finished-job: /v1/status/finished-jobs/2c4111e5-a299-4526-8327-bad5996de400
FinishedJob:
type: object
description: An Asynchronous Job that completed without error.
required: [type, restart-id]
properties:
type:
type: string
enum:
- ok
- error
- not-found
restart-id:
type: string
error-class:
type: string
message:
type: string
details:
type: object
example:
type: ok
restart-id: b1b26596-2dca-4e52-883c-7fdcb8b4be97