Braid-HTTP
This ponyfill library extends the HTTP
implementations of Browsers and Nodejs with Braid-HTTP; transforming them from
state transfer to state synchronization systems.
These features are provided in an elegant, backwards-compatible way:
- Browsers: get a drop-in replacement for
fetch()
- Nodejs: get a route handler that adds abilities to the
http
, https
, and http2
modules
It conforms to the Braid-HTTP
v04
specification, with the additional HTTP
Multiresponse and Multiplexing
v1.0 extensions.
Developed in braid.org.
Installing
Browsers:
<script src="https://unpkg.com/braid-http/braid-http-client.js"></script>
<script>
</script>
Node.js:
npm install braid-http
require('braid-http').fetch
require('braid-http').http_client
require('braid-http').http_server
import {fetch, http_client, http_server} from 'braid-http'
Using it in Browsers
This library adds a {subscribe: true}
option to fetch()
, and lets you
access the result of a subscription with two new fields on the fetch response:
response.subscribe( update => ... )
response.subscription
: an iterator that can be used with for await
Example Subscription with Promises
Here is an example of subscribing to a Braid resource using promises:
fetch('https://braid.org/chat', {subscribe: true}).then(
res => res.subscribe(
(update) => {
console.log('We got a new update!', update)
}
)
)
If you want automatic reconnections, this library add a {retry: true}
option to fetch()
.
fetch('https://braid.org/chat', {subscribe: true, retry: true}).then(
res => res.subscribe(
(update) => {
console.log('We got a new update!', update)
}
)
)
For use in conjunction with {retry: true}
, it's possible to make the parents
param equal to a function, which will be called to get the current parents each time the fetch establishes a new connection.
fetch('https://braid.org/chat', {subscribe: true, retry: true, parents: () => {
return current_parents
}}).then(
res => res.subscribe(
(update) => {
console.log('We got a new update!', update)
}
)
)
Example Subscription with Async/Await
(await fetch('/chat', {subscribe: true, retry: true})).subscribe(
(update) => {
})
Example Subscription with for await
var subscription_iterator = (await fetch('/chat',
{subscribe: true, retry: true})).subscription
for await (var update of subscription_iterator) {
if (update.patches)
chat = apply_patches(update.patches, chat)
else
chat = JSON.parse(update.body_text)
render_stuff()
}
Using it in Nodejs
You can braidify your nodejs server with:
var braidify = require('braid-http').http_server
Braidify adds these new abilities to requests and responses:
req.subscribe
req.startSubscription({onClose: cb})
await req.parseUpdate()
res.sendUpdate()
You can call it in two ways:
braidify((req, res) => ...)
wraps your HTTP request handler, and gives it
perfectly braidified requests and responses.
braidify(req, res, next)
will add arguments to your existing requests and
responses. You can use this as express middleware.
Example Nodejs server with the built-in HTTP module
var braidify = require('braid-http').http_server
import {http_server as braidify} from 'braid-http'
require('http').createServer(
braidify((req, res) => {
if (req.subscribe)
res.startSubscription({ onClose: _=> null })
else
res.statusCode = 200
res.sendUpdate({
version: ['greg'],
body: JSON.stringify({greg: 'greg'})
})
})
).listen(9935)
You can also use braidify
within a request handler like this:
require('http').createServer(
(req, res) => {
braidify(req, res); if (req.is_multiplexer) return
})
).listen(9935)
The is_multiplexer
test in this form is only necessary if multiplexing is
enabled.
Example Nodejs server with Express
Or if you're using express
, you can just call app.use(braidify)
to get
braid features added to every request and response.
var braidify = require('braid-http').http_server
import {http_server as braidify} from 'braid-http'
var app = require('express')()
app.use(braidify)
app.get('/', (req, res) => {
if (req.subscribe)
res.startSubscription({ onClose: _=> null })
else
res.statusCode = 200
res.sendUpdate({
version: ['greg'],
parents: ['gr','eg'],
body: JSON.stringify({greg: 'greg'})
})
})
require('http').createServer(app).listen(8583)
Example Nodejs client with require('http')
var https = require('braid-http').http_client(require('https'))
https.get(
'https://braid.org/chat',
{subscribe: true},
(res) => {
res.on('update', (update) => {
console.log('well we got one', update)
})
}
)
To get auto-reconnections use:
function connect () {
https.get(
'https://braid.org/chat',
{subscribe: true},
(res) => {
res.on('update', (update) => {
console.log('We got a new update!', update)
})
res.on('end', e => setTimeout(connect, 1000))
res.on('error', e => setTimeout(connect, 1000))
})
}
connect()
Example Nodejs client with fetch()
var fetch = require('braid-http').fetch
import {fetch} from 'braid-http'
fetch('https://localhost:3009/chat',
{subscribe: true}).andThen(
x => console.log('Got ', x)
)
Configuring Multiplexing
You shouldn't need to, but can, configure which requests the library will
multiplex. You can configure
multiplexing on both the client and the server. They both need multiplexing
enabled for it to happen.
Client
A client can globally disable multiplexing on braid_fetch()
with:
braid_fetch.enable_multiplex = false
It can enable multiplexing for all GET requests with:
braid_fetch.enable_multiplex = true
It can also set it to multiplex after N
connections to an origin with:
braid_fetch.enable_multiplex = {after: N}
The default value is {after: 1}
.
A client can override this global setting per-request by passing the same
value into braid_fetch(url, {multiplex: <value>})
, such as with:
braid_fetch('/example', {multiplex: true, subscription: true})
braid_fetch('/example', {multiplex: false, subscription: true})
braid_fetch('/example', {multiplex: {after: 1}, subscription: true})
Server
Configure mutliplexing with:
var braidify = require('braid-http').http-server
nbraidify.enable_multiplex = true