Slide 1

Slide 1 text

{"api": "❤"}

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

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.

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

{"api": "❤"}

Slide 12

Slide 12 text

{"restful-web-api": "❤"}

Slide 13

Slide 13 text

[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.

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

No content

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

router.get('/order/:id', function(req, res) { var id = req.param('id'); var order = store.get(id); res.status(200).send(order); });

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

github.com/ahmadnassri/get-express-coffee

Slide 33

Slide 33 text

Collection+JSON Hypertext Application Language ( )

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

No content

Slide 44

Slide 44 text

SSL = Secure Socket Layer TLS = Transport Layer Security sniffing transaction requests capture customer API keys capture application API keys

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

RFC 2617

Slide 47

Slide 47 text

# 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

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

NOT simply a medium:

Slide 50

Slide 50 text

No content

Slide 51

Slide 51 text

No content

Slide 52

Slide 52 text

No content

Slide 53

Slide 53 text

No content

Slide 54

Slide 54 text

No content

Slide 55

Slide 55 text

www.yeoman.to

Slide 56

Slide 56 text

Google Glass Reunion - One Year Later Panel Discussion

Slide 57

Slide 57 text

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