Beautiful REST and JSON APIs - Les Hazlewood

  • 830 views
Uploaded on

Designing a really clean and intuitive REST + JSON API is no small feat. You have to worry about resources, collections of resources, pagination, query parameters, references to other resources, which …

Designing a really clean and intuitive REST + JSON API is no small feat. You have to worry about resources, collections of resources, pagination, query parameters, references to other resources, which HTTP Methods to use, HTTP Caching, security, and more! And you have to make sure it lasts and doesn't break clients as you add features over time. Further, while there are many references on creating REST APIs with XML, there are many fewer references for REST + JSON.

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
830
On Slideshare
0
From Embeds
0
Number of Embeds
2

Actions

Shares
Downloads
0
Comments
0
Likes
14

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Beautiful REST + JSON APIsLes Hazlewood @lhazlewoodCTO, Stormpathstormpath.com
  • 2. .com• Identity Management andAccess Control API• Security for your applications• User security workflows• Security best practices• Developer tools, SDKs, libraries
  • 3. Outline• APIs, REST & JSON• REST Fundamentals• DesignBase URLVersioningResource FormatReturn ValuesContent NegotiationReferences (Linking)PaginationQuery ParametersAssociationsErrorsIDsMethod OverloadingResource ExpansionPartial ResponsesCaching & EtagsSecurityMulti TenancyMaintenance
  • 4. APIs• Applications• Developers• Pragmatism over Ideology• Adoption• Scale
  • 5. Why REST?• Scalability• Generality• Independence• Latency (Caching)• Security• Encapsulation
  • 6. Why JSON?• Ubiquity• Simplicity• Readability• Scalability• Flexibility
  • 7. HATEOAS• Hypermedia• As• The• Engine• Of• Application• StateFurther restriction on REST architectures.
  • 8. REST Is Easy
  • 9. REST Is *&@#$! Hard(for providers)
  • 10. REST can be easy(if you follow some guidelines)
  • 11. Example Domain: Stormpath• Applications• Directories• Accounts• Groups• Associations• Workflows
  • 12. Fundamentals
  • 13. ResourcesNouns, not VerbsCoarse Grained, not Fine GrainedArchitectural style for use-case scalability
  • 14. What If?/getAccount/createDirectory/updateGroup/verifyAccountEmailAddress
  • 15. What If?/getAccount/getAllAccounts/searchAccounts/createDirectory/createLdapDirectory/updateGroup/updateGroupName/findGroupsByDirectory/searchGroupsByName/verifyAccountEmailAddress/verifyAccountEmailAddressByToken…Smells like bad RPC. DON‟T DO THIS.
  • 16. Keep It Simple
  • 17. The AnswerFundamentally two types of resources:Collection ResourceInstance Resource
  • 18. Collection Resource/applications
  • 19. Instance Resource/applications/a1b2c3
  • 20. Behavior• GET• PUT• POST• DELETE• HEAD
  • 21. BehaviorPOST, GET, PUT, DELETE≠ 1:1Create, Read, Update, Delete
  • 22. BehaviorAs you would expect:GET = ReadDELETE = DeleteHEAD = Headers, no Body
  • 23. BehaviorNot so obvious:PUT and POST can both be used forCreate and Update
  • 24. PUT for CreateIdentifier is known by the client:PUT /applications/clientSpecifiedId{…}
  • 25. PUT for UpdateFull ReplacementPUT /applications/existingId{“name”: “Best App Ever”,“description”: “Awesomeness”}
  • 26. PUTIdempotent
  • 27. POST as CreateOn a parent resourcePOST /applications{“name”: “Best App Ever”}Response:201 CreatedLocation: https://api.stormpath.com/applications/a1b2c3
  • 28. POST as UpdateOn instance resourcePOST /applications/a1b2c3{“name”: “Best App Ever. Srsly.”}Response:200 OK
  • 29. POSTNOT Idempotent
  • 30. Media Types• Format Specification + Parsing Rules• Request: Accept header• Response: Content-Type header• application/json• application/foo+json• application/foo+json;application• …
  • 31. Design Time!
  • 32. Base URL
  • 33. http(s)://api.foo.comvshttp://www.foo.com/dev/service/api/rest
  • 34. http(s)://api.foo.comRest ClientvsBrowser
  • 35. Versioning
  • 36. URLhttps://api.stormpath.com/v1vs.Media-Typeapplication/json+foo;application&v=1
  • 37. Resource Format
  • 38. Media TypeContent-Type: application/jsonWhen time allows:application/foo+jsonapplication/foo+json;bar=baz&v=1…
  • 39. camelCase„JS‟ in „JSON‟ = JavaScriptmyArray.forEachNot myArray.for_eachaccount.givenNameNot account.given_nameUnderscores for property/function names areunconventional for JS. Stay consistent.
  • 40. Date/Time/TimestampThere‟s already a standard. Use it: ISO 8601Example:{…,“createdTimestamp”: “2012-07-10T18:02:24.343Z”}Use UTC!
  • 41. HREF• Distributed Hypermedia is paramount!• Every accessible Resource has a uniqueURL.• Replaces IDs (IDs exist, but are opaque).{“href”: https://api.stormpath.com/v1/accounts/x7y8z9”,…}Critical for linking, as we‟ll soon see
  • 42. Response Body
  • 43. GET obviousWhat about POST?Return the representation in the responsewhen feasible.Add override (?_body=false) for control
  • 44. Content Negotiation
  • 45. Header• Accept header• Header values comma delimited in orderof preferenceGET /applications/a1b2c3Accept: application/json, text/plain
  • 46. Resource Extension/applications/a1b2c3.json/applications/a1b2c3.csv…Conventionally overrides Accept header
  • 47. Resource Referencesaka „Linking‟
  • 48. • Hypermedia is paramount.• Linking is fundamental to scalability.• Tricky in JSON• XML has it (XLink), JSON doesn‟t• How do we do it?
  • 49. Instance ReferenceGET /accounts/x7y8z9200 OK{“href”: “https://api.stormpath.com/v1/accounts/x7y8z9”,“givenName”: “Tony”,“surname”: “Stark”,…,“directory”: ????}
  • 50. Instance ReferenceGET /accounts/x7y8z9200 OK{“href”: “https://api.stormpath.com/v1/accounts/x7y8z9”,“givenName”: “Tony”,“surname”: “Stark”,…,“directory”: {“href”: “https://api.stormpath.com/v1/directories/g4h5i6”}}
  • 51. Collection ReferenceGET /accounts/x7y8z9200 OK{“href”: “https://api.stormpath.com/v1/accounts/x7y8z9”,“givenName”: “Tony”,“surname”: “Stark”,…,“groups”: {“href”: “https://api.stormpath.com/v1/accounts/x7y8z9/groups”}}
  • 52. Reference Expansion(aka Entity Expansion, Link Expansion)
  • 53. Account and its Directory?
  • 54. GET /accounts/x7y8z9?expand=directory200 OK{“href”: “https://api.stormpath.com/v1/accounts/x7y8z9”,“givenName”: “Tony”,“surname”: “Stark”,…,“directory”: {“href”: “https://api.stormpath.com/v1/directories/g4h5i6”,“name”: “Avengers”,“creationDate”: “2012-07-01T14:22:18.029Z”,…}}
  • 55. Partial Representations
  • 56. GET/accounts/x7y8z9?fields=givenName,surname,directory(name)
  • 57. Pagination
  • 58. Collection Resource supports query params:• Offset• Limit…/applications?offset=50&limit=25
  • 59. GET /accounts/x7y8z9/groups200 OK{“href”: “…/accounts/x7y8z9/groups”,“offset”: 0,“limit”: 25,“first”: { “href”: “…/accounts/x7y8z9/groups?offset=0” },“previous”: null,“next”: { “href”: “…/accounts/x7y8z9/groups?offset=25” },“last”: { “href”: “…”},“items”: [{“href”: “…”},{“href”: “…”},…]}
  • 60. Many To Many
  • 61. Group to Account• A group can have many accounts• An account can be in many groups• Each mapping is a resource:GroupMembership
  • 62. GET /groupMemberships/23lk3j2j3200 OK{“href”: “…/groupMemberships/23lk3j2j3”,“account”: {“href”: “…”},“group”: {“href”: “…”},…}
  • 63. GET /accounts/x7y8z9200 OK{“href”: “…/accounts/x7y8z9”,“givenName”: “Tony”,“surname”: “Stark”,…,“groups”: {“href”: “…/accounts/x7y8z9/groups”},“groupMemberships”: {“href”: “…/groupMemberships?accountId=x7y8z9”}}
  • 64. Errors
  • 65. • As descriptive as possible• As much information as possible• Developers are your customers
  • 66. POST /directories409 Conflict{“status”: 409,“code”: 40924,“property”: “name”,“message”: “A Directory named „Avengers‟already exists.”,“developerMessage”: “A directory named„Avengers‟ already exists. If you have a stalelocal cache, please expire it now.”,“moreInfo”:“https://www.stormpath.com/docs/api/errors/40924”}
  • 67. Security
  • 68. Avoid sessions when possibleAuthenticate every request if necessaryStatelessAuthorize based on resource content, NOT URL!Use Existing Protocol:Oauth 1.0a, Oauth2, Basic over SSL onlyCustom Authentication Scheme:Only if you provide client code / SDKOnly if you really, really know what you‟re doingUse API Keys instead of Username/Passwords
  • 69. 401 vs 403• 401 “Unauthorized” really meansUnauthenticated“You need valid credentials for me to respond tothis request”• 403 “Forbidden” really means Unauthorized“I understood your credentials, but so sorry, you‟renot allowed!”
  • 70. HTTP Authentication Schemes• Server response to issue challenge:WWW-Authenticate: <scheme name>realm=“Application Name”• Client request to submit credentials:Authorization: <scheme name> <data>
  • 71. API Keys• Entropy• Password Reset• Independence• Speed• Limited Exposure• Traceability
  • 72. IDs
  • 73. • IDs should be opaque• Should be globally unique• Avoid sequential numbers(contention, fusking)• Good candidates: UUIDs, „Url64‟
  • 74. HTTP Method Overrides
  • 75. POST /accounts/x7y8z9?_method=DELETE
  • 76. Caching &Concurrency Control
  • 77. Server (initial response):ETag: "686897696a7c876b7e”Client (later request):If-None-Match: "686897696a7c876b7e”Server (later response):304 Not Modified
  • 78. Maintenance
  • 79. Use HTTP RedirectsCreate abstraction layer / endpoints whenmigratingUse well defined custom Media Types
  • 80. .com• Free for any application• Eliminate months of development• Automatic security best practicesSign Up Now: Stormpath.com