Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The never ending REST API design debate -- Devo...

The never ending REST API design debate -- Devoxx France 2016

Guillaume Laforge

April 22, 2016
Tweet

More Decks by Guillaume Laforge

Other Decks in Technology

Transcript

  1. 2

  2. The never-ending REST API design debate Guillaume Laforge Restlet —

    the Web API platform Chair of the Apache Groovy PMC @glaforge
  3. 8 Representational State Transfer Architectural properties • Performance • Scalability

    • Simplicity • Modifiability • Visibility • Portability • Reliability Architectural constraints • Client-server • Stateless • Cacheable • Layered system • Code on demand (optional) • Uniform interface
  4. 9 REST — Uniform interface • Identification of resources •

    Manipulation of resources 
 through representations • Self-descriptive messages • HATEOAS 
 (Hypermedia As The Engine 
 Of Application State)
  5. 9 REST — Uniform interface • Identification of resources •

    Manipulation of resources 
 through representations • Self-descriptive messages • HATEOAS 
 (Hypermedia As The Engine 
 Of Application State) Resource as URIs http://api.co/cars/123
  6. 9 REST — Uniform interface • Identification of resources •

    Manipulation of resources 
 through representations • Self-descriptive messages • HATEOAS 
 (Hypermedia As The Engine 
 Of Application State) Resource as URIs http://api.co/cars/123 JSON, XML…
  7. 9 REST — Uniform interface • Identification of resources •

    Manipulation of resources 
 through representations • Self-descriptive messages • HATEOAS 
 (Hypermedia As The Engine 
 Of Application State) Resource as URIs http://api.co/cars/123 JSON, XML… HTTP GET, POST, PUT, DELETE media types, cacheability…
  8. 9 REST — Uniform interface • Identification of resources •

    Manipulation of resources 
 through representations • Self-descriptive messages • HATEOAS 
 (Hypermedia As The Engine 
 Of Application State) Resource as URIs http://api.co/cars/123 JSON, XML… HTTP GET, POST, PUT, DELETE media types, cacheability… Hypermedia APIs HAL, JSON-LD, Siren…
  9. 10 HTTP methods / URIs for collection/item GET POST PUT

    DELETE http://api.co/v2/cars/ http://api.co/v2/cars/1234 List all the cars Retrieve an individual car Create a new car Error Replace the entire collection with a whole new list of cars Update an individual car Delete all the cars Delete an individual car
  10. 12 Nouns are good, verbs are bad! • Prefer nouns

    to verbs • nouns refer to resources • resources are handled with HTTP verbs • Verbs can be used for actions or calculations • /login, /logout • /convertTemperature • /repositories/123/star
  11. 14 Singular or plural resources? • Prefer plural forms •

    /tickets/234 vs /ticket/234 • Avoid confusing odd singular vs plural forms • /person vs /people, or /goose vs /geese • Easier for URL routing (same prefix) • Think of it as: 
 ‘This is the 234th item of the tickets collection’
  12. 16 Different casing in the wild • UpperCamelCase or lowerCamelCase

    • snake_case or dashed-snake-case • Prefer lowercase • Prefer snake_case • Underscores seem more common in APIs • But chose one casing and be consistent!
  13. 17 Dealing with relations in your URLs • /tickets/123/messages/4 •

    a ticket could be a group of messages • /usergroups/234/users/67 • a user could belong to different usergroups • user should have a URL of its own, referenced from the usergroup payload
  14. 19 API parameters — rule of thumbs • Path •

    required, resource identifier • Query • optional, query collections • Body • resource specific logic • Header • global, platform-wide
  15. 21 Common HTTP status codes • Use appropriate HTTP status

    codes when answering requests: • 1xx: Hold on… • 2xx: Here you go! • 3xx: Go away! • 4xx: You fucked up :-D • 5xx: I fucked up :-(
  16. 26 Not just 200 OK! — 201 Created • Specify

    a Location header, pointing at the location of the newly created resource POST /cars ... HTTP/1.1 201 Created Location: http://cars.co/v2/cars/5959
  17. 29 Not just 200 OK! — 202 Accepted • Request

    accepted but will be handled asynchronously • a job might be running later and yield a result later on POST /jobs ... HTTP/1.1 202 Accepted No payload returned
  18. 30 Not just 200 OK! — 204 No content •

    The resource was deleted and no payload is returned • but could return 200 OK 
 & provide the payload of the deleted element DELETE /tickets/654 HTTP/1.1 204 No content
  19. 31 Not just 200 OK! — 206 Partial content •

    A partial list of meteorites is returned, using pagination • add a Link header to facilitate navigation GET /meteorites?page=4 HTTP/1.1 206 Partial content Link: <http://nasa.co/meteorites?page=1>; rel="first", 
 <http://nasa.co/meteorites?page=3>; rel="prev", <http://nasa.co/meteorites?page=5>; rel="next", 
 <http://nasa.co/meteorites?page=9>; rel="last" ...
  20. 32 Not just 200 OK! — 304 Not modified •

    When HTTP caching headers are in play • the client should have a version in cache already GET /meteorites/654 HTTP/1.1 304 Not modified
  21. 34 Last-Modified GET /users/123 Modified-Since: Wed, 13 Apr 2016 02:13:11

    GMT HTTP/1.1 200 OK Last-Modified: Fri, 15 Apr 2016 04:58:08 GMT
  22. 35 ETag GET /users/123 If-None-Match: a456ef544eeb7333af HTTP/1.1 200 OK ETag:

    686897696a7c876b7e GET /users/123 If-None-Match: 686897696a7c876b7e HTTP/1.1 304 Not modified
  23. 37 Pagination with query parameters • With a page number:

    ?page=23 • can also specify a page size • might get odd results when insertions happen • With a cursor: ?cursor=34ea3fd6 • insertion-friendly • With a semantic parameter: ?page=A • interesting when limited / discrete number of pages
  24. 38 Pagination with accept range header • Accept range header

    not just for bytes GET /users HTTP/1.1 206 Partial content Accept-Ranges: users Content-Range: users 0-9/200 GET /users Range: users=0-9
  25. 40 Wrapped collections • Prefer unwrapped collections • unless there’s

    specific collection payload metadata
 (example: photo album details) • pagination are better in HTTP headers GET /tickets Content-Type: application/json { data: [ { id: 1, ... }, { id: 2, ... } ] } GET /tickets Content-Type: application/json [ { id: 1, ... }, { id: 2, ... } ]
  26. 43 Provide helpful error payloads • No definitive standard yet

    • http problem proposal and vnd-error mime type HTTP/1.1 403 Forbidden Content-Type: application/problem+json Content-Language: en { "type": "https://example.com/probs/out-of-credit", "title": "You do not have enough credit.", "detail": "Your current balance is 30, but that costs 50.", "instance": "/account/12345/msgs/abc", "balance": 30, "accounts": ["/account/12345", "/account/67890"] }
  27. 45 Treating unknown status codes • An unknown status code

    should be treated 
 as the first one of the family • 4xx — 400 generic client error • 5xx — 500 generic server error
  28. 47 Rate limitation HTTP/1.1 200 OK Date: Mon, 01 Jul

    2013 17:27:06 GMT Status: 200 OK X-RateLimit-Limit: 60 X-RateLimit-Remaining: 56 X-RateLimit-Reset: 1372700873 Total number of requests allowed Number of requests left remaining window before the rate limit resets in UTC epoch seconds
  29. 49 Selecting with query parameters • Only 5 stars Chinese

    restaurants • GET https://api.co/restaurants?type=chinese&stars=5
  30. 51 Filtering • Specify fields you’re interested in: • GET

    https://api.co/users/123?fields=firstname,lastname,age • Specify excluded fields: • GET https://api.co/users/123?exclude=biography,resume • Specify a « style »: • GET https://api.co/users/123?style=compact
  31. 52 Prefer… the prefer header GET /users/123 HTTP/1.1 Content-Type: application/json

    Prefer: return=minimal Vary: Prefer,Accept,Accept-Encoding HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 Vary: Prefer,Accept,Accept-Encoding Preference-Applied: return=minimal Define different profiles: minimal, mobile, full…
  32. 53 Expanding referenced resources • Use the dot notation to

    explicit you want sub-resources • GET https://api.co/users/123?fields=address.zip • user • name • address • zip • country • … • …
  33. 55 Sorting • SQL-style • GET https://api.co/books?sort=title+DESC • GET https://api.co/books?sort=title+DESC,author+ASC

    • Sort + asc/desc combo • GET https://api.co/books?sort=title&desc=title • GET https://api.co/books? sort=title,author&desc=title&asc=author
  34. 58 Search / filter / sort… • Also have a

    look at other approaches • Facebook’s GraphQL • Netflix’s Falcor
  35. v1

  36. 60 Different approaches for API versioning • Most frequent, in

    the URL: • https://api.com/v2/restaurants/1234 • Custom header: • X-API-Version: 2 • Less frequent, with an accept header • clients don’t have to change endpoint, but update headers GET /restaurants Accept: application/vnd.restaurants.v2+json
  37. 63 Pros & Cons of hypermedia • Pros • more

    generic clients • can palliate the need for API versioning • Cons • heavier payload (think mobile devices w/ bad connectivity) • clients still need to understand what links are about and how to represent them in their UI
  38. C H A N G E IS U N A

    V O ID A B L E
  39. 65 Lots of choice • HAL • JSON-LD • Collection+JSON

    • SIREN • … • Which to chose from? • no real consensus yet • but HAL seems quite common
  40. 66 A word about IDs for linked resources • If

    you’re tempted to go your own way for hypermedia… • Be sure to define direct links to resources • photos: [http://news.co/articles/123/photos/654,
 http://news.co/articles/123/photos/659] • Not mere IDs for which API clients need to figure out the exact resource location (error-prone) • photos: [654, 659]
  41. 67 Another word about IDs • Usually avoid counter-type IDs:

    1, 2, 3, 4… • Prefer UUIDs • makes it harder for malignant users 
 to scan & discover existing resources • auto-incrementing IDs might not be unique 
 in distributed systems
  42. 69 HAL approach GET https://api.com/player/1234567890 HTTP/1.1 200 OK { "_links":

    { "self": { "href": "https://api.com/player/1234567890" }, "friends": { "href": "https://api.com/player/1234567890/friends" } }, "playerId": "1234567890", "name": "Kevin Sookocheff", "alternateName": "soofaloofa", "image": "https://api.com/player/1234567890/avatar.png" } Special _links property
  43. 71 API design resources • http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api • https://github.com/paypal/api-standards/blob/master/api-style-guide.md • http://blog.octo.com/en/design-a-rest-api/

    • https://github.com/interagent/http-api-design/blob/master/SUMMARY.md • http://sookocheff.com/post/api/on-choosing-a-hypermedia-format/ • http://www.troyhunt.com/2014/02/your-api-versioning-is-wrong-which-is.html