Post on 14-Jun-2015
description
transcript
Web APIsAlexandre Bertails, Pellucid Analytics
@bertails
1 / 46
Web APIsWho are the users of my API?
What do they do with it?
How will they interact with it?
2 / 46
Web APIsWho are the users of my API?
What do they do with it?
How will they interact with it?
REST
hypermedia
HATEOAS
3 / 46
HTTP, back to the basicsresources
representations
semantics
4 / 46
HTTP interactions$ HEAD https://data.example.com/company/Content-Type: application/json
a media type specification sets out
formats
processing model
hypermedia controls
for its representation
5 / 46
media typeContent-Type and Media Type as defined in HTTPBIS
HTTP uses Internet Media Types [RFC2046] in the Content-Type(Section 3.1.1.5) [...] header fields in order to provide open andextensible data typing [...]. Media types define both a data format andvarious processing models.
6 / 46
IANA registry for media typesIANA registry for Media Types
Name Template Referencejson application/json [RFC7158]
7 / 46
JSONThe JavaScript Object Notation (JSON) Data Interchange Format [RFC7159]
JSON can represent four primitive types (strings, numbers, booleans,and null) and two structured types (objects and arrays).
8 / 46
JSONThe JavaScript Object Notation (JSON) Data Interchange Format [RFC7159]
JSON can represent four primitive types (strings, numbers, booleans,and null) and two structured types (objects and arrays).
No processing model defined in JSON! (neither in JSON-LD, HAL,etc.)
9 / 46
extending media type semantics
what would the RESTafarian do?
probably use a vendor specific media type
$ HEAD https://data.example.com/company/Content-Type: application/vnd.example.company+json
10 / 46
Link header
rel=profile Link header
The 'profile' link relation type [...] allows resource representations toindicate that they are following one or more profiles. A profile isdefined not to alter the semantics of the resource representationitself, but to allow clients to learn about additional semantics [...] inaddition to those defined by the media type [...].
$ HEAD https://data.example.com/company/Content-Type: application/jsonLink: <https://data.example.com/ontology#Company>; rel="profile"
11 / 46
HATEOAS?Hypermedia can be the engine of a single API.
Hypermedia cannot be the engine of cross-API interactions.
Ruben Verborgh, Hypermedia Cannot be the Engine
12 / 46
focusing on dataHATEOAS is like a hypermedia state machine
data modeling is a special case for application state
media type encodes kind/type
but few missing interactions eg. CRUD
13 / 46
data patterns in JSONencodings
links
types
disambiguating schemas
Let's make JSON a hypermedia format :-)
14 / 46
a 1st versionan Industry entity
$ GET https://data.example.com/industry/q6po09Content-Type: application/json
{ "id": "q6po09", "name": "Fruits"}
a Company entity
$ GET https://data.example.com/company/c34dapContent-Type: application/json
{ "id": "c34dap", "name": "Apple", "ticker": "AAPL", "industry": "q6po09"}
documentation probably available at something likehttps://data.example.com/api/documentation 15 / 46
things, not String-san Industry entity
$ GET https://data.example.com/industry/q6po09Content-Type: application/json
{ "@id": "https://data.example.com/industry/q6po09", "name": "Fruits"}
a Company entity
$ GET https://data.example.com/company/c34dapContent-Type: application/json
{ "@id": "https://data.example.com/company/c34dap", "name": "Apple", "ticker": "AAPL", "industry": { "@id": "https://data.example.com/industry/q6po09" }}
16 / 46
this is its own @idan Industry entity
$ GET https://data.example.com/industry/q6po09Content-Type: application/json
{ "name": "Fruits"}
a Company entity
$ GET https://data.example.com/company/c34dapContent-Type: application/json
{ "name": "Apple", "ticker": "AAPL", "industry": { "@id": "https://data.example.com/industry/q6po09" }}
17 / 46
what are we dealing with?an Industry entity
$ GET https://data.example.com/industry/q6po09Content-Type: application/json
{ "type": "Industry", "name": "Fruits"}
a Company entity
$ GET https://data.example.com/company/c34dapContent-Type: application/json
{ "type": "Company", "name": "Apple", "ticker": "AAPL", "industry": { "@id": "https://data.example.com/industry/q6po09" }}
18 / 46
@type + URLan Industry entity
$ GET https://data.example.com/industry/q6po09Content-Type: application/json
{ "@type": { "@id": "https://data.example.com/ontology#Industry" }, "name": "Fruits"}
a Company entity
$ GET https://data.example.com/company/c34dapContent-Type: application/json
{ "@type": { "@id": "https://data.example.com/ontology#Company" }, "name": "Apple", "ticker": "AAPL", "industry": { "@id": "https://data.example.com/industry/q6po09" }}
19 / 46
disambiguating attributes [1/3]How to distinguish an industry's name from a company's name?
an Industry entity
$ GET https://data.example.com/industry/q6po09Content-Type: application/json
{ "@type": { "@id": "https://data.example.com/ontology#Industry" }, "name": "Fruits"}
a Company entity
$ GET https://data.example.com/company/c34dapContent-Type: application/json
{ "@type": { "@id": "https://data.example.com/ontology#Company" }, "name": "Apple", "ticker": "AAPL", "industry": { "@id": "https://data.example.com/industry/q6po09" }}
20 / 46
disambiguating attributes [2/3]How to distinguish an industry's name from a company's name?
an Industry entity
$ GET https://data.example.com/industry/q6po09Content-Type: application/json
{ "@type": { "@id": "https://data.example.com/ontology#Industry" }, "https://data.example.com/ontology#industryName": "Fruits"}
a Company entity
$ GET https://data.example.com/company/c34dapContent-Type: application/json
{ "@type": { "@id": "https://data.example.com/ontology#Company" }, "https://data.example.com/ontology#companyName": "Apple", "ticker": "AAPL", "industry": { "@id": "https://data.example.com/industry/q6po09" }}
21 / 46
disambiguating attributes [3/3]How to distinguish an industry's name from a company's name?
a Company entity
$ GET https://data.example.com/company/c34dapContent-Type: application/json
{ "@context": { "name": { "@id": "https://data.example.com/ontology#companyName" } }, "@type": { "@id": "https://data.example.com/ontology#Company" }, "name": "Apple", "ticker": "AAPL", "industry": { "@id": "https://data.example.com/industry/q6po09" }}
22 / 46
contextualized data: typed valuesa Company entity
$ GET https://data.example.com/company/c34dapContent-Type: application/json
{ "@context": { "name": { "@id": "https://data.example.com/ontology#companyName" }, "ticker": { "@id": "https://data.example.com/ontology#ticker" }, "industry": { "@id": "https://data.example.com/ontology#industry" } }, "@type": { "@id": "https://data.example.com/ontology#Company" }, "name": "Apple", "ticker": "AAPL", "industry": { "@id": "https://data.example.com/industry/q6po09" }}
23 / 46
contextualized data: default vocabularya Company entity
$ GET https://data.example.com/company/c34dapContent-Type: application/json
{ "@context": { "@vocab": "https://data.example.com/ontology#", "name": "companyName", "ticker": { "@type": "Ticker" }, "industry": { "@type": "@id" } }, "@type": "Company", "name": "Apple", "ticker": "AAPL", "industry": "https://data.example.com/industry/q6po09"}
24 / 46
JSON-LDa Company entity
$ GET https://data.example.com/company/c34dapContent-Type: application/ld+json
{ "@context": { "@vocab": "https://data.example.com/ontology#", "name": "companyName", "ticker": { "@type": "Ticker" }, "industry": { "@type": "@id" } }, "@type": "Company", "name": "Apple", "ticker": "AAPL", "industry": "https://data.example.com/industry/q6po09"}
25 / 46
not just yet another media typeis a standard
playground
in use
Google, BBC, Microsoft, Yandex, etc.
26 / 46
Contextualized data: external contextexternal context
$ GET https://data.example.com/general-context.jsonldContent-Type: application/ld+json
{ "@context": { "@vocab": "https://data.example.com/ontology#", "name": "companyName", "ticker": { "@type": "Ticker" }, "industry": { "@type": "@id" } }}
a Company entity
$ GET https://data.example.com/company/c34dapContent-Type: application/jsonLink: <https://data.example.com/context.jsonld>; rel="http://www.w3.org/ns/json-ld#context"
{ "@type": "Company", "name": "Apple", "ticker": "AAPL", "industry": "https://data.example.com/industry/q6po09"} 27 / 46
linking vs embeddingan Industry entity
$ GET https://data.example.com/industry/q6po09Content-Type: application/ld+json
{ "@context": { ... }, "@type": "Industry", "name": "Fruits"}
a Company entity
$ GET https://data.example.com/company/c34dapContent-Type: application/ld+json
{ "@context": { ... }, "@type": "Company", "name": "Apple", "ticker": "AAPL", "industry": "https://data.example.com/industry/q6po09"}
28 / 46
linking vs embeddinga Company entity with its Industry entity
$ GET https://data.example.com/company/c34dapContent-Type: application/ld+json
{ "@context": { ... }, "@type": "Company", "name": "Apple", "ticker": "AAPL", "industry": { "@type": "Industry", "name": "Fruits" }}
29 / 46
deep linkinga Company entity with its Industry entity
$ GET https://data.example.com/company/c34dapContent-Type: application/ld+json
{ "@context": { ... }, "@type": "Company", "name": "Apple", "ticker": "AAPL", "industry": { "@id": "#q6po09", "@type": "Industry", "name": "Fruits" }}
Now I could use <https://data.example.com/company/c34dap#q6po09> to speakabout the Industry referenced from the document defining it.
30 / 46
inlininga Company entity inlining the linked Industry entity
$ GET https://data.example.com/company/c34dapContent-Type: application/ld+json
{ "@context": { ... }, "@type": "Company", "name": "Apple", "ticker": "AAPL", "industry": { "@id": "https://data.example.com/industry/q6po09", "@type": "Industry", "name": "Fruits" }}
remarks
all (or part of) <https://data.example.com/industry/q6po09>'s state isinlinedthe Industry's identity+state is not under this Company's control
could even live on a different domain!applications could decide to follow links to get authoritative state 31 / 46
Summary so farstarted with
$ GET https://data.example.com/company/c34dapContent-Type: application/json
{ "id": "c34dap", "name": "Apple", "ticker": "AAPL", "industry": "q6po09"}
32 / 46
Summary so farstarted with
$ GET https://data.example.com/company/c34dapContent-Type: application/json
{ "id": "c34dap", "name": "Apple", "ticker": "AAPL", "industry": "q6po09"}
ended up with something like
$ GET https://data.example.com/company/c34dapContent-Type: application/ld+json
{ "@context": { ... }, "@type": "Company", "name": "Apple", "ticker": "AAPL", "industry": "https://data.example.com/industry/q6po09"}
33 / 46
Immediate benefitsentities are referenced, embedded and linked together
we get for free provenance and data authority
attributes are disambiguated and can be interrogated
values are typed and can natively be links
vocabularies can be shared, reused and even checked
34 / 46
introducing LDPLinked Data Platform
intersection of REST and RDF
being specced at W3C for the past 3 years
state-of-the-art of REST APIs
35 / 46
Container modelthe usual
$ GET https://data.example.com/company/Content-Type: application/json
{ "contains": [ "https://data.example.com/company/c34dap", ... ]}
becomes (introducing the LDP model)
$ GET https://data.example.com/company/Content-Type: application/ld+jsonLink: <http://www.w3.org/ns/ldp#BasicContainer>; rel="type"
{ "@context": { "ldp": "http://www.w3.org/ns/ldp#", "ldp:contains": { "@container": "@list", "@type": "@id" } }, "@type": [ "Companies", "ldp:BasicContainer" ], "ldp:contains": [ "https://data.example.com/company/c34dap", ... ]} 36 / 46
Container model + inliningContainer's state + inlined members
$ GET https://data.example.com/company/Content-Type: application/ld+jsonLink: <http://www.w3.org/ns/ldp#BasicContainer>; rel="type"
{ "@context": { ... }, "@type": [ "Companies", "ldp:BasicContainer" ], "ldp:contains": [ { "@id": "https://data.example.com/company/c34dap", "@type": "Company", "ticker": "AAPL", "name": "Apple", "industry": { "@id": "https://data.example.com/industry/q6po09", "@type": "Industry", "name": "Fruits" } }, ... ]}
37 / 46
enabling LDP interaction modelrel=type Link header
The "type" link relation can be used to indicate that the contextresource is an instance of the resource identified by the targetInternationalized Resource Identifier (IRI).
in LDP
The presence of this header asserts that the server complies with theLDP specification's constraints on HTTP interactions with LDPRs, thatis it asserts that the resource has Etags, has an RDF representation,and so on, which is not true of all Web resources served as RDF mediatypes.
$ HEAD https://data.example.com/company/Content-Type: application/ld+jsonLink: <http://www.w3.org/ns/ldp#BasicContainer>; rel="type"
38 / 46
LDP interaction modelresources
Resource (LDPR) ← RDF Source (LDPRS) ← Container (LDPC) ← BasicContainer (Basic Container)
affordance
advertised through rel=type Link header, not Content-Type
a GET on a container (LDPC) returns its state (ie. its members)
resources (LDPR) are created by POSTing to the container
HTTP 201 Created + Location header
use DELETE to remove a member
use PUT to override the state of a member
use PATCH for partial updates
39 / 46
LDP Paging (Working Draft) [1/2]HTTP 303 See Other
A 303 response to a GET request indicates that the origin server doesnot have a representation of the target resource [...] the Location fieldvalue refers to a resource that is descriptive of the target resource
also
server has control over the pagination mechanism
client sets preferences
semantics: snapshot, consistency, etc.
40 / 46
LDP Paging (Working Draft) [2/2]use Link relations eg. rel='next'
$ GET https://data.example.com/company/303 See OtherLocation: https://data.example.com/company/?p=5YjF
$ GET https://data.example.com/company/?p=5YjF200 OKLink: <https://data.example.com/company/?p=AyOW>; rel="next"Content-Type: application/ld+json
{ ... }
Save a round-trip: HTTP 333 (being standardised)
41 / 46
servicesmake it discoverable
$ HEAD https://data.example.com/company/Content-Type: application/ld+jsonLink: <https://data.example.com/company/?>; rel="http://data.example.com/api#queryService"
Use Link relation again (not yet standardised)
example
$ GET https://data.example.com/company/?offset=100&limit=50
42 / 46
ad-hoc service-oriented API [1/2]$ GET https://data.example.com/api/getCompaniesByIndustry?industryName="Fruits"Content-Type: application/ld+json
{ "@context": { ... }, "results": [ { "@id": "https://data.example.com/company/c34dap", ... }, ... ]}
domain aware
more capabilities
requires to read documentation
return resource URIs and use inlining when needed
43 / 46
ad-hoc service-oriented API [2/2]microservices
going further
general purpose service-oriented API?
analytics
44 / 46
error handlingLDP servers MUST publish any constraints on LDP clients’ ability tocreate or update LDPRs, by adding a Link header withrel='describedby' [RFC5988] to all responses to requests which fail dueto violation of those constraints. [LDP 4.2.1.2]
so basically, HTTP 4xx + rel='describedby' Link header
use HTTP 400 for application-specific error [LDP ISSUE-98]
for machine readable errors, consider Problem Details for HTTP APIs [http-problem-06]
45 / 46
to readHTTP/REST
Web Client Programming with Perlhttp://www.slideshare.net/RubenVerborgh/hypermedia-cannot-be-the-engine
LDP
LDP 1.0 Primer (Editor's Draft)LDP 1.0 (Editor's Draft)
RDF
http://www.w3.org/TR/2014/REC-turtle-20140225/http://semanticweb.com/introduction-to-rdf_b17953http://www.w3.org/TR/2012/REC-rdb-direct-mapping-20120927/
46 / 46