Reactive Hypermedia APIs
-
Upload
kevin-swiber -
Category
Technology
-
view
483 -
download
1
Transcript of Reactive Hypermedia APIs
-
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