Sliding away from Roy Fielding's

REST model

Filippos Vasilakis

Web Engineer at Kollegorna

Topics

  1. REST defined by Roy Fielding
  2. REST in practice
  3. 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
  1. Available attributes with data types
  2. Links (with URI templates)
    • available resources
    • available associations
  3. 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 runtime that client could need
    • client's UI could render a subset of them
  • provide detailed documentation  provide 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

  1. Available attributes with data types
  2. Links (with URI templates)
    • available resources
    • available associations
  3. 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!

Made with Slides.com