Driver and router component for manage HTT(P)/WS(S)/socket.io services with Cycle.js
npm i cycle-net --save
Create the driver
Arguments
config
with specifics optionsmiddlewares : Array
: array of express compatible middlewares like serveStatic or bodyParserrender: (template) => template
: a template engine renderer, call withreq.response.render(template)
const {run} = require('@cycle/run');
const { makeNetDriver, httpServer } = require('cycle-net');
function main(sources){
const {httpServer} = sources;
const sinks = {
}
return sinks;
}
const drivers = {
httpServer: makeNetDriver(httpServer())
}
run(main,drivers)
To create a server instance, we need to send a config stream to the httpServer output. Like this :
const httpCreate$ = xs.of({
id: 'http',
action: 'create',
config:{
port: 1983
}
});
const sinks = {
httpServer: httpCreate$
}
create action config:
id
: the instance reference name. Needed to select the server stream on input.action:'create'
: the action nameconfig.port
: see server.listen([port][, hostname][, backlog][, callback]) on NodeJS Apiconfig.hostname
: see server.listen([port][, hostname][, backlog][, callback]) on NodeJS Apiconfig.backlog
: see server.listen([port][, hostname][, backlog][, callback]) on NodeJS Apiconfig.handle
: see server.listen(handle[, callback]) on NodeJS Apiconfig.path
: see server.listen(path[, callback]) on NodeJS Apisecured
: set at true to create a HTTPS server.securedConfig
: Needed ifsecured
istrue
see Node HTTPS createServer optionsmiddlewares : Array
: array of express compatible middlewares like serveStatic or bodyParser
Basic example with HTTPS
const securedConfig = {
key: fs.readFileSync(`${__dirname}/certs/key.pem`),
cert: fs.readFileSync(`${__dirname}/certs/cert.pem`)
};
const httpsCreate$ = xs.of({
id: 'https',
action: 'create',
config:{
port: 1984
},
secured: true,
securedConfig
});
To close a server instance we need to send a config stream to the httpServer output.
const httpClose$ = xs.of({
action: 'close',
id: 'http',
});
const sinks = {
httpServer: httpClose$
}
create action config:
id
: the instance reference name. Needed to select the server stream on input.action:'close'
: the action name
Select the server width this specific id
Return Object
const http = httpServer.select('http');
Get event with name
stream from a http
object.
const http = httpServer.select('http');
const httpReady$ = http.events('ready');
const httpRequest$ = http.events('request');
Return Stream
Dispatched when the server is ready to listen.
Returned values :
event
:'ready'
instanceId
: The instance idinstance
: the original Node.js server object
Dispatched when the server received a request.
See Request
object above.
event
:'request'
,instanceId
: The instance idoriginal
: original NodeJS request object,url
: request's url,method
: request's method (POST,GET,PUT, etc...),headers
: request's headers,body
: the body request.undefined
by default. See BodyParser middlewareresponse
: the response object
Format response for driver output.
content
: the body responseoptions
:statusCode
: default200
headers
: defaultnull
statusMessage
: defaultnull
Return formatted object for driver output
Format response in json.
See send()
Format response in plain text.
See send()
Format response in html.
See send()
Format response with the render engine defined in makeHttpServerDriver()
options.
Format response redirection for driver output.
path
: path to redirectoptions
:statusCode
: default302
headers
: defaultnull
statusMessage
: defaultnull
Return formatted object for driver output
const {run} = require('@cycle/run');
const { makeNetDriver, httpServer } = require('cycle-net');
function main(sources){
const {httpServer} = sources;
// get http source
const http = httpServer.select('http');
// get requests
const serverRequest$ = http.events('request');
// create the http server
const httpCreate$ = xs.of({
id: 'http',
action: 'create',
config:{
port: 1983
}
});
// response formated with a helper response object
// Response in text format : 'covfefe'
const response$ = serverRequest$.map( req => req.response.text('covfefe') );
const sinks = {
httpServer: xs.merge(httpCreate$,response$)
}
return sinks;
}
const drivers = {
httpServer: makeNetDriver(httpServer())
}
run(main,drivers)
A Router component using switch-path
Arguments
Router(sources,routes)
sources
: Cycle.js sources object with a specific sourcerequest$
, a stream of http(s) requests.routes
: a collection of routes. See switch-path
Return stream
const { makeNetDriver, httpServer, httpRouter } = require('cycle-net');
function main(sources) {
const { httpServer } = sources;
// get http source
const http = httpServer.select('http');
// create the http server
const httpCreate$ = xs.of({
id: 'http',
action: 'create',
config:{
port: 1983
}
});
// get requests
const httpsServerRequest$ = https.events('request');
const httpsRouter$ = httpRouter({ ...sources, request$: httpsServerRequest$ }, {
'/': sources => Page({ ...sources, props$: xs.of({ desc: 'home' }) }),
'/user/:id': id => sources => Page(Object.assign({}, sources, { props$: xs.of({ desc: `user/${id}` }) })),
});
const sinks = {
httpServer: xs.merge(httpCreate$, router$.map(c => c.httpServer).flatten()),
};
return sinks;
}
function Page(sources) {
const { request$, props$ = xs.of({ appPath: null }) } = sources;
const sinks = {
httpResponse: xs.combine(props$, request$).map(([props, req]) => req.response.text(props.desc))
}
return sinks;
}
Here are discribed two usefull express middlewares.
It is used to serve static files ( images, css, etc... )
Basic usage
const serveStatic = require('serve-static');
const { makeNetDriver, httpServer } = require('cycle-net');
const drivers = {
httpServer: makeNetDriver(httpServer({middlewares:[serveStatic('./public')]})
}
It is used to parse request body and return a full formated body.
Basic usage
const bodyParser = require('body-parser');
const { makeNetDriver, httpServer } = require('cycle-net');
const drivers = {
httpServer: makeNetDriver(httpServer({
middlewares: [
// two parsers used to format body POST request in json
bodyParser.urlencoded({ extended: true }),
bodyParser.json()
]
})
}
Using Snabbdom
Snabbdom is the Virtual DOM using by @cycle/dom. It's possible to use it in server side with snabbdom-to-html.
A small helper to use snabbdom
with cycle-node-http-server
const snabbdomInit = require('snabbdom-to-html/init');
const snabbdomModules = require('snabbdom-to-html/modules');
const { makeNetDriver, httpServer } = require('cycle-net');
export default function vdom(modules=[
snabbdomModules.class,
snabbdomModules.props,
snabbdomModules.attributes,
snabbdomModules.style
]){
return snabbdomInit(modules);
}
const drivers = {
httpServer: makeNetDriver(httpServer({
render: vdom()
})
}
In main
function, snabbdom used with JSX
const response$ = request$.map( req => req.response.render(
<div>
Pouet
</div>
))
at https://github.com/mrpierrot/cycle-net/tree/master/test
at https://github.com/mrpierrot/cycle-net/blob/master/test/io.spec.js
at https://github.com/mrpierrot/cycle-net/blob/master/test/ws.spec.js
MIT