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

API Standards 2.0

API Standards 2.0

We’re all familiar with things like HTTP codes and content types, but there’s so much more we can do when developing an API to make life easier for consumers. How many times have you used an API only to find out that every endpoint is slightly different – some use `snake_case`, others `camelCase`, sometimes the field is called `id`, sometimes it’s `user_id`. How about pagination? Error responses? What about API documentation?

Trying to standardise on all these things can kill an engineering team. There are so many options out there it’s difficult to know where to start. Come along and learn what works for our team! We’ll cover contentious topics (should the version be in the URL or a header?), lesser-known standards that are great (RFC 7807 springs to mind) and a couple of things that aren’t an issue right up until they’re a really big issue (like pagination).

Michael Heap

October 04, 2018
Tweet

More Decks by Michael Heap

Other Decks in Technology

Transcript

  1. API STANDARDS 2.0

    View Slide

  2. HELLO!
    I 'm Michael
    I'm @mheap on Twitter
    I have a favourite Time Zone (DMT)

    View Slide

  3. API STANDARDS 2.0

    View Slide

  4. API STANDARDS 2.0
    AN OPINIONATED
    GUIDE TO

    View Slide

  5. 5

    View Slide

  6. APIs at Nexmo
    6
    REST-like

    View Slide

  7. APIs at Nexmo
    7
    Pragmatic
    REST-like

    View Slide

  8. APIs at Nexmo
    8
    Pragmatic
    REST-like
    Consumer
    Success

    View Slide

  9. API Standards
    9
    Status
    Codes

    View Slide

  10. API Standards
    10
    HTTP
    Verbs
    Status
    Codes

    View Slide

  11. API Standards
    11
    HTTP
    Verbs
    Status
    Codes
    Nouns,
    not Verbs

    View Slide

  12. What we're not going to cover
    ▸ Message formats
    ▸ Rate limiting
    ▸ Content negotiation
    ▸ HTTP headers
    ▸ Hypermedia
    ▸ Resource design
    ▸ Response design
    ▸ RPC endpoints
    ▸ Documentation
    ▸ Asynchronous actions
    ▸ Idempotency
    ▸ Caching
    ▸ API Gateways
    ▸ Security
    ▸ GraphQL
    ▸ Available RFCs
    12

    View Slide

  13. 1.
    Errors
    Status Codes, RFC7807 + Extensions
    13

    View Slide

  14. 2.
    Versioning
    Header/URL, Versioning Schemes, Deprecation
    14

    View Slide

  15. 3.
    Collection Management
    Sorting, Filtering, Searching, Pagination
    15

    View Slide

  16. 4.
    URI Design
    Subresources, Action endpoints
    16

    View Slide

  17. 1.
    Errors
    Status Codes, RFC7807 + Extensions
    17

    View Slide


  18. Errors are easy! People should just
    use status codes

    View Slide

  19. 401 Unauthorized
    Error Design
    19

    View Slide

  20. 401 Unauthorized
    {
    "error": "No credentials provided"
    }
    Error Design
    20

    View Slide

  21. 401 Unauthorized
    {
    "error": "Invalid credentials"
    }
    Error Design
    21

    View Slide

  22. 401 Unauthorized
    {
    "error": "Invalid credentials",
    "more_help": "http://example.com/
    auth#invalid-credentials"
    }
    Error Design
    22

    View Slide

  23. 401 Unauthorized
    {
    "msg": "Invalid credentials"
    }
    Error Design
    23

    View Slide

  24. 401 Unauthorized
    {
    "errorCode": 118118,
    "errorMessage": "Invalid credentials"
    }
    Error Design
    24

    View Slide

  25. 401 Unauthorized
    "Invalid credentials"
    Error Design
    25

    View Slide

  26. RFC7807
    Type
    A URI
    reference that
    identifies the
    problem type.
    When followed,
    it provides
    human-readable
    documentation
    for the
    problem type
    Title
    A short,
    human-readable
    summary of the
    problem type
    Detail
    A human-
    readable
    explanation
    specific to
    this
    occurrence of
    the problem
    26
    Instance
    A URI
    reference that
    identifies the
    specific
    occurrence of
    the problem

    View Slide

  27. RFC7807
    Type
    A URI
    reference that
    identifies the
    problem type.
    When followed,
    it provides
    human-readable
    documentation
    for the
    problem type
    Title
    A short,
    human-readable
    summary of the
    problem type
    Detail
    A human-
    readable
    explanation
    specific to
    this
    occurrence of
    the problem
    27
    Instance
    A URI
    reference that
    identifies the
    specific
    occurrence of
    the problem
    Status
    The HTTP
    status code
    generated by
    the origin
    server for
    this
    occurrence of
    the problem.

    View Slide

  28. RFC7807
    Type
    A URI
    reference that
    identifies the
    problem type.
    When followed,
    it provides
    human-readable
    documentation
    for the
    problem type
    Title
    A short,
    human-readable
    summary of the
    problem type
    Detail
    A human-
    readable
    explanation
    specific to
    this
    occurrence of
    the problem
    28
    Instance
    A URI
    reference that
    identifies the
    specific
    occurrence of
    the problem

    View Slide

  29. {
    "type": "https://developer.nexmo.com/api-
    errors#unauthorized",
    "title": "Invalid credentials supplied",
    "detail": "You did not provide correct credentials.",
    "instance": "797a8f199c45014ab7b08bfe9cc1c12c"
    }
    RFC7807
    29

    View Slide

  30. 403 Forbidden
    {
    "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"
    }
    Extension Members
    30

    View Slide

  31. 403 Forbidden
    {
    "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"]
    }
    Extension Members
    31

    View Slide

  32. 400 Bad Request
    {
    "type": "https://developer.nexmo.com/api-errors/account/secret-
    management#validation",
    "title": "Bad Request",
    "detail": "The request failed due to validation errors",
    "invalid_parameters": [
    {
    "name": "secret",
    "reason": "must contain 1 upper case character"
    }
    ],
    "instance": "797a8f199c45014ab7b08bfe9cc1c12c"
    }
    Extension Members
    32

    View Slide

  33. 401: No Credentials, Invalid
    Credentials
    403: Feature disabled, Exceeded
    calls-per-second limit
    422: Invalid product specified
    + more!
    Response Library
    33

    View Slide


  34. As a consumer of the APIs, this has
    already dramatically reduced the
    amount of code I have to write for
    each endpoint, and I can't wait until
    all endpoints are standardised

    View Slide

  35. 2.
    Versioning
    Header/URL, Versioning Schemes, Deprecation
    35

    View Slide


  36. The reason to make a real REST API
    is to get evolvability … a "v1" is a
    middle finger to your API customers,
    indicating RPC/HTTP (not REST)
    https://twitter.com/fielding/status/376835835670167552

    View Slide

  37. “With a sufficient number of users of an
    interface, it doesn’t matter what you
    promised in the interface contracts, all
    observable behaviors of your class or
    function or whatnot will be depended
    upon by somebody.
    Hyrum's Law

    View Slide

  38. Accept: application/vnd.nexmo+json;
    version=3
    URI vs Header
    38

    View Slide

  39. Accept: application/vnd.nexmo+json;
    version=3

    X-Nexmo-Version: 3
    URI vs Header
    39

    View Slide

  40. Accept: application/vnd.nexmo+json;
    version=3

    X-Nexmo-Version: 3
    https://api.nexmo.com/v3
    URI vs Header
    40

    View Slide

  41. https://api.nexmo.com/v1/calls
    Global vs Endpoint versioning
    41

    View Slide

  42. https://api.nexmo.com/v1/calls
    https://api.nexmo.com/v1/media
    Global vs Endpoint versioning
    42

    View Slide

  43. https://api.nexmo.com/v1/calls
    https://api.nexmo.com/v3/media
    Global vs Endpoint versioning
    43

    View Slide

  44. https://api.nexmo.com/v1/calls
    Versioning Scheme
    44

    View Slide

  45. https://api.nexmo.com/v1/calls
    https://api.example.com/2010-04-01
    Versioning Scheme
    45

    View Slide

  46. https://api.nexmo.com/v1/calls
    https://api.example.com/2010-04-01
    https://api.example.com/1.2.3
    Versioning Scheme
    46

    View Slide

  47. https://api.nexmo.com/v3.new-
    feature/calls
    Version Variants
    47

    View Slide

  48. Have a deprecation policy. It
    doesn't matter what it is, but be
    consistent.
    Deprecation Policies
    48

    View Slide

  49. When the decision has been taken to deprecate an
    API:
    • For beta products the deprecation period must be
    at least 30 days (60 days recommended)
    • For GA products the deprecation period must be at
    least 1 year
    • Warning emails will be sent to the API at regular
    intervals before the deprecation time
    • A guide will be supplied to customers explaining
    how to migrate to the replacement API with the
    initial deprecation notice.
    Deprecation Policies: Nexmo
    49

    View Slide

  50. Use the Sunset Header
    Sunset: Sat, 31 Dec 2018 23:59:59
    GMT
    Sunset Header
    50
    https://tools.ietf.org/html/draft-wilde-sunset-header-03

    View Slide

  51. Use the Link Header
    Link: shutdown> rel="sunset"
    Link Header
    51

    View Slide

  52. 3.
    Collection Management
    Sorting, Filtering, Searching, Pagination
    52

    View Slide

  53. Sorting
    53

    View Slide

  54. GET /users?
    sort_by=email&order_by=asc
    Sorting
    54

    View Slide

  55. GET /users?sort_by=email.asc
    Sorting
    55

    View Slide

  56. GET /users?sort_by=email.asc
    &sort_by=status.desc
    Sorting
    56

    View Slide

  57. GET /users?
    sort_by=email.asc,status.desc
    Sorting
    57

    View Slide

  58. GET /users?sort_by=+email,-status
    Sorting
    58

    View Slide

  59. GET /users?sort_by=+email,-status
    GET /users?
    sort_by=email.asc,status.desc
    Sorting
    59

    View Slide

  60. Filtering
    60

    View Slide

  61. Filtering
    61
    Discrete data e.g. user role
    Continuous data e.g. subscription
    expiry time

    View Slide

  62. Discrete Data
    62
    /users?role=admin
    /orders?shipped=true
    /calls?status=active

    View Slide

  63. Discrete Data
    63
    /users?role=admin
    /orders?shipped=true
    /calls?status=active
    403 Forbidden
    /users?is_fbi_informant=true

    View Slide

  64. Discrete Data: JSON API
    64
    GET /employees?
    filter[role]=internal&filter[title]=
    senior

    View Slide

  65. Discrete Data: JSON API
    65
    GET /employees?
    filter[role]=internal&filter[title]=
    senior
    GET /employees?
    role=internal&title=senior

    View Slide

  66. Continuous Data
    66

    View Slide

  67. Continuous Data
    67
    GET /orders?
    start_date=2018-01-01&end-
    date=2018=01-31

    View Slide

  68. Continuous Data
    68
    GET /orders?
    start_date=2018-01-01&end-
    date=2018=01-31
    GET /orders?
    date[gte]=2018-01-01&date[lte]=2018=
    01-31

    View Slide

  69. Industry Standards
    69

    View Slide

  70. Industry Standards: SCIM
    70
    filter=userName eq "bjensen"
    filter=name.familyName co "O'Malley"
    filter=userName sw "J"
    filter=urn:ietf:params:scim:schemas:core:
    2.0:User:userName sw "J"
    filter=title pr
    filter=meta.lastModified gt "2011-05-13T04:42:34Z"
    https://tools.ietf.org/html/rfc7644#section-3.4.2.2

    View Slide

  71. Searching
    71

    View Slide

  72. Searching
    72
    GET /items?q=title:red chair AND
    price:[10 TO 100]

    View Slide

  73. Pagination
    73
    Offset based
    Cursor based

    View Slide

  74. Pagination: Offset
    74
    GET /calls?page=3&page_size=100

    View Slide

  75. Pagination: Cursor
    75
    GET /calls
    GET /calls?
    cursor=2018-01-19T12:33:51
    GET /calls?
    cursor=2018-01-18T03:00:18

    View Slide

  76. Pagination: Links
    76
    {
    "_links": {
    "next": {
    "href": "/calls?cursor=9274"
    }
    }
    }
    Link: cursor=9274>; rel="next",

    View Slide

  77. 4.
    URI Design
    Subresources, Action endpoints
    77

    View Slide

  78. GET /users/1
    Subresources
    78

    View Slide

  79. GET /users/1
    GET /users/1/calls
    Subresources
    79

    View Slide

  80. GET /users/1
    GET /users/1/calls
    GET /users/1/calls/JSDB-1837A
    Subresources
    80

    View Slide

  81. GET /users/1
    GET /users/1/calls
    GET /users/1/calls/JSDB-1837A
    GET /calls/JSDB-1837A
    Subresources
    81

    View Slide

  82. GET /users/1
    GET /users/1/calls
    Subresources
    82

    View Slide

  83. GET /users/1
    GET /users/1/calls
    GET /calls?user=1
    Subresources
    83

    View Slide

  84. GET /users/1
    GET /addresses/33-90210
    GET /users/1/addresses/33-90210
    Subresources
    84

    View Slide

  85. GET /users/1
    GET /addresses/33-90210
    GET /users/1/addresses/33-90210
    GET /user_addresses/1-33-90210
    Subresources
    85

    View Slide

  86. POST /machines/1/shutdown
    Actions
    86

    View Slide

  87. POST /machines/1/shutdown
    POST /machines/1/actions/shutdown
    Actions
    87

    View Slide

  88. POST /machines/1/shutdown
    POST /machines/1/actions/shutdown
    POST /machines/1/action:shutdown
    Actions
    88

    View Slide

  89. POST /machines/1/shutdown
    POST /machines/1/actions/shutdown
    POST /machines/1/action:shutdown
    POST /machines/1/actions {"type":
    "shutdown"}
    Actions
    89

    View Slide

  90. POST /machine-shutdown
    Actions as Resources
    90

    View Slide

  91. POST /machine-shutdown
    PUT /article-locks/{article-id}
    DELETE /article-locks/{article-id}
    POST /balance-transfer
    Actions as Resources
    91

    View Slide

  92. Conclusion

    View Slide

  93. What we didn't cover
    ▸ Message formats
    ▸ Rate limiting
    ▸ Content negotiation
    ▸ HTTP headers
    ▸ Hypermedia
    ▸ Resource design
    ▸ Response design
    ▸ RPC endpoints
    ▸ Documentation
    ▸ Asynchronous actions
    ▸ Idempotency
    ▸ Caching
    ▸ API Gateways
    ▸ Security
    ▸ GraphQL
    ▸ Available RFCs
    93

    View Slide

  94. View Slide