Upgrade to Pro — share decks privately, control downloads, hide ads and more …

API Love Story

API Love Story

Ahmad Nassri

August 27, 2014
Tweet

More Decks by Ahmad Nassri

Other Decks in Technology

Transcript

  1. { "name": "Ahmad Nassri", "url": "http://www.ahmadnassri.com/", "twitter": "http://twitter.com/ahmadnassri", "email": "[email protected]",

    "bio": "Technologist, Entrepreneur, Dog Lover.", "work": { "company": " ", "job": "API Master" }, "activites": [ " ", " " ], "meetups": [ " ", " " ] } Mashape.com blogging open-source projects #YeomanTO #FBTO
  2. is the largest API hub in the world where you

    can consume, distribute, monitor and monetize your public and private APIs. A revenue generating platform for technology startups Powering thousands of APIs and Applications Used in almost 100 countries by thousands of developers Adopted in every major industry including finance, healthcare, military, agriculture, insurance, government, media, e-commerce, retail, aviation, manufacturing and telecom.
  3. Originally communicated by Roy Fielding in his The REST architectural

    style describes six constraints: doctoral dissertation Uniform Interface Stateless Cacheable Client-Server Layered System Code on Demand (optional) presentational tate ransfer
  4. [1991] Started as notes written by Tim Berners Lee. [1996]

    First standard HTTP/1.0 version (RFC 1945). [1999] HTTP/1.1 (RFC 2616) & REST [2007] Refactoring with HTTP/1.1 bis [2009] SPDY [2012] IETF working group for HTTPbis released draft of HTTP 2.0 SPDY was chosen as the starting point.
  5. RFC7230 - HTTP/1.1: Message Syntax and Routing RFC7231 - HTTP/1.1:

    Semantics and Content RFC7232 - HTTP/1.1: Conditional Requests RFC7233 - HTTP/1.1: Range Requests RFC7234 - HTTP/1.1: Caching RFC7235 - HTTP/1.1: Authentication RFC6265 - HTTP State Management Mechanism
  6. http POST localhost:3000/order drink=coffee HTTP/1.1 201 Created Connection: keep-alive Content-Length:

    132 Content-Type: application/json; charset=utf-8 Date: Tue, 26 Aug 2014 16:37:55 GMT Location: http://localhost:3000/order/1409071075510 { "cost": 3, "drink": "coffee", "next": { "rel": "http://localhost:3000/payment", "uri": "http://localhost:3000/payment/order/1409071075510" } } POST /order HTTP/1.1 Host: localhost:3000 Content-Type: application/json; charset=utf-8 { "drink": "coffee" }
  7. router.post('/order', function(req, res) { // generate new id var id

    = '123'; // create object var order = { drink: req.body.drink, cost: 3, next: { rel: 'http://' + req.get('host') + '/payment', uri: 'http://' + req.get('host') + '/payment/order/' + id } }; // save order store.set(id, order); // status res.status(201); // headers res.set({'Location': 'http://' + req.get('host') + '/order/' + id}); // respond res.send(order); });
  8. http OPTIONS localhost:3000/order/1409071075510 HTTP/1.1 200 OK Allow: GET,PUT Connection: keep-alive

    Content-Length: 7 Content-Type: text/html; charset=utf-8 Date: Tue, 26 Aug 2014 16:54:44 GMT GET,PUT OPTIONS /order/1409071075510 HTTP/1.1 Host: localhost:3000
  9. http PUT localhost:3000/order/1409071075510 additions=shot HTTP/1.1 200 OK Connection: keep-alive Content-Length:

    151 Content-Type: application/json; charset=utf-8 Date: Tue, 26 Aug 2014 16:53:07 GMT Location: http://localhost:3000/order/1409071075510 { "additions": "shot", "cost": 4, "drink": "coffee", "next": { "rel": "http://localhost:3000/payment", "uri": "http://localhost:3000/payment/order/1409071075510" } } PUT /order/1409071075510 HTTP/1.1 Host: localhost:3000 Content-Type: application/json; charset=utf-8 { "additions": "shot" }
  10. router.put('/order/:id', function(req, res) { var id = req.param('id'); var order

    = store.get(id); // modify order order.additions = req.body.additions; order.cost += 1; // save order store.set(id, order); // status res.status(200); // headers res.set({'Location': 'http://' + req.get('host') + '/order/' + id}); res.send(order); });
  11. http PUT localhost:3000/order/1409071075510 additions=moar+shots HTTP/1.1 409 Conflict Connection: keep-alive Content-Length:

    151 Content-Type: application/json; charset=utf-8 Date: Tue, 26 Aug 2014 16:53:07 GMT Location: http://localhost:3000/order/1409071075510 { "additions": "shot", "cost": 4, "drink": "coffee", "next": { "rel": "http://localhost:3000/payment", "uri": "http://localhost:3000/payment/order/1409071075510" } } PUT /order/1409071075510 HTTP/1.1 Host: localhost:3000 Content-Type: application/json; charset=utf-8 { "additions": "moar shots" }
  12. http GET localhost:3000/order/1409071075510 HTTP/1.1 200 OK Connection: keep-alive Content-Length: 151

    Content-Type: application/json; charset=utf-8 Date: Tue, 26 Aug 2014 16:53:07 GMT Location: http://localhost:3000/order/1409071075510 { "additions": "shot", "cost": 4, "drink": "coffee", "next": { "rel": "http://localhost:3000/payment", "uri": "http://localhost:3000/payment/order/1409071075510" } } GET /order/1409071075510 HTTP/1.1 Host: localhost:3000 Accept: application/json
  13. http OPTIONS localhost:3000/payment/order/1409071075510 HTTP/1.1 200 OK Allow: GET,PUT Connection: keep-alive

    Content-Length: 7 Content-Type: text/html; charset=utf-8 Date: Tue, 26 Aug 2014 16:54:44 GMT GET,PUT OPTIONS /payment/order/1409071075510 HTTP/1.1 Host: localhost:3000
  14. http PUT localhost:3000/payment/order/1409071075510 \ --auth-type=digest \ -a ahmad:123 \ cardNo=123456789

    expires="07/15" name="Ahmad Nassri" amount="4.00" HTTP/1.1 201 Created Connection: keep-alive Content-Length: 151 Content-Type: application/json; charset=utf-8 Date: Tue, 26 Aug 2014 16:53:07 GMT { ... "payment": { "amount": "4.00", "cardNo": "123456789", "expires": "07/15", "name": "Ahmad Nassri" } } PUT /payment/order/1409071075510 HTTP/1.1 Host: localhost:3000 Content-Type: application/json; charset=utf-8 Authorization: Digest username="ahmad" realm="localhost" nonce="..." ... { "amount": "4.00", "cardNo": "123456789", "expires": "07/15", "name": "Ahmad Nassri" }
  15. router.put('/payment/order/:id', function(req, res) { var id = req.param('id'); var order

    = store.get(id); // modify order order.payment = { cardNo: req.body.cardNo, expires: req.body.expires, name: req.body.name, amount: req.body.amount }; // save order store.set(id, order); // status res.status(201); // headers res.set({'Location': 'http://' + req.get('host') + '/order/' + id}); res.send(order); });
  16. GET /player/1234567890 HTTP/1.1 { "collection": { "version": "1.0", "href": "https://api.example.com/player",

    "items": [ { "href": "https://api.example.com/player/1234567890", "data": [ {"name": "playerId", "value": "1234567890", "prompt": "Identifier"}, {"name": "name", "value": "Kevin Sookocheff", "prompt": "Full Name"}, {"name": "alternateName", "value": "soofaloofa", "prompt": "Alias"} ], "links": [{ "rel": "friends", "href": "https://api.example.com/player/1234567890/friends", "prompt": "Friends" },{ "rel": "image", "href": "https://api.example.com/player/1234567890/avatar.png", "prompt": "Avatar", "render": "image" } ] } ] } }
  17. GET /player/1234567890/friends HTTP/1.1 { "collection": { "version": "1.0", "href": "https://api.example.com/player/1234567890/friends",

    "links": [ {"rel": "next", "href": "https://api.example.com/player/1234567890/friends?page=2"} ], "items": [ { "href": "https://api.example.com/player/1895638109", "data": [ {"name": "playerId", "value": "1895638109", "prompt": "Identifier"}, {"name": "name", "value": "Sheldon Dong", "prompt": "Full Name"}, {"name": "alternateName", "value": "sdong", "prompt": "Alias"} ], "links": [ {"rel": "image", "href": "https://api.example.com/player/1895638109/avatar.png", "prompt": "Avatar", "render": "image" }, {"rel": "friends", "href": "https://api.example.com/player/1895638109/friends", "prompt": "Friends" } ] }, { "href": "https://api.example.com/player/8371023509", "data": [ {"name": "playerId", "value": "8371023509", "prompt": "Identifier"}, {"name": "name", "value": "Martin Liu", "prompt": "Full Name"}, {"name": "alternateName", "value": "mliu", "prompt": "Alias"} ], "links": [ {"rel": "image", "href": "https://api.example.com/player/8371023509/avatar.png", "prompt": "Avatar", "render": "image" }, {"rel": "friends", "href": "https://api.example.com/player/8371023509/friends", "prompt": "Friends" } ] } ], "queries": [ { "rel": "search", "href": "https://api.example.com/player/1234567890/friends/search", "prompt": "Search", "data": [ {"name": "search", "value": ""} ] } ], "template": { "data": [ {"name": "playerId", "value": "", "prompt": "Identifier" }, {"name": "name", "value": "", "prompt": "Full Name"}, {"name": "alternateName", "value": "", "prompt": "Alias"}, {"name": "image", "value": "", "prompt": "Avatar"} ] } } }
  18. GET /player/1234567890 HTTP/1.1 { "_links": { "self": { "href": "https://api.example.com/player/1234567890"

    }, "curies": [{ "name": "ex", "href": "https://api.example.com/docs/rels/{rel}", "templated": true }], "ex:friends": { "href": "https://api.example.com/player/1234567890/friends" } }, "playerId": "1234567890", "name": "Kevin Sookocheff", "alternateName": "soofaloofa", "image": "https://api.example.com/player/1234567890/avatar.png" }
  19. GET /player/1234567890/friends HTTP/1.1 { "_links": { "self": { "href": "https://api.example.com/player/1234567890/friends"

    }, "next": { "href": "https://api.example.com/player/1234567890/friends?page=2" } }, "size": "2", "_embedded": { "player": [ { "_links": { "self": { "href": "https://api.example.com/player/1895638109" }, "friends": { "href": "https://api.example.com/player/1895638109/friends" } }, "playerId": "1895638109", "name": "Sheldon Dong", "alternateName": "sdong", "image": "https://api.example.com/player/1895638109/avatar.png" }, { "_links": { "self": { "href": "https://api.example.com/player/8371023509" }, "friends": { "href": "https://api.example.com/player/8371023509/friends" } }, "playerId": "8371023509", "name": "Martin Liu", "alternateName": "mliu", "image": "https://api.example.com/player/8371023509/avatar.png" } ] } }
  20. GET /player/1234567890 HTTP/1.1 { "@context": { "@vocab": "https://schema.org/", "image": {

    "@type": "@id" }, "friends": { "@type": "@id" } }, "@id": "https://api.example.com/player/1234567890", "playerId": "1234567890", "name": "Kevin Sookocheff", "alternateName": "soofaloofa", "image": "https://api.example.com/player/1234567890/avatar.png", "friends": "https://api.example.com/player/1234567890/friends" }
  21. GET /player/1234567890/friends HTTP/1.1 { "@context": [ "http://www.w3.org/ns/hydra/core", { "@vocab": "https://schema.org/",

    "image": { "@type": "@id" }, "friends": { "@type": "@id" } } ], "@id": "https://api.example.com/player/1234567890/friends", "operation": { "@type": "BefriendAction", "method": "POST", "expects": { "@id": "http://schema.org/Person", "supportedProperty": [ { "property": "name", "range": "Text" }, { "property": "alternateName", "range": "Text" }, { "property": "image", "range": "URL" } ] } }, "member": [ { "@id": "https://api.example.com/player/1895638109", "name": "Sheldon Dong", "alternateName": "sdong", "image": "https://api.example.com/player/1895638109/avatar.png", "friends": "https://api.example.com/player/1895638109/friends" }, { "@id": "https://api.example.com/player/8371023509", "name": "Martin Liu", "alternateName": "mliu", "image": "https://api.example.com/player/8371023509/avatar.png", "friends": "https://api.example.com/player/8371023509/friends" } ], "nextPage": "https://api.example.com/player/1234567890/friends?page=2" }
  22. GET /player/1234567890 HTTP/1.1 { "class": "player", "links": [ { "rel":

    [ "self" ], "href": "https://api.example.com/player/1234567890" }, { "rel": [ "friends" ], "href": "https://api.example.com/player/1234567890/friends" } ], "properties": { "playerId": "1234567890", "name": "Kevin Sookocheff", "alternateName": "soofaloofa", "image": "https://api.example.com/player/1234567890/avatar.png" } }
  23. GET /player/1234567890/friends HTTP/1.1 { "class": "player", "links": [ {"rel": [

    "self" ], "href": "https://api.example.com/player/1234567890/friends"}, {"rel": [ "next" ], "href": "https://api.example.com/player/1234567890/friends?page=2"} ], "actions": [{ "class": "add-friend", "href": "https://api.example.com/player/1234567890/friends", "method": "POST", "fields": [ {"name": "name", "type": "string"}, {"name": "alternateName", "type": "string"}, {"name": "image", "type": "href"} ] }], "properties": { "size": "2" }, "entities": [ { "links": [ {"rel": [ "self" ], "href": "https://api.example.com/player/1895638109"}, {"rel": [ "friends" ], "href": "https://api.example.com/player/1895638109/friends"} ], "properties": { "playerId": "1895638109", "name": "Sheldon Dong", "alternateName": "sdong", "image": "https://api.example.com/player/1895638109/avatar.png" } }, { "links": [ {"rel": [ "self" ], "href": "https://api.example.com/player/8371023509"}, {"rel": [ "friends" ], "href": "https://api.example.com/player/8371023509/friends" } ], "properties": { "playerId": "8371023509", "name": "Martin Liu", "alternateName": "mliu", "image": "https://api.example.com/player/8371023509/avatar.png" } } ] }
  24. great for augmenting existing APIs. mostly serves as documentation to

    add operations use HYDRA. adds a vocabulary for communicating. decouples API serialization format from the communication format. light weight syntax & easy semantics lack of support for specifying actions best for representing data collections list queries templates generic classes of items support for actions
  25. SSL = Secure Socket Layer TLS = Transport Layer Security

    sniffing transaction requests capture customer API keys capture application API keys
  26. openssl genrsa -out key.pem openssl req -new -key key.pem -out

    csr.pem openssl x509 -req -days 9999 -in csr.pem -signkey key.pem -out cert.pem generating a cirtificate is easy Trusted Certificate Authority have their root keys bundled with web browsers and operating systems. Expensive! USD $100 - $1000
  27. # URL Versioning: GET /api/v2/foo HTTP/1.1 # Custom Header: GET

    /api/foo X-VERSION: 2 # Content Type GET: /api/foo Accept: application/vnd.github.v3.raw+json URLs a URL should represent the resource, not a version Custom Headers not a semantic way of describing the resource Accept headers harder to test
  28. Stalk me on Twitter , Read more on my ,

    Follow my APIs on . @AhmadNassri Blog Mashape.com/AhmadNassri http://www.ahmadnassri.com http://www.mashape.com http://www.yeoman.to http://www.fbto.ca