Developer Documentation
Help with using our API
Contents
1 Linked Data Browsing
- 1.1 URI Dereferencing
- 1.2 Resource Document Formats
- 1.3 Ruby Example
- 1.4 Alternative URLs for convenient browsing
- 1.5 Resources in external domains
2 SPARQL
- 2.1 Introduction to accessing the data with SPARQL
- 2.2 Parameter Interpolation
- 2.3 Named Queries
- 2.4 SPARQL Results Formats
- 2.5 Errors
- 2.6 JSON-P
- 2.7 Paging
- 2.8 Use of Named Graphs
3 REST JSON API
Linked Data Browsing
1.1 URI Dereferencing
Following the standard practices for Linked Data, we distinguish between a resource and documents about a resource. Identifiers for the resource follow the pattern:
http://{domain}/id/{...}
When you look them up you get redirected to the corresponding document about that thing. The document URL follows the pattern:
http://{domain}/doc/{...}
For example, in our Zones Dataset, the identifier for Macduff is
http://data.smartjourney.co.uk/id/zone/aberdeenshire/macduff
If you put this into your browser you get redirected to an HTML page about Macduff
http://data.smartjourney.co.uk/doc/zone/aberdeenshire/macduff
1.2 Resource Document Formats
You can specify what format you want that document to be in. By default you get HTML in a human-readable form, but you can also ask for the document in one of several RDF formats: RDF/XML, N-triples, Turtle or RDF/JSON.
There are two ways to specify which format you want: you can append a format extension to the URI or you can use the HTTP 'Accept' header. For both of these approaches, you can apply it either to the resource identifier, the .../id/... URI, or the document address, the .../doc/... URI.
| Format | Extension | Accept Header |
|---|---|---|
| RDF/XML | .rdf | application/rdf+xml |
| n-triples | .nt |
application/n-triples
text/plain |
| Turtle | .ttl | text/turtle |
| JSON | .json | application/json |
1.3 Ruby Example
Here's an example of dereferencing a URI using the Ruby 'RestClient' library. Similar approaches can be taken in other languages.
This assumes you already have Ruby set up on your system. Also, if you don't already have it, you'll need to install the rest-client gem:
gem install rest-client
Full Rest Client documentation is here.
require 'rest-client'
## 1 Specifying the format in an accept header - in this case RDF/XML
# If you're using the accept header, you can directly request the URI.
# This involves two requests, because doing an HTTP GET on the resource identifier gives you a
# 303 redirect to the appropriate document page. RestClient looks after that for you.
puts RestClient.get 'http://data.smartjourney.co.uk/id/zone/aberdeenshire/macduff', :accept=>'application/rdf+xml'
# Note: You can also request the document page directly
puts RestClient.get 'http://data.smartjourney.co.uk/doc/zone/aberdeenshire/macduff', :accept=>'application/rdf+xml'
## 2 Specifing the format as an extension - in this case JSON
# If using an extension, you must request the document page directly
# (as '.json' is not part of the URI)
puts RestClient.get 'http://data.smartjourney.co.uk/doc/zone/aberdeenshire/macduff.json'
1.4 Alternative URLs for convenient browsing
Alongside the definitive URI for a resource, we offer alternative additional URLs for the information about resources that reflects the way we organise the data into datasets and by type. These offer some convenient ways to navigate and access the data.
1.4.1 Datasets
Our 'Travel Zones' dataset has a URI of
http://data.smartjourney.co.uk/id/dataset/zones
but it can also be accessed at:
http://data.smartjourney.co.uk/datasets/zones
1.4.2 List resources of a type
The following URL:
http://data.smartjourney.co.uk/datasets/reports/incident
provides a list of all resources in the 'Reports' dataset which have a type of:
http://data.smartjourney.co.uk/def/Incident
1.4.3 Individual resources of a type
An individual incident can be found at (for example)
http://data.smartjourney.co.uk/datasets/reports/incident/60bc26e9-48a8-cacc-292f-7dcbad3e98be
This view is the same as you get via dereferencing its URI:
http://data.smartjourney.co.uk/id/incident/60bc26e9-48a8-cacc-292f-7dcbad3e98be
These URLs follow the pattern:
http://{domain}/datasets/{dataset short name}/{type short name}/{resource short name}[.{format}]
1.4.4 Formats
As with the basic Linked Data Browsing, the information about a resource can be retrieved in multiple formats. Add the format extension to the URL or use the HTTP Accept header as explained above.
The list of all resources of a given type in a given dataset, together with the available triples about those resources, can also be retrieved in multiple formats, using the approaches described above. For example (N-triples)
http://data.smartjourney.co.uk/datasets/reports/incident.nt
These results are paged.Use the parameters _page and _per_page to control the paging process, with a maximum page size of 100. See the SPARQL 'Paging' section below for more details.
To get dataset metadata in machine readable formats, you can use the pattern
http://{domain}/datasets/{dataset short name}.[{format}]
1.5 Resources in external domains
When minting URIs to identify resources we want to talk about, the usual Linked Data practice is to create those URIs in a domain you control, so that it is possible to respond to them in the ways described above.
However, there are times when it is useful to hold information about external URIs in a triple store - that is URIs in a domain that we don't control. Information about those URIs can be retrieved using SPARQL, but it's also useful to have a standard URL pattern to access them.
This is possible using the pattern:
http://{domain}/resources/{external identifier, with 'http://' removed}
SPARQL
2.1 Introduction to SPARQL
The most flexible way to access the data is by using SPARQL. To submit a SPARQL query from your code, issue an HTTP GET to
http://{domain}/sparql.{format}?query={URL-encoded query}
For example, to run this simple query
SELECT * WHERE {<http://data.smartjourney.co.uk/id/report/dabb28df-fa2f-4c99-9c3a-c9ff3ad4749a> ?p ?o}
and get the results as JSON, you need to GET the following URL (note the .json extension)
http://data.smartjourney.co.uk/sparql.json?query=SELECT+%2A+WHERE+%7B%3Chttp%3A%2F%2Fdata.smartjourney.co.uk%2Fid%2Freport%2Fdabb28df-fa2f-4c99-9c3a-c9ff3ad4749a%3E+%3Fp+%3Fo%7D
See the SPARQL Results Formats section below for more details of the different formats available.
Most languages have simple libraries for URL-encoding strings. This simple example will work in Ruby.
require 'rubygems'
require 'cgi'
query = 'SELECT * WHERE {<http://data.smartjourney.co.uk/id/report/dabb28df-fa2f-4c99-9c3a-c9ff3ad4749a> ?p ?o}'
encodedquery = CGI::escape(query)
puts encodedquery
2.2 Parameter Interpolation
You can parameterize your SPARQL by including %{tokens} in your queries, and providing values for the tokens on the url query string.
http://data.smartjourney.co.uk/sparql.format?query=URL-encoded-SPARQL-query?token1=value-for-token1&token2=value-for-token2
2.3 Named Queries
Named queries can be called via 'shortcut' urls. Available named queries appear on the API tab of the dataset pages.
http://data.smartjourney.co.uk/sparql/query-name.format
2.4 SPARQL Results formats
The available formats depend on the type of SPARQL query. A SPARQL query can be one of four main forms: SELECT, ASK, CONSTRUCT or DESCRIBE
| Query Type | Format | Extension | Accept Header |
|---|---|---|---|
| SELECT | xml | .xml |
application/xml
application/sparql-results+xml |
| json | .json |
application/json
application/sparql-results+json |
|
| text | .text | text/plain | |
| csv | .csv | text/csv | |
| ASK | json | .json |
application/json
application/sparql-results+json |
| xml | .xml |
application/xml
application/sparql-results+json |
|
| text | .text | text/plain | |
| CONSTRUCT | RDF/XML | .rdf | application/rdf+xml |
| N-triples | .nt |
text/plain
application/n-triples |
|
| Turtle | .ttl | text/turtle | |
| DESCRIBE | RDF/XML | .rdf | application/rdf+xml |
| N-triples | .nt |
text/plain
application/n-triples |
|
| Turtle | .ttl | text/turtle |
2.5 Errors
If you make a SPARQL request with a malformed query to any of the formats above (i.e. not via the HTML form at /sparql, or the in-page SPARQL console), then a blank response will be returned, with HTTP status 400.
Additionally, if you make a request for a CONSTRUCT or DESCRIBE query which returns over 2MB of data, the server will also respond with a 400 status.
2.6 JSON-P
If you're requesting JSON, you can additionally pass a callback parameter and the results will be wrapped in that function. This is useful for getting round cross-domain issues if you're writing JavaScript. For example:
http://data.smartjourney.co.uk/sparql.json?callback=myCallbackFunction&query=SELECT+%2A+WHERE+%7B%3Chttp%3A%2F%2Fdata.smartjourney.co.uk%2Fid%2Freport%2Fdabb28df-fa2f-4c99-9c3a-c9ff3ad4749a%3E+%3Fp+%3Fo%7D
or to make a JSONP request with jQuery, you can omit the callback parameter from the url and just set the dataType to jsonp.
queryUrl = 'http://data.smartjourney.co.uk/sparql.json?query=SELECT+%2A+WHERE+%7B%3Chttp%3A%2F%2Fdata.smartjourney.co.uk%2Fid%2Freport%2Fdabb28df-fa2f-4c99-9c3a-c9ff3ad4749a%3E+%3Fp+%3Fo%7D'
$.ajax({
dataType: 'jsonp',
url: queryUrl,
success: function(data) {
// callback code here
alert('success!');
}
});
2.7 Paging
The results of SELECT queries through PublishMyData SPARQL endpoints are paged. We take this approach to make sure that queries respond quickly and to avoid queries with very large result sets putting undue load on the server. The maximum number of results per page is 1000. The default for machine-readable formats is 1000 results per page, and for HTML format results is 20 per page. (We are still experimenting with this feature and would welcome your feedback on it.)
There are two parameters that can be added to the URLs described above to control paging. These are:
-
_per_page: defaults to 10 in the in-page console, 20 on the SPARQL page (at '/sparql'), or 1000 for data-formats. (Maximum of 1000). -
_page: defaults to 1.
For example, this query returns all resources of the Interval Type
SELECT * WHERE {?s a <http://purl.org/NET/c4dm/timeline.owl#Interval>}
To get results 51 to 100 in text format, use this URL:
http://data.smartjourney.co.uk/sparql.text?_page=2&_per_page=50&query=SELECT+%2A+WHERE+%7B%3Fs+a+%3Chttp%3A%2F%2Fpurl.org%2FNET%2Fc4dm%2Ftimeline.owl%23Interval%3E
The results of CONSTRUCT queries are currently limited to 2MB of data triples and we don't do automatic paging. If you have a CONSTRUCT query with a bigger result than that, you'll need to do your own paging using the SPARQL OFFSET and LIMIT keywords.
This sample Ruby code will loop through all pages of the results of a query and combine them into a single array
require 'rubygems'
require 'cgi'
require 'rest-client'
require 'json'
# find all resources of type Interval
query = 'SELECT * WHERE {?s a <http://purl.org/NET/c4dm/timeline.owl#Interval>}'
encodedquery = CGI::escape(query)
# results per page
per_page = 50
base_url = 'http://data.smartjourney.co.uk/sparql.json?query=' + encodedquery
# the final result is an array of hashes
# each element of the array looks like:
# {'s'=>{'value'=>'http://data.smartjourney.co.uk/id/interval/abc', 'type'=>'uri'}}
result = [] # we add the results into this array, page by page
done = false
page = 1
while (!done)
query_url = base_url + "&_page=#{page}&_per_page=#{per_page}"
part_result = JSON.parse(RestClient.get(query_url))
part_result_array = part_result['results']['bindings'] # this reflects the hash structure of the JSON returned
if (part_result_array.length > 0)
result = result + part_result_array
page += 1
else
done = true
end
end
puts 'total number of results = ' + result.length.to_s
2.8 Use of named graphs
Each dataset in PublishMyData-driven sites is contained within a separate named graph. The dataset itself has a URI, for example
http://data.smartjourney.co.uk/id/dataset/reports
The web page for the dataset lists the named graph that contains the dataset, in this case
http://data.smartjourney.co.uk/graph/reports
The graph name for the dataset is contained in the dataset metadata, using a predicate called http://publishmydata.com/def/dataset#graph and can be obtained by a query like this:
SELECT ?graph
WHERE {
<http://data.smartjourney.co.uk/id/dataset/reports> <http://publishmydata.com/def/dataset#graph> ?graph
}
REST JSON API
3.1 Overview
We provide a REST JSON API for reading and writing incident reports. The read-API is fully open, but writes require an API Key. Please get in touch to request one.
3.2 JSON Read API
A few convenience REST / JSON API routes exist for querying data, which don’t require an API key. These routes are used by JavaScript in the web application.
3.2.1 Lists of Reports
The http://smartjourney.co.uk/reports url can be used to get lists of reports. Filters can be applied to the results.
Parameters:
future (boolean, default=false)
tags (string, no default)
selected_zones_only (boolean, default=false, only applies if a user's API key is provided)
Open Reports
The simplest option, with no parameters provides you with a list of all currently open reports.
To get this as JSON, make a GET request to
http://smartjourney.co.uk/reports.json
or http://smartjourney.co.uk/reports (with an application/json accept header).
e.g. curl -v -H "Accept: application/json" http://smartjourney.co.uk/reports
This will return an array of JSON objects. For example:
[{"uri":"http://data.smartjourney.co.uk/id/report/c47fd679-11c5-91f2-b790-4d9abc93833e","description":"A96 Kintore - Aberdeen (A90) - Closure. All lanes closed in both directions for more than an hou...","created_at":"December 13, 2012 10:00","incident_begins_at":"December 13, 2012 10:00","incident_begins_in_future":false,"incident_ends_in_future":null,"latitude":"57.196545","longitude":"-2.264773","tags":["trafficscotland"],"tags_string":"trafficscotland","guid":"c47fd679-11c5-91f2-b790-4d9abc93833e","status":"Open","creator":"trafficscot1"}, {
Applying Filters
Here's an example of applying the filters to get planned reports with tags snow or rain. Again, this returns an array of JSON objects.
curl -v -H "Accept: application/json" "http://smartjourney.co.uk/reports?future=true&tags=snow,rain"
3.2.2 Details of a Single Report
You can the details of a single report as JSON by making a GET request to the url of a report (these urls match those used by the web app, as opposed to the URIs of the RDF resources).
i.e. http://smartjourney.co.uk/reports/{GUID}.json
or http://smartjourney.co.uk/reports/{GUID} (with an application/json accept header).
This will return a single JSON object. e.g.
{"uri":"http://data.smartjourney.co.uk/id/report/c47fd679-11c5-91f2-b790-4d9abc93833e","description":"A96 Kintore - Aberdeen (A90) - Closure. All lanes closed in both directions for more than an hou...","created_at":"December 13, 2012 10:00","incident_begins_at":"December 13, 2012 10:00","incident_begins_in_future":false,"incident_ends_in_future":null,"latitude":"57.196545","longitude":"-2.264773","tags":["trafficscotland"],"tags_string":"trafficscotland","guid":"c47fd679-11c5-91f2-b790-4d9abc93833e","status":"Open","creator":"trafficscot1"}
3.3 JSON Write API
All requests to the write-API must include an API key as a request header. This key must be assigned to an existing user. Contact us to request an API key.
To create a planned/future report, the key must be assigned to a user who has administration rights.
An admin user API key can close or update any report. A normal user API key can only close or update reports created by that user.
3.3.1 Report Data
The report is described as a JSON object, with this structure (and some example data).
Current report (i.e. open now)
{
“report”: {
“latitude”:57.15,
“longitude”:-2.1,
“description”:”blah”,
“tags_string”:”tag1,tag2”
}
}
Planned report (starts in the future)
{
“report”: {
“latitude”:57.15,
“longitude”:-2.1,
“description”:”blah”,
“tags_string”:”tag1,tag2”,
“incident_begins_at”:”2013-01-01 09:00",
“incident_ends_at”:”2013-02-01 15:00"
}
}
3.3.1 Create a new report
Send a POST with the JSON report details as payload to http://smartjourney.co.uk/reports
If successful, returns a status code of 201 in the header, with a JSON response giving the GUID of the newly created report
e.g. {“guid”:”d0fdb9d9-a53f-08a9-ebf4-54ccdbbcaa6b”}
Example request:
curl -v -H "Content-Type: application/json" -H "Accept: application/json" -H "api-key: blah" -X POST -d '{"report":{"latitude":57.15, "longitude":-2.1, "description": "lorry shed its load of jam", "tags_string": "lorry, traffic-jam", "incident_begins_at":"2012-01-01 12:00", "incident_ends_at":"2013-01-01 11:01" }}' http://smartjourney.co.uk/reports
3.3.2 Modifying an existing report
Send a PUT with the updated JSON report details as payload to http://smartjourney.co.uk/reports/{GUID}.
Returns status 200 header if successful. Example request:
curl -v -H "Content-Type: application/json" -H "Accept: application/json" -H "api-key: blah" -X PUT -d '{"report":{"latitude":57.15, "longitude":-2.1, "description": "updated desc", "tags_string": "lorry, traffic-jam" }}' "http://smartjourney.co.uk/reports/56159c92-e9ac-48e7-6443-23a278dfbe40
3.3.3 Closing an existing report
Send a PUT with no (or empty) payload to http://smartjourney.co.uk/reports/{GUID}/close
Returns status 200 if successful. Example request:
curl -v -H "Content-Type: application/json" -H "Accept: application/json" -H "api-key: blah" -X PUT http://smartjourney.co.uk/reports/5bc7ade1-db6a-2f3d-baad-f2dd4589c994x/close
3.3.4 Error Codes
400 Bad request.
401 Unauthorized: If the API key doesn’t identify a user in the system, or the identified user does not have rights to perform the action.
404 Not Found.
- This page is available as
- HTML