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

    View Slide

  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

    View Slide

  3. 3

    View Slide

  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

    View Slide

  5. View Slide

  6. 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

    View Slide

  7. 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

    View Slide

  8. 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

    View Slide

  9. 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

    View Slide

  10. Fail: 400 Bad Request to all invalid input
    Malformed JSON is not the same as not sending one parameter
    10

    View Slide

  11. 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

    View Slide

  12. 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

    View Slide

  13. 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

    View Slide

  14. 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

    View Slide

  15. Tip: Require User-Agent header
    You'll know who uses your API
    Automatically populated by browsers
    15

    View Slide

  16. 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

    View Slide

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

    View Slide

  18. Fail: Even arrays as objects
    {
    "data": {
    "0": {
    "count": 12
    },
    "1": {
    "count": 30
    },
    "2": {
    "count": 61
    }
    }
    }
    18

    View Slide

  19. Tip: Allow easy processing using map , etc.
    {
    "data": [
    {
    "creationDate": "2019-01-01",
    "count": 12
    },
    {
    "creationDate": "2019-01-02",
    "count": 30
    },
    ]
    }
    19

    View Slide

  20. 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

    View Slide

  21. Next level

    View Slide

  22. 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

    View Slide

  23. 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

    View Slide

  24. HATEOAS (or Hypermedia)
    Hypermedia As The Engine Of Application State
    Simply said: Include links to other resources or actions on a
    resource
    24

    View Slide

  25. 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

    View Slide

  26. 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

    View Slide

  27. Questions?

    View Slide

  28. Thank you!

    View Slide