pox to hateoas: our company's journey building a hypermedia api

33
From POX to HATEOAS Our Company's Journey Building a Hypermedia API

Upload: luke-stokes

Post on 11-May-2015

6.828 views

Category:

Technology


4 download

DESCRIPTION

We started FoxyCart.com in 2007 and soon after slapped together some XML and called it an API. As our customer base grew and third-party integrations emerged, the need for a true REST API became a priority. Beginning in 2012, we started researching best practices for modern API development. This talk will tell the story of that research and 10-months of development that followed. You'll get a look at the HAL hypermedia format along with some best practices we came up with for our problem domain of exposing our entire admin interface. We'll cover a lot. You may need a seat belt.

TRANSCRIPT

Page 1: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

From POX to HATEOASOur Company's Journey Building a Hypermedia API

Page 2: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

Who...Luke StokesCo-Founder, Developer of [email protected]@lukestokeshttp://bestoked.blogspot.com

Page 3: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

What...FoxyCart● ecommerce shopping cart system● Started by Brett Florio and myself in

2005/2006, incorporated in 2007.● SaaS (soon to be PaaS)● Built to integrate using your css/html (we're

not a CMS)● No duplication of data

Page 4: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

Why...No duplication? Expose our data!POX: Plain Old XML● Confusing API actions

○ transaction_get, transaction_list, attribute_save, attribute_delete, transaction_modify, store_includes_get, etc

● Confusing request/response model● Tight coupling between the client and server

Page 5: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

APIs and the Internet● Middleware ($$$)● RPC● SOAP● WSDL● Web Services (the WS-* stack)

Tight Coupling!

Does your browser do this?

Page 6: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

REST to the rescueCRUD can be standardized via HTTP methods:

POST/PUT = createGET = readPATCH/PUT = updateDELETE = delete

(goodbye *_list, *_save, *_modify, etc methods)

Page 7: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

REST to the rescueAgreed upon response codes● 1xx: Informational● 2xx: Success● 3xx: Redirection● 4xx: Client Error (You Screwed Up)● 5xx: Server Error (We Screwed Up)

http://en.wikipedia.org/wiki/List_of_HTTP_status_codes

Page 8: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

But... where do we start?

What's a perfect example of a REST API?

Page 9: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

What is REST anyway?Six Constraints:● Client-server● Stateless● Cacheable● Layered system● Code on demand (optional)● Uniform interface

○ Identification of resources○ Manipulation of resources through these representations○ Self-descriptive messages○ Hypermedia as the engine of application state

Page 10: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

REST Client Need-to-Know● Homepage● Hypermedia Format● Rel tags● Known media types (and possibly versions) ● Bonus stuff:

○ ?limit=5&offset=10○ ?order=<field> desc (or asc)○ ?fields=<field>,<field>,<field>○ ?<field>=<value>○ ?<field>=<some * partial value>

Page 11: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

What's a media type?Examples:

application/jsonapplication/xmlapplication/hal+json

Originally defined as MIME types (RFC 2046)Also referred to as Content-Types

Page 12: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

Platform = Will Not BreakEcommerce site broken at 4am and you changed nothing?

No one wants that phone call.

Page 13: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

Flexible Versioning● FOXYCART-API-VERSION header

Page 14: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

Flexible Versioning● FOXYCART-API-VERSION header● Per-resource vendor specific media type:

application/vnd.foxycart.com.store.v1+json

See: http://www.foxycart.com/blog/the-hypermedia-debate

Page 15: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

Flexible Versioning● FOXYCART-API-VERSION header● Per-resource vendor specific media type:

application/vnd.foxycart.com.store.v1+json● Hypermedia allows us to version via the link

relation we code to.

Page 16: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

Flexible Versioning● FOXYCART-API-VERSION header● Per-resource vendor specific media type:

application/vnd.foxycart.com.store.v1+json● Hypermedia allows us to version via the link

relation we code to.link: <https://example.com/users/2>;rel="https://example.com/rels/user"

Page 17: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

Flexible Versioning● FOXYCART-API-VERSION header● Per-resource vendor specific media type:

application/vnd.foxycart.com.store.v1+json● Hypermedia allows us to version via the link

relation we code to.link: <https://example.com/users/2>;rel="https://example.com/rels/user"link: <https://example.com/customers/2>;rel="https://example.com/rels/customer"

Page 18: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

Flexible VersioningHeader: FOXYCART-API-VERSION: 1Add "awesome_sauce" field:... "store_name":"My Store", "awesome_sauce":"pixie dust", "store_domain":"example",...Additions? No problem!

Page 19: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

Flexible VersioningHeader: FOXYCART-API-VERSION: 1Remove "awesome_sauce" field...

Uh Oh.

Option 1: rel="https://example.com/store_v2"Option 2: FOXYCART-API-VERSION: 2

Page 20: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

HEADERS: Array( [0] => Accept: application/hal+xml [1] => FOXYCART-API-VERSION: 1)

curl -X GET -H "Accept: application/hal+xml" -H "FOXYCART-API-VERSION: 1" https://api-sandbox.foxycart.com/

XML Accepts Header

Page 21: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

Next...?<link rel="self" href="https://api-sandbox.foxycart.com/" title="Your API starting point."/><link rel="https://api.foxycart.com/rels/create_client" href="https://api-sandbox.foxycart.com/clients" title="Create a client via POST."/>

HATEOAS:Hypermedia as the Engine of Application State

Page 22: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

Next...? OPTIONScurl -i -X OPTIONS

-H "Authorization: Bearer cae3c0c261fc71512428d612c1d2fd2a"-H "FOXYCART-API-VERSION: 1"-H "Accept: application/hal+xml"

"https://api-sandbox.foxycart.com/stores/2"

HTTP/1.1 200 OK..Allow: HEAD,GET,PUT,PATCH,DELETE...

Page 23: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

Next...? POST: /clientsHEADERS: Array( [0] => Accept: application/hal+xml [1] => FOXYCART-API-VERSION: 1)

curl -X POST -H "Accept: application/hal+xml" -H "FOXYCART-API-VERSION: 1" https://api-sandbox.foxycart.com/clients

Page 24: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

Error HandlingHTTP/1.1 400 Bad RequestDate: Fri, 30 Mar 2012 21:39:50 GMTConnection: closecache-control: private, must-revalidateContent-Type: application/vnd.error+xmlContent-Length: 546

https://github.com/blongden/vnd.error

Page 25: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

Error Handling<errors xml:lang="en"> <error logref=42> <message>Validation failed</message> <link rel='help' href='http://...' title='Error information'/> <link rel='describes' href='http://...' title='Error description'/> </error></errors>

Page 26: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

Let's take a look at the HAL Browser!

Hal Talk:http://haltalk.herokuapp.com/explorer/hal_browser.html#/

Foxy Cart:http://wiki.foxycart.com/v/0.0.0/hypermedia_apihttps://api-sandbox.foxycart.com/hal-browser/hal_browser.html#/https://api-sandbox.foxycart.com/hal-browser/

Examples!

Page 27: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

What's all this token stuff?

* image credit: http://www.ibm.com/developerworks/library/x-androidfacebookapi/

Page 28: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

OAuth 2.0 - Why Bother?Remember: Platform as a service!

● Hosted solutions● Hosted CMS● Self-hosted on a development platform

Simplify where we can:● If you created it, you get full access to it and

we can skip the OAuth Dance

Page 29: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

Client Code$resp = $client->get(

$api_home_page,null,$display->getHeaders()

);$display->displayResult('Home Page',$client);$useful_links['create_client'] = $client->getLink('create_client');$resp = $client->post(

$useful_links['create_client'],$data,$display->getHeaders()

);

Page 30: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

REST is easy, right? (Nope)● Should every resource have a custom media

type?● How should Hypermedia be represented in

JSON (Collection+JSON, HAL, Siren, etc)?● Link header exclusively or links as part of the

body?● To embedded sub resources?● PATCH/PUT or POST? (X-HTTP-Method-

Override)● Where to put the version number?

Page 31: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

REST is easy, right? (Nope)● Include the full resource response when

creating or use a 204?● How do you avoid one PATCH stomping

another?○ ETags and Preconditions

○ "If-None-Match: W/\"9f55f4d0f19b152a6e7c6ddeb4107e486fd7727c\""

○ "If-Modified-Since: Wed, 15 Feb 2012 12:53:52 -0800"

● How do you make hypermedia useful to the client and end user?

● Forms?

Page 32: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

YOU NEED TESTS!Functional tests are critical● Ensures your changes haven't broken

anything old or new● Speeds up prototyping

Tests are NOT a substitute for your eyeballs

Page 33: POX to HATEOAS: Our Company's Journey Building a Hypermedia API

The FutureReliable platformsConsistent functionalityKnown, shared resources

Notes:http://bestoked.blogspot.com/2012/02/restful-resources-required-reading.htmlhttp://wiki.foxycart.com/v/0.0.0/hypermedia_api