API

State of the art

@mihahribar

@toshl

How we build APIs today?

  • SOAP
  • RPC
  • REST

Define: REST

REpresentational State Transfer (REST) is a style of software architecture for distributed systems such as the World Wide Web.

Define: RESTful API

A RESTful API is a web service implemented using HTTP and the principles of REST.

Roy Fielding doctoral dissertation, 2000.

Constraints

  • Client-server

    Separate clients and servers.

  • Stateless server

    Each request from the client contains all the information necessary to service the request.

  • Cacheable

    Clients can cache responses, if permitted by the server.

  • Layered system

    Load balancers, proxies, firewalls etc.

  • Code on demand (optional)

    Client can request code from server and execute it.

  • Uniform interface

    Between the client and the server.

Uniform Interface

  • Identification of resources

    Through URI. api.toshl.com/users/42

  • Manipulation of resources

    POST, GET, PUT/PATCH, DELETE

  • Self-descriptive messages

    Through meta data.

  • Hypermedia as the engine of application state

    HATEOAS, huh?

Define: HATEOAS

A client interacts with a network application entirely through hypermedia provided dynamically by application servers. A REST client needs no prior knowledge about how to interact with any particular application or server beyond a generic understanding of hypermedia.

In HTML <a>, <form>, <img> etc.

Let's jump in

Think things through

When in doubt

Check the spec RFC 2616.

URI Structure

  • Collections
  • Resources
  • Controllers
https://api.toshl.com/expenses
https://api.toshl.com/expenses/42
https://api.toshl.com/budgets
https://api.toshl.com/export

Help a client out

$ curl -v https://api.toshl.com
					
> GET / HTTP/1.1
> 
< HTTP/1.1 204 No Content
< Allow: GET
< Link: </expenses>; rel="expenses",</expenses/tags>; rel="expense tags",</incomes>; rel="incomes",...
< Content-Length: 0
< Content-Type: application/json

Include a handy Link header.

CRUD

  • POST = Create
  • GET = Read
  • PUT/PATCH = Update
  • DELETE = Delete
$ curl -v https://api.toshl.com/expenses
					
> GET / HTTP/1.1
> 
< HTTP/1.1 200 OK
< Allow: GET, POST, HEAD

Use correct response status codes

  • 200 (OK)
  • 201 (Created)
  • 202 (Accepted)
  • 204 (No Content)

Create

$ curl -v -X POST -d "..." https://api.toshl.com/expenses

> POST /expenses HTTP/1.1
> 
< HTTP/1.1 201 Created
< Allow: GET,POST
< Location: /expenses/1031
< Content-Length: 176
< Content-Type: application/json
< 
{"id":1031,"amount":100,"currency":"EUR","rate":1,"date":"2012-10-23","desc":null,"tags":["food"],"loc":["0.000000","0.000000"],"modified":"2012-10-23T19:20:46+00:00Z","repeat":null,"extra":null}

Spot the error?

Create

$ curl -v -X POST -d "..." https://api.toshl.com/expenses

> POST /expenses HTTP/1.1
> 
< HTTP/1.1 201 Created
< Allow: GET,POST
< Location: /expenses/1031
< Content-Length: 200
< Content-Type: application/json
< 
{"id":1031,"href":"/expenses/1031","amount":100,"currency":"EUR","rate":1,"date":"2012-10-23","desc":null,"tags":["food"],"loc":["0.000000","0.000000"],"modified":"2012-10-23T19:20:46+00:00Z","repeat":null,"extra":null}

HATEOAS - include a link to the resource URI.

Read

$ curl -v https://api.toshl.com/expenses/1031

> GET /expenses/1031 HTTP/1.1
> 
< HTTP/1.1 200 OK
< Allow: GET,PUT,PATCH,DELETE
< Content-Length: 219
< Content-Type: application/json
< 
{"id":1031,"href":"/expenses/1031","amount":100,"currency":"EUR","rate":1,"date":"2012-10-23","desc":null,"tags":["food"],"loc":["0.000000","0.000000"],"modified":"2012-10-23T19:20:46+00:00Z","repeat":null,"extra":null}

Update

$ curl -v -X PUT -d "..." https://api.toshl.com/expenses/1031

> PUT /expenses/1031 HTTP/1.1
> 
< HTTP/1.1 200 OK
< Allow: GET,PUT,PATCH,DELETE
< Content-Length: 219
< Content-Type: application/json
< 
{"id":1031,"href":"/expenses/1031","amount":200,"currency":"EUR","rate":1,"date":"2012-10-23","desc":null,"tags":["food"],"loc":["0.000000","0.000000"],"modified":"2012-10-23T19:20:46+00:00Z","repeat":null,"extra":null}

GET and PUT are idempotent methods.

Delete

$ curl -v -X DELETE https://api.toshl.com/expenses/1031

> DELETE /expenses/1031 HTTP/1.1
> 
< HTTP/1.1 204 No Content
< Allow: GET,PUT,PATCH,DELETE
< Content-Length: 0
< Content-Type: application/json
<

Programmers are people too

Errors

  • 400 (Bad Request)
  • 401 (Unauthorized)
  • 403 (Forbidden)
  • 404 (Not Found)
  • 405 (Method Not Allowed)
  • 409 (Conflict)
  • 500 (Internal Server Error)
  • 503 (Service Unavailable)
  • 418 (?) I'm a teapot
{
	"id": "income_limit"
	"description": "Income limit reached."
}

Media Types

  • Format specification and parsing rules
  • application/json
  • application/vnd.toshl+json
  • application/vnd.toshl.expense+json

Versioning

  • URI

    https://api.toshl.com/v1/expenses/
  • Media Types

    application/vnd.toshl.v1+json
    application/vnd.toshl.expense.v1+json

Pagination

https://api.toshl.com/expenses?page=1&per_page=20

What about previous/next/last links?

$ curl -v https://api.toshl.com/expenses
					
> GET / HTTP/1.1
> 
< HTTP/1.1 200 OK
< Allow: GET, POST
< Link: <expenses?page=2>; rel="next",<expenses?page=9>; rel="last"

Date & time

Timestamp 2012-10-23T22:05:37+00:00Z. ISO 8601.

Sync

  • Add ?since=1351033818

  • Add ?since_id=37821

  • Using Last-Modified and If-Modified-Since

    RESTful API with sync

  • Using Last-Modified and ?since=2012-10-23T22:05:37+00:00Z

Caching

  • Server responds with ETag: "3e12ec4d-994fefe4-24c8868"
  • Client can then send If-None-Match: "3e12ec4d-994fefe4-24c8868"
  • If not modified, server responds with 304 (Not Modified)

Security

  • Basic auth
  • OAuth 1.0
  • OAuth 2.0

    GET /expenses HTTP/1.1
    Host: api.toshl.com
    Authorization: Bearer vF9dft4qmT
  • OAuth 2.0 + MAC

    GET /expenses HTTP/1.1
    Host: api.toshl.com
    Authorization: MAC id="h480djs93hd8",
    	       nonce="264095:dj83hs9s",
    	       mac="SLDJd4mg43cjQfElUs3Qub4L6xE="

Are we there yet?

  • We expose our objects by type-marshaling/serialization
  • Create special media types for each object
  • Smack a CRUD interface on top of it
  • And call it an API

But then

  • Update the API, clients break
  • Update process, rewrite clients
  • Versioning doesn't help
  • Simple data, complex client
  • Shouldn't that be the other way round?

Define: HATEOAS (again)

A client interacts with a network application entirely through hypermedia provided dynamically by application servers. A REST client needs no prior knowledge about how to interact with any particular application or server beyond a generic understanding of hypermedia.

Close but no cigar

Standing on the shoulders of giants

The WWW is fundamentally a distributed hypermedia application. —Richard Taylor

APIs and clients, they are hiding in plain sight.

Websites, HTML and the browser.

Explain

  • Point the browser to a web page
  • Browser executes a GET page.
  • If the user clicks a link, construct a GET uri request.
  • If the user submits a form, construct a POST uri "data" request.

Complex data, simple client

  • Server can update independent from the client
  • Clients don't break
  • Clients don't have to know anything about your data
  • Just how to parse it and present it
  • Execute custom code on the client

Why don't we build APIs this way?

Define: WRML

Web Resource Modeling Language

WRML, pronounced like "Wormle", is an open source project focused on providing standards, frameworks, and tools that support the development of web-oriented, client-server applications.
> GET /common/Collection HTTP/1.1 Host: api.schemas.wrml.org

< HTTP/1.1 200 OK
< Content-Type: application/wrml;
< format="http://api.formats.wrml.org/application/json"; schema="http://api.schemas.wrml.org/common/Collection"
{"name" : "Collection", ...}

Hypermedia APIs

  • Use HTTP correctly
  • Serve hypermedia responses
  • Expose processes not objects

Hypermedia factors

  • LO Outbound Links
  • LT Templated Links
  • LI Idempotent Links
  • LN Non-Idempotent Links
  • Embed Links
  • CU Update Controls
  • CM Method Controls
  • CL Link Annotation Controls

Mind blown

Collection+JSON

// sample collection object
{
	"collection" : {
		"version" : "1.0", 
		"href" : URI,
		"links" : [ARRAY], 
		"items : [ARRAY], 
		"queries" : [ARRAY], 
		"template" : {OBJECT}, 
		"error" : {OBJECT}
	}
}

Conclusion

  • Complex data, simple client
  • Expose your processes not your objects
  • Let your API evolve
  • Build Hypermedia APIs

Links