maki.ericmartindale.com
@martindale • Atlanta NodeJS Meetup • April 9th, 2015
trinket.io
<a href="location">document</a>
<abbr title="2015-04-09T21:16:37Z">
3 minutes ago
</abbr>
<a href="http://twitter.com/martindale" rel="me">
Eric on Twitter
</a>
microformats.org
While the World Wide Web is a publishing platform,
the Internet should be a secure network of privacy-
aware applications that protect individual liberties.
Events | WebSockets (http Upgrade header) |
Pipelining | spdy, http/2.0 |
Content Negotiation | Accept, Accept-Language headers |
Methods | verbs: OPTIONS, PATCH, PUT... |
Authentication | Basic Auth (username, password) Cryptographic (HTTP Signatures) |
They're perfect for progressively enhancing a document,
but only after it has been served.
Benefits include: performance, resilience (high-latency connections), bandwidth...
...and developer ease-of-use.
GET | to retrieve a document or collection |
POST | to create a document in a collection |
PUT | to create a document at a specific location |
PATCH | to update a document at a specific location |
DELETE | to remove a document at a specific location |
HEAD | to retrieve a document or collection metadata |
OPTIONS | to retrieve a list of methods a document supports in the current HTTP context (i.e., what credentials are provided in the Authorization header?) |
$ curl -H "Accept: text/html" irs.gov/returns
<!DOCTYPE html>
<html>
<head>
...
Full document including a list of returns,
and maybe some Javascript to live-update the page.
$ curl -H "Accept: application/json" irs.gov/returns
[
{
"id": 8675309,
"date": "Thu Apr 09 2015 21:48:57 GMT-0400 (EDT)",
"amount": 2753.22,
"status": "pending"
},
...
]
var ws = new WebSocket('irs.gov/returns/8675309');
ws.onmessage = function(msg) {
console.log('Resource updated.', msg );
};
$ curl -X PATCH -d "status=issued" irs.gov/returns/8675309
HTTP/2.0 200 OK
{
"id": 8675309,
"date": "Thu Apr 09 2015 21:48:57 GMT-0400 (EDT)",
"amount": 2753.22,
"status": "issued"
}
var Maki = require('maki');
var twitter = new Maki();
twitter.define('Tweet', {
attributes: {
content: { type: 'String', max: 140 }
}
});
twitter.start();
var Maki = require('maki');
var twitter = new Maki();
twitter.define('User', {
attributes: {
username: { type: String, max: 35 }
}
});
twitter.define('Tweet', {
attributes: {
content: { type: String, max: 140 },
_user: { type: twitter.mongoose.SchemaTypes.ObjectId, ref: 'User' }
}
});
twitter.start();
var Maki = require('maki');
var twitter = new Maki();
var Passport = require('maki-passport-local');
var passport = new Passport({
resource: 'User'
});
twitter.use( passport );
twitter.define('User', {
attributes: {
username: { type: String , max: 35 , slug: true },
password: { type: String , max: 200 , masked: true }
}
});
twitter.define('Tweet', {
attributes: {
content: { type: String, max: 140 },
_user: { type: twitter.mongoose.SchemaTypes.ObjectId, ref: 'User' }
}
});
twitter.start();
var Maki = require('maki');
var twitter = new Maki();
var Passport = require('maki-passport-local');
var passport = new Passport({
resource: 'User'
});
twitter.use( passport );
var User = twitter.define('User', {
attributes: {
username: { type: String , max: 35 , slug: true },
password: { type: String , max: 200 , masked: true }
}
});
var Tweet = twitter.define('Tweet', {
attributes: {
content: { type: String, max: 140 },
_user: { type: twitter.mongoose.SchemaTypes.ObjectId, ref: 'User' }
}
});
User.on('create', function(user) {
Tweet.create({
content: 'My first tweet!',
_user: user._id
}, function(err, tweet) { console.log( err || tweet ); });
});
twitter.start();
Atomic transformations for objects,
encoded as a standard JSON string.
var ws = new WebSocket('ws://localhost:9200/tweets'); // generic WebSocket
ws.onmessage = function( msg ) { // message handler
console.log( JSON.parse( msg.data ) ); // JSON-RPC string + Data
} //
//
{ // WebSocket Message Data
"jsonrpc": "2.0", // JSON-RPC wrapper
"method": "patch", // JSON-RPC wrapper
"params": { // JSON-RPC wrapper
"channel": "/tweets", // Maki protocol
"ops": [ // JSON PATCH
{ // JSON PATCH
"op": "add", // JSON PATCH method // JSON PATCH
"path": "/0", // DOM/XPath for JSON // JSON PATCH
"value": { // JSON PATCH
"_id": "5526d60b20aed53950ab5112", // JSON PATCH
"content": "Another fantastic example tweet." // JSON PATCH
} // JSON PATCH
} // JSON PATCH
] // JSON PATCH
} // JSON-RPC wrapper
"id": "7f7244f0-def0-11e4-af97-75fb2146fd5f" // JSON-RPC wrapper
} // WebSocket Message Data
var ws = new WebSocket('ws://localhost:9200/tweets'); // generic WebSocket
ws.onmessage = function( msg ) { // message handler
console.log( JSON.parse( msg.data ) ); // JSON-RPC messages
}
ws.send({
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"channel": "/users"
}
});
maki.ericmartindale.com
github.com/martindale/maki
eric@ericmartindale.com • @martindale