Share
Embed
API Love Story
Ahmad Nassri
August 27, 2014
Transcript
57 slides
-
{ "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 -
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. -
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 -
[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. -
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 -
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" } -
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); }); -
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 -
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" } -
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); }); -
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" } -
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 -
router.get('/order/:id', function(req, res) { var id = req.param('id'); var order
= store.get(id); res.status(200).send(order); }); -
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 -
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" } -
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); }); -
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" } ] } ] } } -
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"} ] } } } -
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" } -
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" } ] } } -
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" } -
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" } -
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" } } -
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" } } ] } -
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 -
SSL = Secure Socket Layer TLS = Transport Layer Security
sniffing transaction requests capture customer API keys capture application API keys -
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 -
# 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 -
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