71
API Design 3 rd Edition Kevin Swiber @kevinswiber Apigee @apigee Brian Mulloy @landlessness

API Design - 3rd Edition

  • Upload
    apigee

  • View
    151

  • Download
    3

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: API Design - 3rd Edition

API Design3rd Edition

Kevin Swiber@kevinswiber

Apigee@apigee

Brian Mulloy@landlessness

Page 2: API Design - 3rd Edition

groups.google.com/group/api-craft

Page 3: API Design - 3rd Edition

youtube.com/apigee

Page 4: API Design - 3rd Edition

slideshare.net/apigee

Page 5: API Design - 3rd Edition

@landlessness @kevinswiber

Page 6: API Design - 3rd Edition

“ 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

Page 7: API Design - 3rd Edition

http://www.flickr.com/photos/mattharvey1/5712604622/

Page 8: API Design - 3rd Edition

Agenda

• Recap Previous Edition• API Modeling• Security• Message Design• Hypermedia• Transactions

Page 9: API Design - 3rd Edition

http://offers.apigee.com/web-api-design-ebook/

Page 10: API Design - 3rd Edition

URL DesignPlural nouns for collections

/dogs

ID for entity /dogs/1234

Associations /owners/5678/dogs

4 HTTP Methods

POST GET PUT DELETE

Bias toward concrete names

/dogs (not animals)

Multiple formats in URL

/dogs.json/dogs.xml

Paginate with limit and offset

?limit=10&offset=0

Query params ?color=red&state=running

Partial selection ?fields=name,state

Use medial capitalization

"createdAt": 1320296464myObject.createdAt;

Use verbs for non-resource requests

/convert?from=EUR&to=CNY&amount=100

Search /search?q=happy%2Blabrador

DNS api.foo.comdevelopers.foo.com

Errors8 Status Codes 200 201 304 400 401 403 404

500

Verbose messages {"msg": "verbose, plain language hints"}

VersioningInclude version in URL

/v1/dogs

Keep one previous version long enough for developers to migrate

/v1/dogs/v2/dogs

Client ConsiderationsClient does not support HTTP status codes

?suppress_response_codes=true

Client does not support HTTP methods

GET /dogs?method=postGET /dogsGET /dogs?method=putGET /dogs?method=delete

Complement API with SDK and code libraries

1. JavaScript2. …3. …

Page 11: API Design - 3rd Edition

How do we get started with our API?

Page 12: API Design - 3rd Edition

Build an API Model

http://www.flickr.com/photos/brent_nashville/2156695472/in/photostream/

Page 13: API Design - 3rd Edition

Don’t Go Cowboy

http://www.flickr.com/photos/theory/3364213389/in/photostream/

Page 14: API Design - 3rd Edition

How do we secure our API?

Page 15: API Design - 3rd Edition

Authorization: Basic aWhlYXJ0OmFwaXM=

Twitter Streaming API

Authorization: AWS AKIAIOSFODNN7EXAMPLE:frJIUNo//yllqDzg=

Amazon Web Services API

Authorization: Bearer 1/fFBGRNJru1FQd44AzqT3Zg

Google API

Page 16: API Design - 3rd Edition

Authorization: Bearer 1/fFBGRNJru1FQd44AzqT3Zg

OAuth2

Page 17: API Design - 3rd Edition

How do approach message design?

Page 18: API Design - 3rd Edition

Support multiple formats JSON and XML

Page 19: API Design - 3rd Edition

Make JSON the default

Page 20: API Design - 3rd Edition

How do we represent single items?

Page 21: API Design - 3rd Edition

21

Twitter Foursquare{ "meta": {…}, "data": {}}

Instagram{ "meta": {…}, "notifications": […], "response": {}}

{ "created_at": "Thu Jan 10 08:44:59 +0000 2013", "id": 289291736440791040, "id_str": "289291736440791040", "text": "@landlessness here's one for you: 50-year plan to fix Detroit\n\nhttp://t.co/kJ2l1FZv", "source": "<a href="http://twitter.com/download/android" 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}

Page 22: API Design - 3rd Edition

22

Twitter Foursquare{ "meta": {…}, "data": { "attribution": {…}, "type": "image", "location": {…}, "comments": {…}, "filter": "Sierra", "created_time": "1357826573", "link": "http://instagr.am/p/UTk5Xut3gN/", "likes": {…}, "images": {…}, "caption": {…}, "user_has_liked": false, "id": "365798266911553549_3573549", "user": {…} }}

Instagram{ "meta": {…}, "notifications": […], "response": { "checkin": { "id": "50eeff78e4b0f8e9624ea5f8", "createdAt": 1357840248, "type": "checkin", "shout": "Pharmacy #DRUGS!!! #ToothPulled :(", "timeZone": "America/Detroit", "timeZoneOffset": -300, "user": {…}, "venue": {…}, "source": {…} } }}

{ "created_at": "Thu Jan 10 08:44:59 +0000 2013", "id": 289291736440791040, "id_str": "289291736440791040", "text": "@landlessness here's one for you: 50-year plan to fix Detroit\n\nhttp://t.co/kJ2l1FZv", "source": "<a href="http://twitter.com/download/android" 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}

Page 23: API Design - 3rd Edition

23

Take the best of Foursquare and Instagram

{ "meta": {…}, "dog": {…} "notifications": […],}

Page 24: API Design - 3rd Edition

How do we represent collections?

Page 25: API Design - 3rd Edition

25

Twitter Foursquare{ "meta": {…}, "data": [ { "attribution": {…}, "type": "image", "location": {…}, "comments": {…}, "filter": "Sierra", "created_time": "1357826573", "link": "http://instagr.am/p/UTk5Xut3gN/", "likes": {…}, "images": {…}, "caption": {…}, "user_has_liked": false, "id": "365798266911553549_3573549", "user": {…} }, {…}, {…} ] }}

Instagram{ "meta": {…}, "notifications": […], "response": { "recent": [ { "id": "50eeff78e4b0f8e9624ea5f8", "createdAt": 1357840248, "type": "checkin", "shout": "Pharmacy #DRUGS!!! #ToothPulled :(", "timeZone": "America/Detroit", "timeZoneOffset": -300, "user": {…}, "venue": {…} }, {…}, {…}, ] }}

[ { "created_at": "Thu Jan 10 08:44:59 +0000 2013", "id": 289291736440791040, "id_str": "289291736440791040", "text": "@landlessness here's one for you: 50-year plan to fix Detroit\n\nhttp://t.co/kJ2l1FZv", "source": "<a href="http://twitter.com/download/android" 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 }, {…}, {…}]

Page 26: API Design - 3rd Edition

26

Take the best of Foursquare and Instagram

{ "meta": {…}, "dogs": {…} /* include same info as single */ "notifications": […],}

Page 27: API Design - 3rd Edition

How do we represent search results?

Page 28: API Design - 3rd Edition

“ Selecting results is not the same as searching.

-Facebook API

Page 29: API Design - 3rd Edition

29

Bing Search Google Custom Search{"kind": "Listing", "data": { "after": "t3_qy342", "before": null, "children": [ { "data": { "id": "f605o", "num_comments": 943, "score": 1146, "ups": 3110, "downs": 1964, "created": 1295553753.0, "url": "http://www.reddit.com/r/AskReddit/comments/f605o/this_is_a_long_shot_any_sushi_chefs_need_a_job_in/", "author": "jining", } }, { "data": { "id": "c9eng”, "num_comments": 308, "score": 59, "ups": 128, "downs": 69, "created": 1275155900.0, "url": "http://www.reddit.com/r/IAmA/comments/c9eng/i_am_a_sushi_man_ama/","saved": false, "is_self": true, "permalink": "/r/IAmA/comments/c9eng/i_am_a_sushi_man_ama/", "author": "IAmASushiMan” } } ] }}

Reddit Search{ "kind": "customsearch#search", "url": { "type": "application/json", "template": "https://www.googleapis.com/customsearch/v1?q={searchTerms}…}, "queries": { "request": [ { "title": "Google Custom Search - sushi", "totalResults": "15000000", "searchTerms": "sushi", "count": 10, "startIndex": 1, } ] }, "context": { "title": "Custom Search" }, "searchInformation": { "searchTime": 0.314942, "formattedSearchTime": "0.31", "totalResults": "15000000", "formattedTotalResults": "15,000,000" }, "items": [ { "kind": "customsearch#result", "title": "Standardized Usage Statistics Harvesting Initiative (SUSHI ... - NISO", "htmlTitle": "\u003cb\u003eStandardized Usage Statistics Harvesting Initiative\u003c/b\u003e (\u003cb\u003eSUSHI\u003c/b\u003e \u003cb\u003e...\u003c/b\u003e - 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 ...”,

{ "SearchResponse": { "Version": "2.2", "Query": { "SearchTerms": "sushi" }, "Web": { "Total": 95200000, "Offset": 0, "Results": [ { "Title": "The Sushi FAQ - The ultimate guide to sushi and sashimi and how to ...", "Description": "What is sushi?..", "Url": "http://www.sushifaq.com/", "CacheUrl": "http://cc.bingj.com/cache.aspx?q=sushi&d=4855190808495712&w=yU8fJS-YPT-f4svREMW2xSa75OoBUAZR", "DisplayUrl": "www.sushifaq.com", "DateTime": "2013-01-08T15:12:00Z" }, { "Title": "What Is Sushi? - Sushi Guide - Eatsushi.com", "Description": "Eatsushi.com...", "Url": "http://www.eatsushi.com/whatsushi.asp", "CacheUrl": "http://cc.bingj.com/cache.aspx?q=sushi&d=5013249854931333&w=ihBzI9k9WbrnwxKcV3n8mOoV97M89K-b", "DisplayUrl": "www.eatsushi.com/whatsushi.asp", "DateTime": "2013-01-07T13:51:00Z" } ] } }}

Page 30: API Design - 3rd Edition

30

(Mostly) Follow Google Custom Search

{ "meta": { "limit": 1, "offset": 10, "totalResults": 15000000, "query": "sushi", "searchTime": 0.314942 }, "results": [ {}, {}, {} ]}

Page 31: API Design - 3rd Edition

How do we represent links?

Page 32: API Design - 3rd Edition

<link href=“http://api-public.netflix.com/catalog/people/100637” rel=“http://schemas.netflix.com/catalog/person.actor” title="Elijah Wood”></link>

Netflix API

"organization": { "login": "octocat", "id": 1, "url": "https://api.github.com/users/octocat", "type": "Organization”}

GitHub API

Page 33: API Design - 3rd Edition

<link href=“http://api-public.netflix.com/catalog/people/100637” rel=“http://schemas.netflix.com/catalog/person.actor” title="Elijah Wood”></link>

Follow Netflix and the Web Linking spec

Page 34: API Design - 3rd Edition

How do we represent actions?

Page 35: API Design - 3rd Edition

GitHub

”actions": [{ “name”: “edit-repo”, “method”: “PATCH”, “href”: “https://api.github.com/repos/kevinswiber/siren”, ”fields”: [ { “name”: “name”, “type”: “text” }, { “name”: “description”, “type”: “text” }}]

Form-based API

Page 36: API Design - 3rd Edition

"actions": [{ "name": "edit-repo", “method”: “PATCH”, “href”: “https://api.github.com/repos/kevinswiber/siren”, ”fields”: [ { “name”: “name”, “type”: “text” }, { “name”: “description”, “type”: “text” }}]

Form-based API

Page 37: API Design - 3rd Edition

How do we represent metadata?

Page 38: API Design - 3rd Edition

<item type="photo” id="10289” server="2” views="47” faves="0” more="0">

Flickr API (inline)

{ "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}

Dropbox API (/metadata)

Page 39: API Design - 3rd Edition

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 }}

Page 40: API Design - 3rd Edition

What can we learn from hypermedia types?

Page 41: API Design - 3rd Edition

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>

Page 42: API Design - 3rd Edition

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>

Page 43: API Design - 3rd Edition

HAL

{ “currentlyProcessing”: 14 “shippedToday”: 20, “_links”: { “self”: { “href”: “/orders?page=2” }, “next”: { “href”: “/orders?page=3” }, “prev”: { “href”: “/orders?page=1” } }}

Page 44: API Design - 3rd Edition

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”: “” } ] }}

Page 45: API Design - 3rd Edition

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” } ]}

Page 46: API Design - 3rd Edition

How do we accept binary data?

Page 47: API Design - 3rd Edition

multipart/form-data

Content-Type: multipart/form-data; boundary=AaB03x

--AaB03xContent-Disposition: form-data; name=“caption”

Cool picture of my cat.--AaB03xContent-Disposition: form-data; name=“photo”; filename=“catpajamas.jpg”Content-Type: image/jpegContent-Transfer-Encoding: binary

…contents of catpajamas.jpg…--AaB03x

Page 48: API Design - 3rd Edition

Inline Base64 Encoding

POST /photos{ “caption”: “Cool picture of my cat.” “photo”: “RHVkZSwgbXkgY2F0IGhhcyB0aGUgYmVzdCBwYWphbWFzLg==”}

Page 49: API Design - 3rd Edition

2-Step Process

POST /photos{ “caption”: “Cool picture of my cat.”}

PUT /photos/1234/dataContent-Type: image/jpegContent-Length: 240Content-Transfer-Encoding: binary

…binary content…

Page 50: API Design - 3rd Edition

Opt for multipart/form-data.Be consistent.

Page 51: API Design - 3rd Edition

How do we support caching?

Page 52: API Design - 3rd Edition

Expiration

200 OKCache-Control: private, max-age=2592000

Page 53: API Design - 3rd Edition

ETags

GET /dogs/1ETag: “a7D92kda94aisdfG”

GET /dogs/1If-None-Match: “a7D92kda94aisdfG”

Page 54: API Design - 3rd Edition

Last-Modified

GET /dogs/1Last-Modified: Thu, 10 Jan 2013 19:43:31 GMT

GET /dogs/1If-Modified-Since: Thu, 10 Jan 2013 19:43:31 GMT

Page 55: API Design - 3rd Edition

Think about the client.

Page 56: API Design - 3rd Edition

Do we need a JavaScript API?

Page 57: API Design - 3rd Edition

Yes. Follow LinkedIn’s lead.

Page 58: API Design - 3rd Edition

What about posting data?

Page 59: API Design - 3rd Edition

application/x-www-form-urlencoded

breed=Dachshund&name=Hotdog&age=2

Page 60: API Design - 3rd Edition

application/xml

<dog> <breed>Dachshund</breed> <name>Hotdog</name> <age>2</age></dog>

Page 61: API Design - 3rd Edition

application/json

{ “breed”: “Dachshund”, “name”: “Hotdog”, “age”: 2}

Page 62: API Design - 3rd Edition

Favor application/x-www-form-urlencoded data.

Page 63: API Design - 3rd Edition

How do we handle transactions?

Page 64: API Design - 3rd Edition

Create a Transaction

POST /carts…201 CreatedLocation: /carts/1

Page 65: API Design - 3rd Edition

Add ItemsPOST /carts/1/items/{ “productId”: “mittens123”, “quantity”: 1 }…201 CreatedLocation: /cartItems/1234

Page 66: API Design - 3rd Edition

Commit the TransactionPOST /carts/1{ “message”: “checkout” }…200 OK

Page 67: API Design - 3rd Edition

• 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

Summary

Page 68: API Design - 3rd Edition

Questions?

Page 69: API Design - 3rd Edition

THANK YOUSubscribe to API webinars at:

youtube.com/apigee

Page 70: API Design - 3rd Edition

THANK YOUQuestions and ideas to:

groups.google.com/group/api-craft

Page 71: API Design - 3rd Edition

THANK YOUContact us at:

@[email protected]

@[email protected]

@apigee