Filippos Vasilakis
Web Engineer at Kollegorna
REST is defined by four interface constraints
(taken from Roy's thesis)
That would mean:
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..
Provide a ORM to client over HTTP
Resource
+
Collection
Collection
}
}
{
"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?
{
"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
{
"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
{
"_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": {
"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":[{ "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":[
{
"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
Parsing these info at runtime leads to:
{
"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?
Separate hypermedia and documentation from actual data
Idea
How?
JSON Hyper Schemas + HTTP OPTIONS on the endpoint
API introspection
HTTP GET https://my-api.com/api/v1/users/1
protocol
method
host
resource
unique
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
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.
{
"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
{
"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
{
"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
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)
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
Still online but on demand:
Specs that seprate hypermedia from data model and data
Specs that seprate hypermedia from data model and data
Specs that seprate hypermedia from data model and data
Thank you!