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

API Standards 2.0

Michael Heap
February 22, 2019

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

February 22, 2019
Tweet

More Decks by Michael Heap

Other Decks in Technology

Transcript

  1. Have a deprecation policy. It doesn't matter what it is,

    but be consistent. Deprecation Policies 6
  2. 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 7
  3. Use the Sunset Header Sunset: Sat, 31 Dec 2018 23:59:59

    GMT Sunset Header 8 https://tools.ietf.org/html/draft-wilde-sunset-header-03
  4. $ composer require hskrasek/guzzle-sunset --- $stack = new \GuzzleHttp\HandlerStack(\GuzzleHttp\choose_handler()); $stack->push(new

    \HSkrasek\Sunset\SunsetMiddleware($logger)); $client = new \GuzzleHttp\Client(['handler' => $stack]); API Deprecation: Sunset Header 9
  5. “ 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
  6. “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
  7. GET /users 30 200 OK 301 Moved Permanently 302 Found

    404 Not Found 406 Not Acceptable
  8. PATCH /users/1 36 RFC 7396 - JSON Merge Patch {

    "name":"Michael", "address": { "line_2": null } }
  9. PATCH /users/1 37 RFC 6902 - JavaScript Object Notation (JSON)

    Patch [ { "op": "replace", "path": "/name", "value": "Michael" }, { "op": "remove", "path": "/ address/line_2" } ]
  10. Resource Design 54 • Use snake_case for key names •

    [resource]_id - A string that identifies a specific resource • [description]_url - A url that is necessary for communication. For example, callback_url. • [description]_method - Send the callback using either GET or POST. • start - The time the communication started in https:// en.wikipedia.org/wiki/ISO_8601 format. • end - The time the communication ended in https:// en.wikipedia.org/wiki/ISO_8601 format.
  11. Webhooks 55 • Use snake_case for key names • start

    - The time the communication started in https:// en.wikipedia.org/wiki/ISO_8601 format. • end - The time the communication ended in https:// en.wikipedia.org/wiki/ISO_8601 format.
  12. 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 65 Instance A URI reference that identifies the specific occurrence of the problem
  13. 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 66 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.
  14. 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 67 Instance A URI reference that identifies the specific occurrence of the problem
  15. { "type": "https://developer.nexmo.com/api- errors#unauthorized", "title": "Invalid credentials supplied", "detail": "You

    did not provide correct credentials.", "instance": "797a8f199c45014ab7b08bfe9cc1c12c" } RFC7807 68
  16. 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 69
  17. 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 70
  18. 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 71
  19. 401: No Credentials, Invalid Credentials 403: Feature disabled, Exceeded calls-per-second

    limit 422: Invalid product specified + more! Response Library 72
  20. “ 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
  21. '400': $ref: '#/components/responses/ InvalidPayloadError' '401': $ref: '../shared_errors.yml#/components/ responses/BadCredentialsError' '405': $ref:

    '../shared_errors.yml#/components/ responses/InvalidRequestMethod' '406': $ref: '../shared_errors.yml#/components/ responses/InvalidAcceptHeader' Design First APIs 75
  22. Industry Standards: SCIM 96 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
  23. Pagination: Links 102 { "_links": { "next": { "href": "/calls?cursor=9274"

    } } } Link: <https://api.nexmo.com/v1/calls? cursor=9274>; rel="next",
  24. [ { "id": "78d335fa323d01149c3dd6f0d489", "name": "My Application", } ] GET

    /v2/applications/78d335fa323d01149c3dd6f0d489 104
  25. [ { "id": "78d335fa323d01149c3dd6f0d48968cf", "name": "My Application", "_links": { "self":

    { "href": "/v2/applications/ 78d335fa323d01149c3dd6f0d48968cf" } } } ] GET /v2/applications/78d335fa323d01149c3dd6f0d489 105
  26. [ { "id": "78d335fa323d01149c3dd6f0d48968cf", "name": "My Application", "_links": { "self":

    { "href": "/v2/applications/ 78d335fa323d01149c3dd6f0d48968cf" }, "numbers": { "href": "/v2/numbers? application=78d335fa323d01149c3dd6f0d48968cf" } } } ] GET /v2/applications/78d335fa323d01149c3dd6f0d489 106
  27. "hints": { "allow": [ "GET", "PUT", "DELETE", "PATCH" ], "formats":

    { "application/json": {} } } Hints Format 107
  28. { "numbers": { "href": "/v2/numbers? application=78d335fa323d01149c3dd6f0d48968cf", "hints": { "allow": [

    "GET", "PUT", "DELETE", "PATCH" ], "formats": { "application/json": {} } } } Hints Format 108