Beautiful REST + JSON APIs

Les Hazlewood @lhazlewood
CTO, Stormpath
stormpath.com
.com
• Identity Management and
Access Control API
• Security for your applications
• User security workflows
• Security be...
Outline
• APIs, REST & JSON
• REST Fundamentals
• Design
Base URL
Versioning
Resource Format
Return Values
Content Negotia...
APIs
•
•
•
•
•

Applications
Developers
Pragmatism over Ideology
Adoption
Scale

Learn more at Stormpath.com
Why REST?
•
•
•
•
•
•

Scalability
Generality
Independence
Latency (Caching)
Security
Encapsulation

Learn more at Stormpa...
Why JSON?
•
•
•
•
•

Ubiquity
Simplicity
Readability
Scalability
Flexibility

Learn more at Stormpath.com
HATEOAS
•
•
•
•
•
•
•

Hypermedia
As
The
Engine
Of
Application
State

Further restriction on REST architectures.
Learn mor...
REST Is Easy

Learn more at Stormpath.com
REST Is *&@#$! Hard
(for providers)

Learn more at Stormpath.com
REST can be easy
(if you follow some guidelines)

Learn more at Stormpath.com
Example Domain: Stormpath
•
•
•
•
•
•

Applications
Directories
Accounts
Groups
Associations
Workflows
Fundamentals

Learn more at Stormpath.com
Resources
Nouns, not Verbs
Coarse Grained, not Fine Grained
Architectural style for use-case scalability

Learn more at St...
What If?
/getAccount
/createDirectory
/updateGroup
/verifyAccountEmailAddress
Learn more at Stormpath.com
What If?
/getAccount
/getAllAccounts
/searchAccounts
/createDirectory
/createLdapDirectory
/updateGroup
/updateGroupName
/...
Keep It Simple

Learn more at Stormpath.com
The Answer
Fundamentally two types of resources:
Collection Resource
Instance Resource

Learn more at Stormpath.com
Collection Resource

/applications

Learn more at Stormpath.com
Instance Resource

/applications/a1b2c3

Learn more at Stormpath.com
Behavior
•
•
•
•
•

GET
PUT
POST
DELETE
HEAD

Learn more at Stormpath.com
Behavior
POST, GET, PUT, DELETE

≠ 1:1
Create, Read, Update, Delete

Learn more at Stormpath.com
Behavior
As you would expect:
GET = Read
DELETE = Delete
HEAD = Headers, no Body

Learn more at Stormpath.com
Behavior
Not so obvious:
PUT and POST can both be used for
Create and Update

Learn more at Stormpath.com
PUT for Create
Identifier is known by the client:
PUT /applications/clientSpecifiedId
{
…

}

Learn more at Stormpath.com
PUT for Update
Full Replacement
PUT /applications/existingId
{
“name”: “Best App Ever”,
“description”: “Awesomeness”
}
Lea...
PUT

Idempotent

Learn more at Stormpath.com
POST as Create
On a parent resource
POST /applications
{
“name”: “Best App Ever”
}
Response:
201 Created
Location: https:/...
POST as Update
On instance resource
POST /applications/a1b2c3

{
“name”: “Best App Ever. Srsly.”
}

Response:
200 OK

Lear...
POST

NOT Idempotent

Learn more at Stormpath.com
Media Types
• Format Specification + Parsing Rules
• Request: Accept header
• Response: Content-Type header
•
•
•
•

appli...
Design Time!

Learn more at Stormpath.com
Base URL

Learn more at Stormpath.com
http(s)://api.foo.com
vs
http://www.foo.com/dev/service/api/rest

Learn more at Stormpath.com
http(s)://api.foo.com
Rest Client
vs
Browser
Learn more at Stormpath.com
Versioning

Learn more at Stormpath.com
URL
https://api.stormpath.com/v1
vs.
Media-Type
application/foo+json;application&v=1
Learn more at Stormpath.com
Resource Format

Learn more at Stormpath.com
Media Type
Content-Type: application/json
When time allows:
application/foo+json
application/foo+json;bar=baz&v=1

…
Learn...
camelCase
„JS‟ in „JSON‟ = JavaScript
myArray.forEach
Not myArray.for_each
account.givenName
Not account.given_name

Under...
Date/Time/Timestamp
There‟s already a standard. Use it: ISO 8601
Example:
{
…,
“createdTimestamp”: “2012-07-10T18:02:24.34...
Response Body

Learn more at Stormpath.com
GET obvious
What about POST?

Return the representation in the response
when feasible.
Add override (?_body=false) for con...
Content Negotiation

Learn more at Stormpath.com
Header
• Accept header
• Header values comma delimited in order
of preference
GET /applications/a1b2c3
Accept: application...
Resource Extension
/applications/a1b2c3.json
/applications/a1b2c3.csv
…
Conventionally overrides Accept header

Learn more...
HREF
• Distributed Hypermedia is paramount!
• Every accessible Resource has a
canonical unique URL
• Replaces IDs (IDs exi...
Instance w/ HREF (v1)
GET /accounts/x7y8z9
200 OK
{
“href”: “https://api.stormpath.com/v1/accounts/x7y8z9”,
“givenName”: “...
Resource References
aka „Linking‟
(v1)

Learn more at Stormpath.com
• Hypermedia is paramount.
• Linking is fundamental to scalability.
• Tricky in JSON
• XML has it (XLink), JSON doesn‟t
• ...
Instance Reference (v1)
GET /accounts/x7y8z9
200 OK
{
“href”: “https://api.stormpath.com/v1/accounts/x7y8z9”,
“givenName”:...
Instance Reference (v1)
GET /accounts/x7y8z9
200 OK
{
“href”: “https://api.stormpath.com/v1/accounts/x7y8z9”,
“givenName”:...
Collection Reference (v1)
GET /accounts/x7y8z9
200 OK
{
“href”: “https://api.stormpath.com/v1/accounts/x7y8z9”,
“givenName...
Linking v2
(recommended)

Learn more at Stormpath.com
Instance HREF (v2)
GET /accounts/x7y8z9
200 OK
{
“meta”: {
“href”: “https://api.stormpath.com/v1/accounts/x7y8z9”,
“mediaT...
Instance Reference (v2)
GET /accounts/x7y8z9
200 OK
{
“meta”: { ... },
“givenName”: “Tony”,
“surname”: “Stark”,
…,
“direct...
Collection Reference (v2)
GET /accounts/x7y8z9
200 OK
{
“meta”: { ... },
“givenName”: “Tony”,
“surname”: “Stark”,
…,
“grou...
Reference Expansion
(aka Entity Expansion, Link Expansion)

Learn more at Stormpath.com
Account and its Directory?

Learn more at Stormpath.com
GET /accounts/x7y8z9?expand=directory
200 OK
{
“meta”: {...},
“givenName”: “Tony”,
“surname”: “Stark”,
…,
“directory”: {
“...
Partial Representations

Learn more at Stormpath.com
GET
/accounts/x7y8z9?fields=givenName,surname,
directory(name)

Learn more at Stormpath.com
Pagination

Learn more at Stormpath.com
Collection Resource supports query params:
• Offset
• Limit
…/applications?offset=50&limit=25

Learn more at Stormpath.com
GET /accounts/x7y8z9/groups
200 OK
{
“meta”: { ... },
“offset”: 0,
“limit”: 25,
“first”: { “meta”:{“href”: “…/accounts/x7y...
Many To Many

Learn more at Stormpath.com
Group to Account
• A group can have many accounts
• An account can be in many groups
• Each mapping is a resource:
GroupMe...
GET /groupMemberships/23lk3j2j3
200 OK
{
“meta”:{“href”: “…/groupMemberships/23lk3j2j3”},
“account”: {
“meta”:{“href”: “…”...
GET /accounts/x7y8z9
200 OK
{
“meta”:{“href”: “…/accounts/x7y8z9”},
“givenName”: “Tony”,
“surname”: “Stark”,
…,
“groups”: ...
Errors

Learn more at Stormpath.com
• As descriptive as possible
• As much information as possible
• Developers are your customers

Learn more at Stormpath.co...
POST /directories
409 Conflict
{
“status”: 409,
“code”: 40924,
“property”: “name”,
“message”: “A Directory named „Avengers...
Security

Learn more at Stormpath.com
Avoid sessions when possible
Authenticate every request if necessary
Stateless
Authorize based on resource content, NOT UR...
401 vs 403
• 401 “Unauthorized” really means
Unauthenticated
“You need valid credentials for me to respond to
this request...
HTTP Authentication Schemes
• Server response to issue challenge:
WWW-Authenticate: <scheme name>
realm=“Application Name”...
API Keys
•
•
•
•
•
•

Entropy
Password Reset
Independence
Speed
Limited Exposure
Traceability

Learn more at Stormpath.com
IDs

Learn more at Stormpath.com
• IDs should be opaque
• Should be globally unique
• Avoid sequential numbers (contention,
fusking)
• Good candidates: UUI...
HTTP Method Overrides

Learn more at Stormpath.com
POST /accounts/x7y8z9?_method=DELETE

Learn more at Stormpath.com
Caching &
Concurrency Control

Learn more at Stormpath.com
Server (initial response):
ETag: "686897696a7c876b7e”

Client (later request):
If-None-Match: "686897696a7c876b7e”

Server...
Maintenance

Learn more at Stormpath.com
Use HTTP Redirects
Create abstraction layer / endpoints when
migrating
Use well defined custom Media Types

Learn more at ...
.com
• Free for developers
• Eliminate months of development
• Automatic security best practices

Sign Up Now: Stormpath.c...
Upcoming SlideShare
Loading in...5
×

Design Beautiful REST + JSON APIs

150,340

Published on

Les Hazlewood, Stormpath co-founder and CTO and the Apache Shiro PMC Chair demonstrates how to design a beautiful REST + JSON API. Includes the principles of RESTful design, how REST differs from XML, tips for increasing adoption of your API, and security concerns.

Presentation video: https://www.youtube.com/watch?v=5WXYw4J4QOU
More info: http://www.stormpath.com/blog/designing-rest-json-apis
Further reading: http://www.stormpath.com/blog

Stormpath is a user management and authentication service for developers. By offloading user management and authentication to Stormpath, developers can bring applications to market faster, reduce development costs, and protect their users. Easy and secure, the flexible cloud service can manage millions of users with a scalable pricing model.

Published in: Technology, Design
8 Comments
318 Likes
Statistics
Notes
  • Awesome!
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • very detail, everything be concerned but want to more deep into it...
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • What would be the appropriate style/format to do an Update (via PUT) where it is not applied to a single object (e.g. not PUT collection/), but an update (PUT) over a number of objects (trying to minimize the number of trips, when we have an array of updates to be applied.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Nice, simple presentation illustrating common best practices.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • @banq lol
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total Views
150,340
On Slideshare
0
From Embeds
0
Number of Embeds
52
Actions
Shares
0
Downloads
2,960
Comments
8
Likes
318
Embeds 0
No embeds

No notes for slide

Design Beautiful REST + JSON APIs

  1. 1. Beautiful REST + JSON APIs Les Hazlewood @lhazlewood CTO, Stormpath stormpath.com
  2. 2. .com • Identity Management and Access Control API • Security for your applications • User security workflows • Security best practices • Developer tools, SDKs, libraries
  3. 3. Outline • APIs, REST & JSON • REST Fundamentals • Design Base URL Versioning Resource Format Return Values Content Negotiation References (Linking) Pagination Query Parameters Associations Errors IDs Method Overloading Resource Expansion Partial Responses Caching & Etags Security Multi Tenancy Maintenance
  4. 4. APIs • • • • • Applications Developers Pragmatism over Ideology Adoption Scale Learn more at Stormpath.com
  5. 5. Why REST? • • • • • • Scalability Generality Independence Latency (Caching) Security Encapsulation Learn more at Stormpath.com
  6. 6. Why JSON? • • • • • Ubiquity Simplicity Readability Scalability Flexibility Learn more at Stormpath.com
  7. 7. HATEOAS • • • • • • • Hypermedia As The Engine Of Application State Further restriction on REST architectures. Learn more at Stormpath.com
  8. 8. REST Is Easy Learn more at Stormpath.com
  9. 9. REST Is *&@#$! Hard (for providers) Learn more at Stormpath.com
  10. 10. REST can be easy (if you follow some guidelines) Learn more at Stormpath.com
  11. 11. Example Domain: Stormpath • • • • • • Applications Directories Accounts Groups Associations Workflows
  12. 12. Fundamentals Learn more at Stormpath.com
  13. 13. Resources Nouns, not Verbs Coarse Grained, not Fine Grained Architectural style for use-case scalability Learn more at Stormpath.com
  14. 14. What If? /getAccount /createDirectory /updateGroup /verifyAccountEmailAddress Learn more at Stormpath.com
  15. 15. What If? /getAccount /getAllAccounts /searchAccounts /createDirectory /createLdapDirectory /updateGroup /updateGroupName /findGroupsByDirectory /searchGroupsByName /verifyAccountEmailAddress /verifyAccountEmailAddressByToken … Smells like bad RPC. DON‟T DO THIS. Learn more at Stormpath.com
  16. 16. Keep It Simple Learn more at Stormpath.com
  17. 17. The Answer Fundamentally two types of resources: Collection Resource Instance Resource Learn more at Stormpath.com
  18. 18. Collection Resource /applications Learn more at Stormpath.com
  19. 19. Instance Resource /applications/a1b2c3 Learn more at Stormpath.com
  20. 20. Behavior • • • • • GET PUT POST DELETE HEAD Learn more at Stormpath.com
  21. 21. Behavior POST, GET, PUT, DELETE ≠ 1:1 Create, Read, Update, Delete Learn more at Stormpath.com
  22. 22. Behavior As you would expect: GET = Read DELETE = Delete HEAD = Headers, no Body Learn more at Stormpath.com
  23. 23. Behavior Not so obvious: PUT and POST can both be used for Create and Update Learn more at Stormpath.com
  24. 24. PUT for Create Identifier is known by the client: PUT /applications/clientSpecifiedId { … } Learn more at Stormpath.com
  25. 25. PUT for Update Full Replacement PUT /applications/existingId { “name”: “Best App Ever”, “description”: “Awesomeness” } Learn more at Stormpath.com
  26. 26. PUT Idempotent Learn more at Stormpath.com
  27. 27. POST as Create On a parent resource POST /applications { “name”: “Best App Ever” } Response: 201 Created Location: https://api.stormpath.com/applications/a1b2c3 Learn more at Stormpath.com
  28. 28. POST as Update On instance resource POST /applications/a1b2c3 { “name”: “Best App Ever. Srsly.” } Response: 200 OK Learn more at Stormpath.com
  29. 29. POST NOT Idempotent Learn more at Stormpath.com
  30. 30. Media Types • Format Specification + Parsing Rules • Request: Accept header • Response: Content-Type header • • • • application/json application/foo+json application/foo+json;application … Learn more at Stormpath.com
  31. 31. Design Time! Learn more at Stormpath.com
  32. 32. Base URL Learn more at Stormpath.com
  33. 33. http(s)://api.foo.com vs http://www.foo.com/dev/service/api/rest Learn more at Stormpath.com
  34. 34. http(s)://api.foo.com Rest Client vs Browser Learn more at Stormpath.com
  35. 35. Versioning Learn more at Stormpath.com
  36. 36. URL https://api.stormpath.com/v1 vs. Media-Type application/foo+json;application&v=1 Learn more at Stormpath.com
  37. 37. Resource Format Learn more at Stormpath.com
  38. 38. Media Type Content-Type: application/json When time allows: application/foo+json application/foo+json;bar=baz&v=1 … Learn more at Stormpath.com
  39. 39. camelCase „JS‟ in „JSON‟ = JavaScript myArray.forEach Not myArray.for_each account.givenName Not account.given_name Underscores for property/function names are unconventional for JS. Stay consistent. Learn more at Stormpath.com
  40. 40. Date/Time/Timestamp There‟s already a standard. Use it: ISO 8601 Example: { …, “createdTimestamp”: “2012-07-10T18:02:24.343Z” } Use UTC! Learn more at Stormpath.com
  41. 41. Response Body Learn more at Stormpath.com
  42. 42. GET obvious What about POST? Return the representation in the response when feasible. Add override (?_body=false) for control Learn more at Stormpath.com
  43. 43. Content Negotiation Learn more at Stormpath.com
  44. 44. Header • Accept header • Header values comma delimited in order of preference GET /applications/a1b2c3 Accept: application/json, text/plain Learn more at Stormpath.com
  45. 45. Resource Extension /applications/a1b2c3.json /applications/a1b2c3.csv … Conventionally overrides Accept header Learn more at Stormpath.com
  46. 46. HREF • Distributed Hypermedia is paramount! • Every accessible Resource has a canonical unique URL • Replaces IDs (IDs exist, but are opaque). • Critical for linking, as we‟ll soon see Learn more at Stormpath.com
  47. 47. Instance w/ HREF (v1) GET /accounts/x7y8z9 200 OK { “href”: “https://api.stormpath.com/v1/accounts/x7y8z9”, “givenName”: “Tony”, “surname”: “Stark”, ... } Learn more at Stormpath.com
  48. 48. Resource References aka „Linking‟ (v1) Learn more at Stormpath.com
  49. 49. • Hypermedia is paramount. • Linking is fundamental to scalability. • Tricky in JSON • XML has it (XLink), JSON doesn‟t • How do we do it? Learn more at Stormpath.com
  50. 50. Instance Reference (v1) GET /accounts/x7y8z9 200 OK { “href”: “https://api.stormpath.com/v1/accounts/x7y8z9”, “givenName”: “Tony”, “surname”: “Stark”, …, “directory”: ???? } Learn more at Stormpath.com
  51. 51. Instance Reference (v1) GET /accounts/x7y8z9 200 OK { “href”: “https://api.stormpath.com/v1/accounts/x7y8z9”, “givenName”: “Tony”, “surname”: “Stark”, …, “directory”: { “href”: “https://api.stormpath.com/v1/directories/g4h5i6” } } Learn more at Stormpath.com
  52. 52. Collection Reference (v1) GET /accounts/x7y8z9 200 OK { “href”: “https://api.stormpath.com/v1/accounts/x7y8z9”, “givenName”: “Tony”, “surname”: “Stark”, …, “groups”: { “href”: “https://api.stormpath.com/v1/accounts/x7y8z9/groups” } } Learn more at Stormpath.com
  53. 53. Linking v2 (recommended) Learn more at Stormpath.com
  54. 54. Instance HREF (v2) GET /accounts/x7y8z9 200 OK { “meta”: { “href”: “https://api.stormpath.com/v1/accounts/x7y8z9”, “mediaType”: “application/ion+json;version=2&schema=...” }, “givenName”: “Tony”, “surname”: “Stark”, … } Learn more at Stormpath.com
  55. 55. Instance Reference (v2) GET /accounts/x7y8z9 200 OK { “meta”: { ... }, “givenName”: “Tony”, “surname”: “Stark”, …, “directory”: { “meta”: { “href”: “https://api.stormpath.com/v1/directories/g4h5i6” “mediaType”: “application/ion+json;version=2&schema=...” } } } Learn more at Stormpath.com
  56. 56. Collection Reference (v2) GET /accounts/x7y8z9 200 OK { “meta”: { ... }, “givenName”: “Tony”, “surname”: “Stark”, …, “groups”: { “meta”: { “href”: “https://api.stormpath.com/v1/accounts/x7y8z9/groups”, “mediaType”: “application/ioncoll+json;version=2&schema=...” } } } Learn more at Stormpath.com
  57. 57. Reference Expansion (aka Entity Expansion, Link Expansion) Learn more at Stormpath.com
  58. 58. Account and its Directory? Learn more at Stormpath.com
  59. 59. GET /accounts/x7y8z9?expand=directory 200 OK { “meta”: {...}, “givenName”: “Tony”, “surname”: “Stark”, …, “directory”: { “meta”: { ... }, “name”: “Avengers”, “description”: “Hollywood’s hope for more $”, “creationDate”: “2012-07-01T14:22:18.029Z”, … } } Learn more at Stormpath.com
  60. 60. Partial Representations Learn more at Stormpath.com
  61. 61. GET /accounts/x7y8z9?fields=givenName,surname, directory(name) Learn more at Stormpath.com
  62. 62. Pagination Learn more at Stormpath.com
  63. 63. Collection Resource supports query params: • Offset • Limit …/applications?offset=50&limit=25 Learn more at Stormpath.com
  64. 64. GET /accounts/x7y8z9/groups 200 OK { “meta”: { ... }, “offset”: 0, “limit”: 25, “first”: { “meta”:{“href”: “…/accounts/x7y8z9/groups?offset=0”}}, “previous”: null, “next”: { “meta”:{“href”: “…/accounts/x7y8z9/groups?offset=25”}}, “last”: { “meta”:{“href”: “…”}}, “items”: [ { “meta”: { “href”: “…”, ...} }, { “meta”: { “href”: “…”, ...} }, … ] } Learn more at Stormpath.com
  65. 65. Many To Many Learn more at Stormpath.com
  66. 66. Group to Account • A group can have many accounts • An account can be in many groups • Each mapping is a resource: GroupMembership Learn more at Stormpath.com
  67. 67. GET /groupMemberships/23lk3j2j3 200 OK { “meta”:{“href”: “…/groupMemberships/23lk3j2j3”}, “account”: { “meta”:{“href”: “…”} }, “group”: { “meta”{“href”: “…”} }, … } Learn more at Stormpath.com
  68. 68. GET /accounts/x7y8z9 200 OK { “meta”:{“href”: “…/accounts/x7y8z9”}, “givenName”: “Tony”, “surname”: “Stark”, …, “groups”: { “meta”:{“href”: “…/accounts/x7y8z9/groups”} }, “groupMemberships”: { “meta”:{“href”: “…/groupMemberships?accountId=x7y8z9”} } } Learn more at Stormpath.com
  69. 69. Errors Learn more at Stormpath.com
  70. 70. • As descriptive as possible • As much information as possible • Developers are your customers Learn more at Stormpath.com
  71. 71. POST /directories 409 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 stale local cache, please expire it now.”, “moreInfo”: “https://www.stormpath.com/docs/api/errors/4092 4” } Learn more at Stormpath.com
  72. 72. Security Learn more at Stormpath.com
  73. 73. Avoid sessions when possible Authenticate every request if necessary Stateless Authorize based on resource content, NOT URL! Use Existing Protocol: Oauth 1.0a, Oauth2, Basic over SSL only Custom Authentication Scheme: Only if you provide client code / SDK Only if you really, really know what you‟re doing Use API Keys instead of Username/Passwords Learn more at Stormpath.com
  74. 74. 401 vs 403 • 401 “Unauthorized” really means Unauthenticated “You need valid credentials for me to respond to this request” • 403 “Forbidden” really means Unauthorized “I understood your credentials, but so sorry, you‟re not allowed!” Learn more at Stormpath.com
  75. 75. HTTP Authentication Schemes • Server response to issue challenge: WWW-Authenticate: <scheme name> realm=“Application Name” • Client request to submit credentials: Authorization: <scheme name> <data> Learn more at Stormpath.com
  76. 76. API Keys • • • • • • Entropy Password Reset Independence Speed Limited Exposure Traceability Learn more at Stormpath.com
  77. 77. IDs Learn more at Stormpath.com
  78. 78. • IDs should be opaque • Should be globally unique • Avoid sequential numbers (contention, fusking) • Good candidates: UUIDs, „Url64‟ Learn more at Stormpath.com
  79. 79. HTTP Method Overrides Learn more at Stormpath.com
  80. 80. POST /accounts/x7y8z9?_method=DELETE Learn more at Stormpath.com
  81. 81. Caching & Concurrency Control Learn more at Stormpath.com
  82. 82. Server (initial response): ETag: "686897696a7c876b7e” Client (later request): If-None-Match: "686897696a7c876b7e” Server (later response): 304 Not Modified Learn more at Stormpath.com
  83. 83. Maintenance Learn more at Stormpath.com
  84. 84. Use HTTP Redirects Create abstraction layer / endpoints when migrating Use well defined custom Media Types Learn more at Stormpath.com
  85. 85. .com • Free for developers • Eliminate months of development • Automatic security best practices Sign Up Now: Stormpath.com
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×