Ahmad Nassri
Advocate of all things open-source. Founder at Tech Masters, Mentor at Node School Toronto, Director at Full Stack Toronto, Director at Open API Initiative, Editor at The RESTful Web.

{"api": "❤"}{
"name": "Ahmad Nassri",
"url": "http://www.ahmadnassri.com/",
"twitter": "http://twitter.com/ahmadnassri",
"email": "ahmad@ahmadnassri.com",
"bio": "Technologist, Entrepreneur, Dog Lover.",
"work": {
"company": "Mashape.com",
"job": "API Master"
},
"activites": [
"blogging",
"open-source projects"
],
"meetups": [
"#YeomanTO",
"#FBTO"
]
}

Mashape is the largest API hub in the world where you can consume, distribute, monitor and monetize your public and private APIs.
In Egyptian mythology, Apis, is a bull-deity that was worshipped in the Memphis region. Apis served as an intermediary between humans and an all-powerful god.

an application programming interface (API) specifies a software component in terms of its operations, their inputs and outputs and underlining types. Its main purpose is to define a set of functionalities that are independent of their respective implementation, allowing both definition and implementation to vary without compromising each other.
A Web service is a method of communication between two electronic devices over a network. It is a software function provided at a network address over the web with the service always on as in the concept of utility computing.

© http://www.slideshare.net/markedgington
Originally communicated by Roy Fielding in his doctoral dissertation The REST architectural style describes six constraints:
REpresentational State Transfer
{"api": "❤"}{"restful-web-api": "❤"}These RFCs collectively obsolete all preceding RFCs defining HTTP, including RFC1945, RFC2068 and RFC2616.

http://httpwg.github.io
http://http2.github.io
http://www.infoq.com/articles/webber-rest-workflow




The Customer Workflow
The Barista's Workflow







http POST localhost:3000/order drink=coffeeHTTP/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/1409071075510HTTP/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,PUTOPTIONS /order/1409071075510 HTTP/1.1
Host: localhost:3000
http PUT localhost:3000/order/1409071075510 additions=shotHTTP/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+shotsHTTP/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/1409071075510HTTP/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/1409071075510HTTP/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,PUTOPTIONS /payment/order/1409071075510 HTTP/1.1
Host: localhost:3000http 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);
});github.com/ahmadnassri/get-express-coffee


Collection+JSON
Hypertext Application Language (HAL)



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"
}
]
}
]
}
}Kevin Sookocheff http://sookocheff.com/posts/2014-03-11-on-choosing-a-hypermedia-format/
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"}
]
}
}
}Kevin Sookocheff http://sookocheff.com/posts/2014-03-11-on-choosing-a-hypermedia-format/
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"
}Kevin Sookocheff http://sookocheff.com/posts/2014-03-11-on-choosing-a-hypermedia-format/
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"
}
]
}
}Kevin Sookocheff http://sookocheff.com/posts/2014-03-11-on-choosing-a-hypermedia-format/
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"
}Kevin Sookocheff http://sookocheff.com/posts/2014-03-11-on-choosing-a-hypermedia-format/
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"
}Kevin Sookocheff http://sookocheff.com/posts/2014-03-11-on-choosing-a-hypermedia-format/
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"
}
}Kevin Sookocheff http://sookocheff.com/posts/2014-03-11-on-choosing-a-hypermedia-format/
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"
}
}
]
}Kevin Sookocheff http://sookocheff.com/posts/2014-03-11-on-choosing-a-hypermedia-format/

"API Security Trooper" Credits: https://flic.kr/p/fJEXeX


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



RFC 2617

# 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
NOT simply a medium:
AWS, Twilio, Facebook, IFTTT



www.yeoman.to

Google Glass Reunion - One Year Later Panel Discussion
meetu.ps/2tTVkl
Stalk me on Twitter @AhmadNassri, Read more on my Blog, Follow my APIs on Mashape.com/AhmadNassri.
http://www.ahmadnassri.com
http://www.mashape.com
http://www.yeoman.to
http://www.fbto.ca
By Ahmad Nassri
Advocate of all things open-source. Founder at Tech Masters, Mentor at Node School Toronto, Director at Full Stack Toronto, Director at Open API Initiative, Editor at The RESTful Web.