Successfully reported this slideshow.
Your SlideShare is downloading. ×

API Design - 3rd Edition

Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
API Design
3rd Edition



Brian Mulloy
@landlessness
Kevin Swiber     Apigee
@kevinswiber    @apigee
groups.google.com/group/api-craft
youtube.com/apigee

YouTube videos are no longer supported on SlideShare

View original on YouTube

Loading in …3
×

Check these out next

1 of 72 Ad
Advertisement

More Related Content

Slideshows for you (20)

Viewers also liked (20)

Advertisement

Similar to API Design - 3rd Edition (20)

More from Apigee | Google Cloud (20)

Advertisement

Recently uploaded (20)

API Design - 3rd Edition

  1. 1. API Design 3rd Edition Brian Mulloy @landlessness Kevin Swiber Apigee @kevinswiber @apigee
  2. 2. groups.google.com/group/api-craft
  3. 3. youtube.com/apigee
  4. 4. slideshare.net/apigee
  5. 5. @landlessness @kevinswiber
  6. 6. “ The real issue is about design: designing things that have the power required for the job while maintaining understandability, the feeling of control, and the pleasure of accomplishment. -Donald Norman
  7. 7. http://www.flickr.com/photos/mattharvey1/5712604622/
  8. 8. Agenda • Recap Previous Edition • API Modeling • Security • Message Design • Hypermedia • Transactions
  9. 9. http://offers.apigee.com/web-api-design-ebook/
  10. 10. URL Design Versioning Plural nouns for /dogs Include version in /v1/dogs collections URL ID for entity /dogs/1234 Keep one previous /v1/dogs version long /v2/dogs Associations /owners/5678/dogs enough for POST GET PUT DELETE developers to 4 HTTP migrate Methods Bias toward /dogs (not animals) concrete names Errors Multiple /dogs.json 8 Status Codes 200 201 304 400 401 403 404 500 formats in URL /dogs.xml Verbose messages {"msg": "verbose, plain language hints"} Paginate with ?limit=10&offset=0 limit and offset Query params ?color=red&state=running Client Considerations Partial selection ?fields=name,state Client does not ?suppress_response_codes=true Use medial "createdAt": 1320296464 support HTTP capitalization myObject.createdAt; status codes /convert?from=EUR&to=CNY&amoun Client does not GET /dogs?method=post Use verbs for GET /dogs non-resource t=100 support HTTP GET /dogs?method=put requests methods GET /dogs?method=delete Search /search?q=happy%2Blabrador Complement API 1. JavaScript with SDK and code 2. … DNS api.foo.com 3. … developers.foo.com libraries
  11. 11. How do we get started with our API?
  12. 12. Build an API Model http://www.flickr.com/photos/brent_nashville/2156695472/in/photostream/
  13. 13. Don’t Go Cowboy http://www.flickr.com/photos/theory/3364213389/in/photostream/
  14. 14. How do we secure our API?
  15. 15. Twitter Streaming API Authorization: Basic aWhlYXJ0OmFwaXM= Amazon Web Services API Authorization: AWS AKIAIOSFODNN7EXAMPLE:frJIUNo//yllqDzg= Google API Authorization: Bearer 1/fFBGRNJru1FQd44AzqT3Zg
  16. 16. OAuth2 Authorization: Bearer 1/fFBGRNJru1FQd44AzqT3Zg
  17. 17. How do approach message design?
  18. 18. Support multiple formats JSON and XML
  19. 19. Make JSON the default
  20. 20. How do we represent single items?
  21. 21. Twitter Foursquare Instagram { { { "created_at": "Thu Jan 10 08:44:59 "meta": {…}, "meta": {…}, +0000 2013", "notifications": […], "data": {} "id": 289291736440791040, "response": {} } "id_str": "289291736440791040", } "text": "@landlessness here's one for you: 50-year plan to fix Detroitnnhttp://t.co/kJ2l1FZv", "source": "<a href="http://twitter.com/download/andr oid" rel="nofollow">Twitter for Android</a>", "truncated": false, "in_reply_to_status_id": null, "in_reply_to_status_id_str": null, "in_reply_to_user_id": 41020312, "in_reply_to_user_id_str": "41020312", "in_reply_to_screen_name": "landlessness", "user": {…}, "geo": {…}, "coordinates": {…}, "place": {…}, "contributors”:{…}, "retweet_count": 0, "entities": {…}, "favorited": false, "retweeted": false, "possibly_sensitive": false } 21
  22. 22. Twitter Foursquare Instagram { { { "created_at": "Thu Jan 10 08:44:59 "meta": {…}, "meta": {…}, +0000 2013", "notifications": […], "data": { "id": 289291736440791040, "response": { "attribution": {…}, "id_str": "289291736440791040", "checkin": { "type": "image", "text": "@landlessness here's one "id": "50eeff78e4b0f8e9624ea5f8", "location": {…}, for you: 50-year plan to fix "createdAt": 1357840248, "comments": {…}, Detroitnnhttp://t.co/kJ2l1FZv", "type": "checkin", "filter": "Sierra", "source": "<a "shout": "Pharmacy #DRUGS!!! "created_time": "1357826573", href="http://twitter.com/download/andr #ToothPulled :(", "link": oid" rel="nofollow">Twitter for "timeZone": "America/Detroit", "http://instagr.am/p/UTk5Xut3gN/", Android</a>", "timeZoneOffset": -300, "likes": {…}, "truncated": false, "user": {…}, "images": {…}, "in_reply_to_status_id": null, "venue": {…}, "caption": {…}, "in_reply_to_status_id_str": null, "source": {…} "user_has_liked": false, "in_reply_to_user_id": 41020312, } "id": "365798266911553549_3573549", "in_reply_to_user_id_str": } "user": {…} "41020312", } } "in_reply_to_screen_name": } "landlessness", "user": {…}, "geo": {…}, "coordinates": {…}, "place": {…}, "contributors”:{…}, "retweet_count": 0, "entities": {…}, "favorited": false, "retweeted": false, "possibly_sensitive": false } 22
  23. 23. Take the best of Foursquare and Instagram { "meta": {…}, "dog": {…} "notifications": […], } 23
  24. 24. How do we represent collections?
  25. 25. Twitter Foursquare Instagram [ { { { "meta": {…}, "meta": {…}, "created_at": "Thu Jan 10 08:44:59 "notifications": […], "data": [ +0000 2013", "response": { { "id": 289291736440791040, "recent": [ "attribution": {…}, "id_str": "289291736440791040", { "type": "image", "text": "@landlessness here's one "id": "50eeff78e4b0f8e9624ea5f8", "location": {…}, for you: 50-year plan to fix "createdAt": 1357840248, "comments": {…}, Detroitnnhttp://t.co/kJ2l1FZv", "type": "checkin", "filter": "Sierra", "source": "<a "shout": "Pharmacy #DRUGS!!! "created_time": "1357826573", href="http://twitter.com/download/andr #ToothPulled :(", "link": oid" rel="nofollow">Twitter for "timeZone": "America/Detroit", "http://instagr.am/p/UTk5Xut3gN/", Android</a>", "timeZoneOffset": -300, "likes": {…}, "truncated": false, "user": {…}, "images": {…}, "in_reply_to_status_id": null, "venue": {…} "caption": {…}, "in_reply_to_status_id_str": null, }, "user_has_liked": false, "in_reply_to_user_id": 41020312, {…}, "id": "365798266911553549_3573549", "in_reply_to_user_id_str": {…}, "user": {…} "41020312", ] }, "in_reply_to_screen_name": } {…}, "landlessness", } {…} "user": {…}, ] "geo": {…}, } "coordinates": {…}, } "place": {…}, "contributors”:{…}, "retweet_count": 0, "entities": {…}, "favorited": false, "retweeted": false, "possibly_sensitive": false }, {…}, {…} ] 25
  26. 26. Take the best of Foursquare and Instagram { "meta": {…}, "dogs": {…} /* include same info as single */ "notifications": […], } 26
  27. 27. How do we represent search results?
  28. 28. “ Selecting results is not the same as searching. -Facebook API
  29. 29. Bing Search Google Custom Search Reddit Search { { { "SearchResponse": { "kind": "customsearch#search", "kind": "Listing", "Version": "2.2", "url": { "data": { "Query": { "type": "application/json", "after": "t3_qy342", "SearchTerms": "sushi" "template": "before": null, }, "https://www.googleapis.com/customsearch/v1?q={s "children": [ "Web": { earchTerms}…}, { "Total": 95200000, "queries": { "data": { "Offset": 0, "request": [ "id": "f605o", "Results": [ { "num_comments": 943, { "title": "Google Custom Search - sushi", "score": 1146, "Title": "The Sushi FAQ - The ultimate "totalResults": "15000000", "ups": 3110, guide to sushi and sashimi and how to ...", "searchTerms": "sushi", "downs": 1964, "Description": "What is sushi?..", "count": 10, "created": 1295553753.0, "Url": "http://www.sushifaq.com/", "startIndex": 1, "url": "CacheUrl": } "http://www.reddit.com/r/AskReddit/comments/f605 "http://cc.bingj.com/cache.aspx?q=sushi&d=485519 ] o/this_is_a_long_shot_any_sushi_chefs_need_a_job 0808495712&w=yU8fJS-YPT-f4svREMW2xSa75OoBUAZR", }, _in/", "DisplayUrl": "www.sushifaq.com", "context": { "author": "jining", "DateTime": "2013-01-08T15:12:00Z" "title": "Custom Search" } }, }, }, { "searchInformation": { { "Title": "What Is Sushi? - Sushi Guide - "searchTime": 0.314942, "data": { Eatsushi.com", "formattedSearchTime": "0.31", "id": "c9eng”, "Description": "Eatsushi.com...", "totalResults": "15000000", "num_comments": 308, "Url": "formattedTotalResults": "15,000,000" "score": 59, "http://www.eatsushi.com/whatsushi.asp", }, "ups": 128, "CacheUrl": "items": [ "downs": 69, "http://cc.bingj.com/cache.aspx?q=sushi&d=501324 { "created": 1275155900.0, 9854931333&w=ihBzI9k9WbrnwxKcV3n8mOoV97M89K-b", "kind": "customsearch#result", "url": "DisplayUrl": "title": "Standardized Usage Statistics "http://www.reddit.com/r/IAmA/comments/c9eng/i_a "www.eatsushi.com/whatsushi.asp", Harvesting Initiative (SUSHI ... - NISO", m_a_sushi_man_ama/", "DateTime": "2013-01-07T13:51:00Z" "htmlTitle": "u003cbu003eStandardized Usage "saved": false, "is_self": true, "permalink": } Statistics Harvesting Initiativeu003c/bu003e "/r/IAmA/comments/c9eng/i_am_a_sushi_man_ama/", ] (u003cbu003eSUSHIu003c/bu003e "author": "IAmASushiMan” } u003cbu003e...u003c/bu003e - NISO", } } "link": } } "http://www.niso.org/workrooms/sushi", ] "displayLink": "www.niso.org", } "snippet": "The Standardized Usage Statistics } Harvesting Initiative (SUSHI) Protocol standard (ANSI/NISO Z39.93-2007) defines an automated request and response model ...”, 29
  30. 30. (Mostly) Follow Google Custom Search { "meta": { "limit": 1, "offset": 10, "totalResults": 15000000, "query": "sushi", "searchTime": 0.314942 }, "results": [ {}, {}, {} ] } 30
  31. 31. How do we represent links?
  32. 32. Netflix API <link href=“http://api-public.netflix.com/catalog/people/100637” rel=“http://schemas.netflix.com/catalog/person.actor” title="Elijah Wood” ></link> GitHub API "organization": { "login": "octocat", "id": 1, "url": "https://api.github.com/users/octocat", "type": "Organization” }
  33. 33. Follow Netflix and the Web Linking spec <link href=“http://api-public.netflix.com/catalog/people/100637” rel=“http://schemas.netflix.com/catalog/person.actor” title="Elijah Wood” ></link>
  34. 34. How do we represent actions?
  35. 35. GitHub Form-based API ”actions": [{ “name”: “edit-repo”, “method”: “PATCH”, “href”: “https://api.github.com/repos/kevinswiber/siren”, ”fields”: [ { “name”: “name”, “type”: “text” }, { “name”: “description”, “type”: “text” } }]
  36. 36. Form-based API "actions": [{ "name": "edit-repo", “method”: “PATCH”, “href”: “https://api.github.com/repos/kevinswiber/siren”, ”fields”: [ { “name”: “name”, “type”: “text” }, { “name”: “description”, “type”: “text” } }]
  37. 37. How do we represent metadata?
  38. 38. Flickr API (inline) <item type="photo” id="10289” server="2” views="47” faves="0” more="0"> Dropbox API (/metadata) { "size": "225.4KB”, "rev": "35e97029684fe”, "bytes": 230783, "modified": "Tue, 19 Jul 2011 21:55:38 +0000”, "path": "/Getting_Started.pdf”, "is_dir": false, "icon": "page_white_acrobat”, "root": "dropbox”, "mime_type": "application/pdf”, "revision": 220823 }
  39. 39. Include a metadata in responses and consider a dedicated /meta resource { "meta": { "size": "225.4KB”, "rev": "35e97029684fe”, "bytes": 230783, "modified": "Tue, 19 Jul 2011 21:55:38 +0000”, "path": "/Getting_Started.pdf”, "is_dir": false, "icon": "page_white_acrobat”, "root": "dropbox”, "mime_type": "application/pdf”, "revision": 220823 } } 39
  40. 40. What can we learn from hypermedia types?
  41. 41. Atom/AtomPub <?xml version="1.0"?> <entry xmlns="http://www.w3.org/2005/Atom"> <title>My New Collection</title> <id>urn:uuid:de46e3a1-e489-41a6-88a6-21e7f0e8e2d8</id> <updated>2009-06-12T12:13:46Z</updated> <author> <name>Daffy</name> </author> <summary type="text" /> <content type="application/atom+xml;type=feed" src="http://example.org/my-new-collection"/> <link rel="edit” href="http://example.org/my-new-collection.atom" /> </entry>
  42. 42. XHTML <ul class=“search user-list”> <li class=“user”> <div class="avatar"> <a href="/users/@kevin"> <img class=”user-image" src=”/img/avatar.png" /> </a> </div> <div> <a href=“/users/@kevin” rel=“user messages”> <span class=“user-name”>@kevin</span> (<span class="user-text">@kevin</span>) </a> </div> </li> </ul>
  43. 43. HAL { “currentlyProcessing”: 14 “shippedToday”: 20, “_links”: { “self”: { “href”: “/orders?page=2” }, “next”: { “href”: “/orders?page=3” }, “prev”: { “href”: “/orders?page=1” } } }
  44. 44. Collection+JSON { “collection”: { “version”: “1.0”, “href”: “http://example.org/friends”, “items”: [ “href”: “http://example.org/friends/kevin”, “data”: [ {“name”: “full-name”, “value”: “Kevin Swiber” } ] ], “queries”: [ {“rel”: “search”, “href”: “./search”, “data”: [ {“name”: “search”, “value”: “” } ] } }
  45. 45. Siren { “class”: [“owner”, “vip”], “properties”: { “name”: “Kevin” }, “entities”: [ { “rel”: [“https://rels.x.io/dog”], “href”: “https://api.x.io/dogs/1” } ], “actions”: [ { “name”: “adopt”, “method”: “POST”, “href”: “https://api.x.io/owners/1/dogs”, “fields”: [ { “name”: “dog-name”, “type”: “text” } ] } ], “links”: [ { “rel”: [“self”], “href”: “https://api.x.io/owners/1” } ] }
  46. 46. How do we accept binary data?
  47. 47. multipart/form-data Content-Type: multipart/form-data; boundary=AaB03x --AaB03x Content-Disposition: form-data; name=“caption” Cool picture of my cat. --AaB03x Content-Disposition: form-data; name=“photo”; filename=“catpajamas.jpg” Content-Type: image/jpeg Content-Transfer-Encoding: binary …contents of catpajamas.jpg… --AaB03x
  48. 48. Inline Base64 Encoding POST /photos { “caption”: “Cool picture of my cat.” “photo”: “RHVkZSwgbXkgY2F0IGhhcyB0aGUgYmVzdCBwYWphbWFzLg==” }
  49. 49. 2-Step Process POST /photos { “caption”: “Cool picture of my cat.” } PUT /photos/1234/data Content-Type: image/jpeg Content-Length: 240 Content-Transfer-Encoding: binary …binary content…
  50. 50. Opt for multipart/form-data. Be consistent.
  51. 51. How do we support caching?
  52. 52. Expiration 200 OK Cache-Control: private, max-age=2592000
  53. 53. ETags GET /dogs/1 ETag: “a7D92kda94aisdfG” GET /dogs/1 If-None-Match: “a7D92kda94aisdfG”
  54. 54. Last-Modified GET /dogs/1 Last-Modified: Thu, 10 Jan 2013 19:43:31 GMT GET /dogs/1 If-Modified-Since: Thu, 10 Jan 2013 19:43:31 GMT
  55. 55. Think about the client.
  56. 56. Do we need a JavaScript API?
  57. 57. Yes. Follow LinkedIn’s lead.
  58. 58. What about posting data?
  59. 59. application/x-www-form-urlencoded breed=Dachshund&name=Hotdog&age=2
  60. 60. application/xml <dog> <breed>Dachshund</breed> <name>Hotdog</name> <age>2</age> </dog>
  61. 61. application/json { “breed”: “Dachshund”, “name”: “Hotdog”, “age”: 2 }
  62. 62. Favor application/x-www-form-urlencoded data.
  63. 63. How do we handle transactions?
  64. 64. Create a Transaction POST /carts … 201 Created Location: /carts/1
  65. 65. Add Items POST /carts/1/items/ { “productId”: “mittens123”, “quantity”: 1 } … 201 Created Location: /cartItems/1234
  66. 66. Commit the Transaction POST /carts/1 { “message”: “checkout” } … 200 OK
  67. 67. Summary • Checkout previous editions for URI design • Start with API modeling • Use OAuth for security • Good message design is for developers • Learn from hypermedia specs • More on transactions later
  68. 68. Questions?
  69. 69. THANK YOU Subscribe to API webinars at: youtube.com/apigee
  70. 70. THANK YOU Questions and ideas to: groups.google.com/group/api-craft
  71. 71. THANK YOU Contact us at: @landlessness brian@apigee.com @kevinswiber kswiber@apigee.com @apigee

Editor's Notes

  • Creative Commons Attribution-Share Alike 3.0 United States License
  • “The argument is not between adding features and simplicity, between adding capability and usability. The real issue is about design: designing things that have the power required for the job while maintaining understandability, the feeling of control, and the pleasure of accomplishment.” – Donald Norman, “Simplicity Is Not The Answer”, ACM Interactions, volume 15, issue 5. “We are faced with an apparent paradox, but don&apos;t worry: good design will see us through. People want the extra power that increased features bring to a product, but they intensely dislike the complexity that results. Is this a paradox? Not necessarily. Complexity can be managed. “ – Donald Norman, “Simplicity Is Not the Answer”, ACM Interactions, volume 15, issue 5.
  • http://www.flickr.com/photos/mattharvey1/5712604622/We’re building a cathedral. Though it is complex, it must be beautiful.
  • What security measures can we put around our API?
  • http://www.flickr.com/photos/brent_nashville/2156695472/in/photostream/Collaborate with all stakeholders: marketing, business analysts, software engineers, key business people, etc. This will be your API team.Develop a ubiquitous language, a glossary of terms that will appear in your API. This keeps everyone on the same page.Document a mental model of your API. (How you do this is up to you. See: UML)Iterate.
  • http://www.flickr.com/photos/theory/3364213389/in/photostream/Freedom is fantastic until you hit the wall of reality. Your API represents your organization. Make sure your organization is present on key decisions.
  • What security measures can we put around our API?
  • Twitter uses HTTP Basic authentication. It has been around for a long time.Amazon Web Services chose to roll their own. This may have pre-dated the OAuth 1.0 specification.Google is using Bearer tokens with the OAuth 2.0 Framework specification.
  • We like OAuth2. It’s a standard, which means anyone can read how it’s done. There are also good libraries out there to help build this for your API.OAuth2 allows developers to build clients that take advantage of user resources located on other services, such as Facebook, Google, and GitHub.A good alternative is using OAuth 1.0a. LinkedIn uses OAuth 1.0a for authorizing clients in their API, and it works very well.Keep an eye on stronger access token algorithms. OAuth2 MAC token support is still an Internet-Draft.
  • What security measures can we put around our API?
  • What security measures can we put around our API?
  • What security measures can we put around our API?
  • What security measures can we put around our API?
  • What security measures can we put around our API?
  • What security measures can we put around our API?
  • What security measures can we put around our API?
  • What security measures can we put around our API?
  • What security measures can we put around our API?
  • What security measures can we put around our API?
  • What security measures can we put around our API?
  • What security measures can we put around our API?
  • What security measures can we put around our API?
  • What security measures can we put around our API?
  • Netflix uses Web Linking (RFC5899). Links have a relation value that may contain standard or custom relation types. An href is included as a link to follow based on that rel value.GitHub repos contain an organization object that has a URL one can follow. Note: GitHub does follow the Web Linking spec for certain links. They include a Link header with prev and next links.
  • We prefer the Web Linking style, which can be expressed in both XML and JSON styles. It adheres to a standard that anyone can follow. Also, we can utilize the standard link relations where appropriate.
  • GitHub’s API prefers an out-of-band approach. The alternative is based on HTML forms. Here’s a snippet of the Siren format using actions.
  • Inline form-style actions provide greater insight to developers exploring the API via HTTP. It allows the server to maintain control of the preferred method, href, and fields. This approach allows for easier inclusion of hidden field values the server deems necessary. Note: This is still emerging and is not yet widespread.
  • Flickr includes metadata such as number of views, server, and favorites inline with the data representation. Dropbox has a separate metadata resource that returns its metadata.
  • Actually, we think both these options are good. If the amount of metadata is relatively small, including it inline makes a lot of sense, as it’s less overhead than creating a brand new resource.If metadata happens to be very large, as may be the case for Dropbox, adding a separate resource may make sense. At this point, the metadata itself may be important enough to your API consumers to warrant a new resource. This is a good topic for discussion during an API modeling exercise.Metadata can also include response times, pagination counts, etc.
  • Simultaneous presentation of information and controls such that the information becomes the affordance through which the user obtains choices and selects actions.Not a linear progression, more of a directed acyclic graph.Offers choices for users to select actions.Offers links to related representations.
  • ALPS example from rstat.us.
  • ALPS example from rstat.us.
  • Links, Queries, Write Templates
  • Properties, Entities, Actions, Links
  • Benefits: Only one HTTP call. Binary files can be sent in binary format—more compact than base64. HTTP tools to handle this.
  • Benefits: Quick to implement. Good for small files.
  • Benefits: Good for larger binary files.
  • Just choose one method of submitting binary data in your API. Think about the options, how big your binary data will be, and where you want to go in the future. Even though there are trade-offs to each approach, they’re all capable.
  • 30 Days
  • Yes, it’s important to not beat up your API server with requests. It’s also important to let client knows if they can save a round-trip to your server.

×