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

Design a REST API you will love to work with

Design a REST API you will love to work with

Talk about common mistakes in REST APIs.

Vladimír Kriška

February 23, 2019
Tweet

More Decks by Vladimír Kriška

Other Decks in Technology

Transcript

  1. Design a REST API you will love to work with

    Posobota 102. (Brněnská) Vladimír Kriška
  2. whoami Developer at Keboola currently more on UI/JS than PHP

    building ETL platform Keboola Connection writing about it at 500.keboola.com Occasional speaker, geek, blogger twitter.com/ujovlado medium.com/@ujovlado ujovlado.com 2
  3. 3

  4. State of the APIs? It's 2019 and we're still building

    (or maintaining) the APIs which are huge PITA to use. Cause: Bad design decisions made (e.g. consuming form-data) Developers are careless about API consumers (e.g. objects everywhere) Developers are lazy (e.g. 400 Bad Request for all things that cannot be processes) 4
  5. Fail: Not accepting endpoint w/o trailing / GET /users/ HTTP/1.1

    200 OK GET /users HTTP/1.1 500 Internal Server Error Something like your web not working without www part 6
  6. But it can be even worse Redirects, they said ...

    GET /users HTTP/1.1 301 Moved Permanently Location: /users/ POST /users HTTP/1.1 301 Moved Permanently Location: /users/ 7
  7. 401 Unauthorized vs. 403 Forbidden It's not the same (obviously)

    401 Unauthorized I'm accessing API without valid credentials (token, authorization, etc) 403 Forbidden I'm authorized but not allowed to access speci c endpoint or Rate limiting is in action 8
  8. TIP: Return 404 Not Found in some cases Imagine rst

    user is authenticated. User is allowed to access /pictures/123 (because he uploaded that picture) There's another image with id 456 uploaded by other user Accessing /pictures/456 should return 404 Not Found for the rst user not 403 Forbidden Otherwise we're leaking existence Security issue. 9
  9. Fail: 400 Bad Request to all invalid input Malformed JSON

    is not the same as not sending one parameter 10
  10. Tip: Use 422 Unprocessable Entity for validation POST /users {

    "username": "ujovlado" } HTTP/1.1 422 Unprocessable Entity { "message": "Missing required fields", "errors": [ { "field": "email", "error": "E-mail address is required" } ] } 11
  11. Fail: 201 Created with empty body POST /users HTTP/1.1 201

    Created I don't know what's that mean Where is resource I just created? Well, I'll get it my way: GET /users ^ That can be prevented 12
  12. Tip: Return new resources For creation, return newly created: POST

    /users HTTP/1.1 201 Created { "username": "ujovlado", "email": "vlado@..." } For updates, return updated resource: PUT /users/ujovlado HTTP/1.1 200 OK { ... 13
  13. Tip: 202 Accepted for async resource actions There are some

    cases when requests action is processed asynchronously Provide meaningful response, so consumer can check processing (if available) 14
  14. Tip: Require User-Agent header You'll know who uses your API

    Automatically populated by browsers 15
  15. Tip: Allow browser usage Don't expect only server to server

    communication (especially not these days when "everything" is moving to client). Accept OPTIONS method. And response with proper headers. OPTIONS / HTTP/1.1 204 No Content Access-Control-Allow-Headers: ... Access-Control-Allow-Methods: ... Access-Control-Allow-Origin: * 16
  16. Fail: Everything as object { "data": { "2019-01-01": { "count":

    12 }, "2019-01-02": { "count": 30 } } } Do you know what a date means? 17
  17. Fail: Even arrays as objects { "data": { "0": {

    "count": 12 }, "1": { "count": 30 }, "2": { "count": 61 } } } 18
  18. Tip: Allow easy processing using map , etc. { "data":

    [ { "creationDate": "2019-01-01", "count": 12 }, { "creationDate": "2019-01-02", "count": 30 }, ] } 19
  19. Fail: Versioning instead of evolution Issuing new endpoint (e.g. /v3

    ) is the same like major version of the library. It is less invasive if your APIs are used through client libraries, but still a BC break. 20
  20. Include related resources Instead of 2 requests GET /users/ujovlado and

    GET /users/ujovlado/devices , special parameter is used to include also related resources. GET /users/ujovlado?include=devices { ... "devices": [ {"type": "mobile"}, {"type": "screen"} ] } 22
  21. Respect cache-related headers If request is made with header If-Modified-Since:

    Thu, 05 Feb 2019 15:31:30 GMT you should return data only if resource changed. Otherwise return 304 Not Modify 23
  22. HATEOAS (or Hypermedia) Hypermedia As The Engine Of Application State

    Simply said: Include links to other resources or actions on a resource 24
  23. Example GET /users/ujovlado HTTP/1.1 200 OK { "username": "....", "email":

    "....", "links": { "devices": "https://MY_API/users/ujovlado/devices", "posts": "https://MY_API/users/ujovlado/posts } } 25
  24. Tips & Links Spend more time on designing Design your

    API with respect to some speci cation (e.g. https://jsonapi.org/ is better than nothing) Or use framework which will do it Do not reinvent a wheel, get inspired by highly used APIs (Github API, etc.) For REST APIs, check: https://apisyouwonthate.com/ Try to write simple SPA consuming your API 26