Creating Solid APIs - DjangoCon AU 2018

Creating Solid APIs - DjangoCon AU 2018

Presented at DjangoCon AU 2018

Creating APIs that other developers love to use isn't trivial. I'll share some tips and best practices.

See also: https://rivolaks.com/posts/creating-solid-apis/

895ac7b84a280f686b70e2a70a8f5cd9?s=128

Rivo Laks

August 23, 2018
Tweet

Transcript

  1. Creating Solid APIs DjangoCon AU 2018 Rivo Laks ⋅ 2018-08-24

  2. Background

  3. What is an API?

  4. What is an API? application programming interface

  5. What is an API? application programming interface application programmer interface

  6. What is an API? application programming interface application programmer interface

    API is user interface for developers
  7. Goals

  8. Goals

  9. Goals Comprehensive API for 3rd-party devs

  10. Goals Comprehensive API for 3rd-party devs Easy & automated onboarding

  11. Goals Comprehensive API for 3rd-party devs Easy & automated onboarding

    Minimize pain (friction)
  12. Versioning

  13. Why Do We Need Versioning?

  14. Why Do We Need Versioning? for breaking things in controlled

    fashion
  15. How to Version?

  16. How to Version? You need: Deprecation schedules

  17. How to Version? You need: Deprecation schedules Changelogs / upgrade

    notes
  18. Versioning Schemes

  19. Versioning Schemes AcceptHeaderVersioning (DRF) GET /projects HTTP/1.0 Accept: application/json; version=1

  20. Versioning Schemes AcceptHeaderVersioning (DRF) GET /projects HTTP/1.0 Accept: application/json; version=1

    URLPathVersioning (DRF) GET /v1/projects HTTP/1.0 Accept: application/json
  21. Versioning Schemes Cont. Integers ( v1 ) vs dates (

    2018-08-24 )?
  22. Versioning Schemes Cont. Integers ( v1 ) vs dates (

    2018-08-24 )? Dates are less emotional
  23. Versioning Schemes Cont. Integers ( v1 ) vs dates (

    2018-08-24 )? Dates are less emotional Easier internal / test versions
  24. Version Transformers

  25. Version Transformers » » Requests into newer version » »

    Core code is for latest version « « Responses into older version « «
  26. Version Transformers » » Requests into newer version » »

    Core code is for latest version « « Responses into older version « « Won't work for big, breaking changes
  27. Authentication & Authorization

  28. Token Authentication Clients send HTTP header, ala Authorization: Token 9944b09199c62bcf9418

  29. OAuth 2.0

  30. OAuth 2.0 For creating platforms

  31. OAuth 2.0 For creating platforms Complex, but solves many issues

  32. OAuth 2.0 For creating platforms Complex, but solves many issues

    Many packages, e.g. Django OAuth Toolkit, OAuthLib
  33. Standardize!

  34. Standardize! Standards help: bring familiarity

  35. Standardize! Standards help: bring familiarity avoid common pitfalls

  36. Standardize! Standards help: bring familiarity avoid common pitfalls historically, standardized

    approaches win
  37. JSON API http://jsonapi.org/ one potential standard to use

  38. JSON API http://jsonapi.org/ one potential standard to use GraphQL is

    another option
  39. Standardize Structure

  40. Standardize Structure Responses have predictable, familiar structure

  41. GET https://example.com/api/v1/projects { "links": { "next": "https://example.com/api/v1/projects?cursor=cD0yMDE4L", "prev": null },

    "data": [...], "included": [...] }
  42. "data": [ { "type": "project", "id": "289", "links": { "self":

    "https://example.com/api/v1/projects/289" }, "attributes": { "created": "2018-06-28T22:52:08.690486Z", "name": "Allison-Patterson", "description": "aggregate collaborative models" }, "relationships": {...} }, ... ],
  43. "data": [{ ... "relationships": { "created_by": { "data": { "type":

    "user", "id": "199" } }, "epics": { "data": [ { "type": "epic", "id": "3101" } ], } } }, ... ],
  44. "included": [ { "type": "epic", "id": "3101", "attributes": { "created":

    "2018-06-28T22:50:45.885691Z", "name": "Ergonomic background extranet" }, "links": { "self": "https://example.com/api/v1/epics/3101" } }, { "type": "user", "id": "199", "attributes": {...} } ]
  45. Impressions?

  46. Flexibility Con gurable elds: GET https://example.com/api/v1/projects GET https://example.com/api/v1/projects \ ?included=comments

    GET https://example.com/api/v1/projects \ ?included=comments&fields[project]=name,comments
  47. Pagination List responses have next / prev links { "links":

    { "next": "https://example.com/api/v1/projects?cursor=cD0yMDE4L", "prev": null }, "data": [...], }
  48. Pagination List responses have next / prev links { "links":

    { "next": "https://example.com/api/v1/projects?cursor=cD0yMDE4L", "prev": null }, "data": [...], } Cursor-based pagination FTW (but YMMV).
  49. Errors

  50. Errors POST https://example.com/api/v1/projects { "errors": [ { "title": "Invalid Attribute",

    "detail": "Name must contain at least three letters.", "source": { "pointer": "/data/attributes/name" }, "code": "name_too_short", "status": "422" } ] }
  51. Special Cases For when you have LOTS of data

  52. Special Cases For when you have LOTS of data out-of-band

    approach
  53. GET https://example.com/api/v1/datasets/123 { "data": { "type": "dataset", "id": "123", "attributes":

    { "name": "CIFAR10 dataset", }, "links": { "data_tgz": "https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz", "self": "https://example.com/api/v1/datasets/123" } } }
  54. Standardization Matters the speci c standard isn't that important GraphQL,

    etc are also good options
  55. Documentation

  56. Documentation Often overlooked

  57. Documentation Often overlooked Gives the rst impression

  58. Documentation Often overlooked Gives the rst impression The e ort

    is worth it!
  59. Creating Awesome Docs

  60. What Should Go In There?

  61. What Should Go In There? How do I access it?

  62. What Should Go In There? How do I access it?

    Do I need developer account?
  63. What Should Go In There? How do I access it?

    Do I need developer account? Root URL, etc
  64. What Should Go In There? How do I access it?

    Do I need developer account? Root URL, etc Authentication info
  65. What Should Go In There? General encodings, formats, etc

  66. What Should Go In There? General encodings, formats, etc Versioning,

    pagination, etc
  67. What Should Go In There? General encodings, formats, etc Versioning,

    pagination, etc Common errors
  68. What Should Go In There? General encodings, formats, etc Versioning,

    pagination, etc Common errors Code for getting started
  69. The Endpoints

  70. The Endpoints URL & operations

  71. The Endpoints URL & operations Request/response data

  72. The Endpoints URL & operations Request/response data Optional parameters

  73. The Endpoints URL & operations Request/response data Optional parameters Permissions

    etc
  74. Keep it Fresh!

  75. Keep it Fresh! Obsolete docs are the worst

  76. Keep it Fresh! Obsolete docs are the worst Always autogenerate!

  77. Keep it Fresh! Obsolete docs are the worst Always autogenerate!

    Usually code » schema » docs
  78. Schema & Autogeneration

  79. Schema & Autogeneration OpenAPI, Swagger, etc

  80. Schema & Autogeneration OpenAPI, Swagger, etc Use your tools

  81. Schema & Autogeneration OpenAPI, Swagger, etc Use your tools Combine

    docs & code examples
  82. Schema & Autogeneration OpenAPI, Swagger, etc Use your tools Combine

    docs & code examples Client libs autogeneration
  83. In Summary Embrace standards (e.g. JSON API) Invest in documentation

    Use automation Reduce friction
  84. Thanks! Rivo Laks ⋅ @rivolaks ⋅ rivolaks.com tinyurl.com/TODO