Sliding away from Roy Fielding's
REST model
Filippos Vasilakis
Web Engineer at Kollegorna
Topics
- REST defined by Roy Fielding
- REST in practice
- Introspected REST
Roy Fielding's REST
- identification of resources
- manipulation of resources through representations
- self-descriptive messages
-
hypermedia as the engine of application state.
- HATOEAS
REST is defined by four interface constraints
(taken from Roy's thesis)
Roy Fielding's REST
-
provide links that client must use
- server response (with links) reflects the UI
Roy Fielding's REST
-
provide links that client must use
- response (with links) reflects the UI
That would mean:
- different response for different devices
- Accept header
- Content-Type header
APIs of a business in 2016
- develop a flexible API
- one to fit all strategy
- split content in resources
- provide links at runtime that client could need
- client's UI could render a subset of them
- provide detailed documentation
Roy Fielding's REST
A REST API should be entered with no prior knowledge beyond the initial URI (bookmark) and set of standardized media types that are appropriate for the intended audience (i.e., expected to be understood by any client that might use the API).
We are already sliding away from Roy's idea..
Modern APIs
Provide a ORM to client over HTTP
- Sparse fields
- Granular permissions
- Associations on demand
- Hypermedia Driven
Resource
+
Collection
Collection
}
- Sorting & pagination
- Filtering collections
- Aggregation queries
}
Hypermedia Driven
{
"micropost": {
"id": 3031,
"description": "Hey there!",
"links": {
"self": "/api/v1/microposts/3031",
"comments": "/api/v1/microposts/3031/comments",
"user": "/api/v1/users/18"
},
"likes": [{
"user_id": 18,
"video_id": 3031,
"user": {
"id": 18,
"username": "filippos",
"name": "Filippos Vasilakis",
"avatar": "4c657cfe-116d-4f3f-694d-9164e5294e72.jpg"
},
"links":{
"micropost": "/api/v1/micropost/3031",
"user": "/api/v1/users/18"
}
}]
}
}
Is it only links?
API specs on 2016
{
"data": [
{
"id": "288",
"type": "microposts",
"attributes": {
"content": "Nordic APIs now live!",
"user-id": 1,
"created-at": "2016-10-06T20:45:12Z",
"updated-at": "2016-10-06T11:02:12Z"
},
"relationships": {
"user": {
"links": {
"self": "/api/v1/users/1"
}
}
}
}
],
"links": {
"self": "/api/v1/microposts?page[number]=1&page[size]=1",
"next": "/api/v1/microposts?page[number]=2&page[size]=1",
"last": "/api/v1/microposts?page[number]=3&page[size]=1"
}
}
JSONAPI
- Some links (no URI templates)
- No actions
- No info on available attributes
- No data types of attributes
- No descriptions/helpful messages
API specs on 2016
{
"data": {
"id": "1",
"type": "users",
"attributes": {
"name": "Filippos Vasilakis",
"email": "vasilakisfil@gmail.com",
"created-at": "2016-10-06T20:46:55Z",
"microposts-count": 50,
"followers-count": 38,
"followings-count": 49
},
"relationships": {
"microposts": {
"links": {
"related": "/api/v1/microposts?user_id=1"
}
}
}
}
JSONAPI
- Some links (no URI templates)
- No actions
- No info on available attributes
- No data types of attributes
- No descriptions/helpful messages
API specs on 2016
{
"_links":{
"self":{
"href":"/api/v1/microposts"
},
"curries":[
{
"name":"ea",
"href":"http://example.com/docs/rels/{rel}",
"templated":true
}
]
},
"_embedded":{
"micropost":[
{
"_links":{
"self":{
"href":"/api/v1/microposts/{id}"
},
"user":{
"href":"/api/v1/users/{user_id}"
}
},
"id": 288,
"content":"Nordic APIs is not live!",
"user_id":6,
"created_at":"2016-10-06T20:45:12.693Z",
"updated_at":"2016-10-06T11:02:12.693Z"
}
]
}
}
HAL
- Links (no URI templates)
- No actions
- No info on available attributes
- No data types of attributes
- Some descriptions/helpful messages
API specs on 2016
{
"_links": {
"self": {
"href": "/api/v1/users/{id}"
},
"microposts": {
"href": "/api/v1/microposts/user_id={id}",
"templated": true
}
},
"id": "1",
"name": "Filippos Vasilakis",
"email": "vasilakisfil@gmail.com",
"created-at": "2016-10-06T20:46:55Z",
"microposts-count": 50,
"followers-count": 38,
"followings-count": 49
}
HAL
- Links (no URI templates)
- No actions
- No info on available attributes
- No data types of attributes
- Some descriptions/helpful messages
API specs on 2016
{
"links":[{ "rel": ["self"], "href": "/api/v1/microposts" }],
"entities":[
{
"links":[
{"rel":["self"], "href":"/api/v1/microposts/288"},
{"rel":["user"], "href":"/api/v1/users/1"}
],
"rel":[
"micropost"
],
"class":[
"micropost"
],
"properties":{
"content":"Nordic APIs is now live!",
"user_id":1,
"created_at":"2016-10-06T20:45:12.693Z",
"updated_at":"2016-10-06T11:02:12.693Z"
}
},
],
"actions":[
{
"name": "create-micropost",
"title": "Create Micropost",
"method": "POST",
"href": "http://myapi.com/microposts",
"type": "application/json",
"fields": [
{ "name": "context", "type": "text" }
]
}
],
"class":[
"microposts"
]
}
Siren
- Links (no URI templates)
- Actions
- No info on available attributes
- No data types of attributes
- Some descriptions/helpful messages
API specs on 2016
{
"links":[
{
"rel":[
"self"
],
"href":"/api/v1/users/1"
},
{
"rel":[
"microposts"
],
"href":"/api/v1/microposts?user_id=1"
}
],
"class":[
"user"
],
"actions":[
],
"properties":{
"id":"1",
"name":"Filippos Vasilakis",
"email":"vasilakisfil@gmail.com",
"created-at":"2016-10-06T20:46:55Z",
"microposts-count":50,
"followers-count":38,
"followings-count":49
}
}
Siren
- Links (no URI templates)
- Actions
- No info on available attributes
- No data types of attributes
- Some descriptions/helpful messages
- Available attributes with data types
- Links (with URI templates)
- available resources
- available associations
- Available actions
Hypermedia Driven APIs
- Performance issues
- Complexity
- Possibly useless information
Parsing these info at runtime leads to:
API specs on 2006
{
"id":"1",
"name":"Filippos Vasilakis",
"email":"vasilakisfil@gmail.com",
"created-at":"2016-10-06T20:46:55Z",
"microposts-count":50,
"followers-count":38,
"followings-count":49
}
I miss my good old API
{
"microposts":[
{
"content":"Nordic APIs is now live!",
"user_id":1,
"created_at":"2016-10-06T20:45:12.693Z",
"updated_at":"2016-10-06T11:02:12.693Z"
}
]
}
Is it possible to have an API like that today?
APIs for the future
Separate hypermedia and documentation from actual data
Idea
How?
JSON Hyper Schemas + HTTP OPTIONS on the endpoint
API introspection
APIs for the future
HTTP GET https://my-api.com/api/v1/users/1
protocol
method
host
resource
unique
APIs for the future
https://my-api.com/api/v1/users/1
}
GET
POST
PUT/PATCH
DELETE
{
HTTP
https://my-api.com/api/v1/users
}
GET
POST
PUT/PATCH
DELETE
{
HTTP
APIs for the future
- Develop a flexible API
- one to fit all strategy
- Split content in resources
- provide links
at runtimethat client could need- client's UI could render a subset of them
-
provide detailed documentationprovide automated documentation
APIs for the future
Provide automated documentation
JSON Schemas!
JSON Schema specifies a JSON-based format to define the structure of JSON data for validation, documentation, and interaction control. A JSON Schema provides a contract for the JSON data required by a given application, and how that data can be modified.
API specs for the future
{
"id":"1",
"name":"Filippos Vasilakis",
"email":"vasilakisfil@gmail.com",
"created-at":"2016-10-06T20:46:55Z",
"microposts-count":50,
"followers-count":38,
"followings-count":49
}
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"email": {
"type": "string"
},
"created-at": {
"type": "string"
},
"microposts-count": {
"type": "integer"
},
"followers-count": {
"type": "integer"
},
"followings-count": {
"type": "integer"
}
}
}
1. Available attributes with data types
API specs for the future
{
"id":"1",
"name":"Filippos Vasilakis",
"email":"vasilakisfil@gmail.com",
"created-at":"2016-10-06T20:46:55Z",
"microposts-count":50,
"followers-count":38,
"followings-count":49
}
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"id": {
"type": "string",
"minimum": "1"
},
"name": {
"type": "string",
"pattern": "^[a-zA-Z ]*$",
"minLength": 5,
"maxLength": 120
},
"email": {
"type": "string",
"format": "email"
},
"created-at": {
"type": "string",
"format": "date-time"
},
"microposts-count": {
"type": "integer",
"format": "date-time"
},
"followers-count": {
"type": "integer",
"minimum": "1"
},
"followings-count": {
"type": "integer",
"minimum": "1"
}
}
}
1. Available attributes with data types
API specs for the future
{
"microposts":[
{
"content":"Nordic APIs is now live!",
"user_id":1,
"created_at":"2016-10-06T20:45:12.693Z",
"updated_at":"2016-10-06T11:02:12.693Z"
}
]
}
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"microposts": {
"type": "array",
"uniqueItems": true,
"items": {
"type": "object",
"properties": {
"content": {
"type": "string",
"minLength": 1,
"maxLength": 160
},
"user_id": {
"type": "integer",
"multipleOf": 1,
"minimum": 1,
},
"created_at": {
"type": "string",
"format": "date-time"
},
"updated_at": {
"type": "string",
"format": "date-time"
}
}
}
}
}
}
1. Available attributes with data types
API specs for the future
JSON Hyper-Schema
{
"$schema":"http://json-schema.org/draft-04/schema#",
"type":"object",
"properties":{
"microposts":{
"type":"array",
"uniqueItems":true,
"items":{
"type":"object",
"properties":{
}
}
},
"links":[
{
"rel":"user",
"method":"GET",
"href":"/api/v1/user/{user_id}"
}
]
}
}
2. Links (using URI templates)
API specs for the future
JSON Hyper-Schema
{
"$schema":"http://json-schema.org/draft-04/schema#",
"type":"object",
"properties":{
"microposts":{
"type":"array",
"uniqueItems":false,
"items":{
"type":"object",
"properties":{...}
}
},
"links":[
{
"rel":"user",
"method":"GET",
"href":"/api/v1/user/{user_id}"
}, {
"encType": "application/json",
"method": "POST",
"href": "/microposts",
"properties": {
"content": {
"description": "Content of the micropost.",
"type": "string",
"minLength": 1,
"maxLength": 160
}
}
}
]
}
}
3. Available actions
- Available attributes with data types
- Links (with URI templates)
- available resources
- available associations
- Available actions
Hypermedia Driven APIs
- Better performance
- Documentation driven
- Testable input/output for both client and server
Still online but on demand:
APIs for the future
Specs that seprate hypermedia from data model and data
- Open API (also known as Swagger)
- A spec for writting a documentation
- Heavy uses JSON Schemas
- Complex but very robust
- it can even describe headers
- Targeted for offline documetation generation and server side code generation
- limtations on the client side
APIs for the future
Specs that seprate hypermedia from data model and data
- Hydra Spec (JSON-LD + Schema.org + Hydra core Vocabulary)
- Links
- Attributes (no data types)
- Actions
- Context (semantics in Social Web)
APIs for the future
Specs that seprate hypermedia from data model and data
-
GraphQL
- No links :(
- Attributes + data types ( calls it introspection)
- Actions (calls it mutations)
- Covered on the next talk!
Sliding away from Roy Fielding's
REST model
Thank you!
Sliding away from Roy Fielding's REST model
By Filippos Vasilakis
Sliding away from Roy Fielding's REST model
The 2016 Platform Summit, Nordic APIs, Stockholm, Sweden, October 2016
- 2,137