Upload
kevin-swiber
View
483
Download
1
Embed Size (px)
Citation preview
Reactive Hypermedia APIs
Kevin Swiber
CODEMASH V2.0.1.5
I Like Buzzwords
Open source platform for the Internet of Things
http://zettajs.org
APIs Suck
/data.cgi
/data.cgiN0
0BIE
.NET Remoting
.NET RemotingBR
OKEN
SOAP
SOAPSTU
PID
RESTful?
RESTful?WR
ONG
Hypermedia!
Hypermedia!NERD
Whats the problem?
The real world is complex
Feedback can be vicious
We fool ourselves into thinking all problems are the same
There is no silver bullet
Love the bomb
The 15th Standard
Back to Zetta (IoT)
Reaching the Edge
DevicesDevicesDevices
Zetta
Zetta
DevicesDevicesDevices
Zetta
ClientsClientsClients
ClientsClientsClients Local Network
Data Center
Internet
The only thing we control
Desired Architectural Properties
Decoupling of implementations
Independent evolution
Scale
Load balancing
Centralize complexity, distribute simplicity
Reduce latency
Support event streams
Architectural Constraints Client-server, stateless, cacheable, layered
system, uniform interface, etc.
Wait, isnt that REST?
The hypest of all media!
http://sirenspec.org
What about event streams?
How streams are done over HTTP today
WebHooks
Chunked Transfer-Encoding
HTTP Pipelining
Long Polling
Server Sent Events
XXXXX
Just upgrade
Connection info is in the action parameters or link URI
mqtt://example.org:8863/topic
stomp+ws://example.org/topic
amqp://example.org/topic { href: ws://example.org, protocol: custom }
It works!
Model resources as finite state machines
LED.prototype.init = function(config) { config .type('led') .state('off') .when('off', { allow: ['turn-on'] }) .when('on', { allow: ['turn-off'] }) .map('turn-on', this.turnOn) .map('turn-off', this.turnOff); };
Transitions are represented as affordances in the message.
"actions": [ { "name": "turn-on", "method": "POST", "href": ..., "fields": [ { "name": "action", "type": "hidden", "value": "turn-on" } ] } ]
We need to consume an object stream.
links: [ { title: pulse, rel: [http://rxapi.org/object-stream], href: ws://... } ]
We need to consume an object stream.
wscat -c ws://... connected (press CTRL+C to quit) < {"topic":"heartbeat/1/pulse","timestamp":1411757412119,"data":61} < {"topic":"heartbeat/1/pulse","timestamp":1411757412620,"data":65} < {"topic":"heartbeat/1/pulse","timestamp":1411757413121,"data":69} < {"topic":"heartbeat/1/pulse","timestamp":1411757413622,"data":71} < {"topic":"heartbeat/1/pulse","timestamp":1411757414124,"data":66} < {"topic":"heartbeat/1/pulse","timestamp":1411757414626,"data":64} < {"topic":"heartbeat/1/pulse","timestamp":1411757415128,"data":68} < {"topic":"heartbeat/1/pulse","timestamp":1411757415629,"data":63} < {"topic":"heartbeat/1/pulse","timestamp":1411757416130,"data":65} < {"topic":"heartbeat/1/pulse","timestamp":1411757416631,"data":63}
Monitor resource events before taking action.
links: [ { title: logs, rel: [ monitor, http://rxapi.org/object-stream ], href: ws://... } ]
Monitor resource events before taking action.
wscat -c ws://... connected (press CTRL+C to quit) < {"topic":"led/2/logs","timestamp":1411809676901,"transition":"turn-on","input":[],"properties":{"id":"2","type":"led","name":null,"state":"on"}} < {"topic":"led/2/logs","timestamp":1411809677548,"transition":"turn-off","input":[],"properties":{"id":"2","type":"led","name":null,"state":"off"}} < {"topic":"led/2/logs","timestamp":1411809678483,"transition":"turn-on","input":[],"properties":{"id":"2","type":"led","name":null,"state":"on"}} < {"topic":"led/2/logs","timestamp":1411809679126,"transition":"turn-off","input":[],"properties":{"id":"2","type":"led","name":null,"state":"off"}}
We also need binary.links: [ { rel: [http://rxapi.org/binary-stream], href: ws://..., type: video/mpeg, } ]
We also need binary.
wscat -c ws://... connected (press CTRL+C to quit) Q`rCEDDIp=`"3ss79:Yk}{` 5e\`>9%J[K89\z^> 8X Gp;WqXF h1{%O;7
We also need binary.
wscat -c ws://... connected (press CTRL+C to quit)
Reactive Clientsvar siren = require('siren'); !siren() .load('http://zetta-cloud-2.herokuapp.com') .link('http://rels.zettajs.io/peer', 'Detroit') .entity(function(e) { return e.properties.type === 'sound'; }) .link('http://rels.zettajs.io/object-stream', 'level') .monitor() .subscribe(console.log);
Reactive Clientsvar zrx = require('zrx'); !zrx() .load('http://zetta-cloud-2.herokuapp.com') .server('Detroit') .device(function(d) { return d.type === 'sound'; }) .stream('level') .subscribe(console.log);
Going Forward
Solve the producer-consumer problem.
Reactive Stream Control Protocol
Consumer controlled streams
Runs over WebSockets
Multiplex streams
URI scheme definition
Will be supported on HTTP/2 + WebSockets.
What can you do with streams?
Monitoring values over time
Distributed data processing
Event sourcing
Batches
// TODO:
Extract reactive hypermedia framework from Zetta internals.
Produce a clean specification and documentation.
Experiment with multiple languages/platform implementations.
Hit me up! [email protected]
https://twitter.com/kevinswiber
https://linkedin.com/in/kevinswiber
https://github.com/kevinswiber