Friday 26 July 2019

Small, pretty, transport agnostic, HTTP/2-ready web server which can work in browser.

Plant is a new web server which is HTTP/2-ready, WebAPI compatible, transport agnostic, highly modular, very secure by default and small: Plant's size is 8 KiB + optional node.js HTTP transport is 38 KiB (minified, gzipped) ; 74 KiB and 125 KiB respectively (unminified, ungzipped).Plant was designed to use bleeding edge technologies, reduce complexity and make server portable. This portability gives you ability to write and test server-side APIs right in browser using only text editor. Plant has additional packages like http-adapter, router and bunch of http transports.const Plant = require('@plant/plant') const {createServer} = require('@plant/http') const plant = new Plant() plant.use('/greet', ({res}) => { res.body = 'Hello, World!' }) createServer(plant) .listen(8080) In-browser exampleThis is a very-very simple example of how it could work. It's just renders requestCodesandbox · PreviewDetailsHTTP/2-readyPlant can push responses to the client using HTTP/2 resource push mechanics.plant.use(({res}) => { res.push('/js/index.js') res.push('/css/style.css') res.html('...') } WebAPI compatibleObjects like Request, Response, Headers and streams have the same or familiar interfaces that already exists in WebAPI. Plant's Request and Response are mirrored from the Client, that's why Request object has Response's method json().plant.use(({req, res}) => { req.url.pathname // "/" req.headers.get('content-type') res.headers.set('content-length', 5) res.body = 'Hello' }) // Retrieve JSON with one single command plant.use('/echo', async ({req, res}) => { const body = await req.json() res.json(json) }) Plant is using ReadableStreams instead of Node streams. That's why it can work seamlessly in browser. For example in ServiceWorker.Transport agnosticPlant isn't tightly coupled with the Node.js http module server, instead Plant is using it as external dependency. You can easely create your own transport. That's why you able to deliver requests via anything: WebSockets, MessageChannel, raw TCP, or even email (why not). It makes things extremely simple, especially your tests.const Plant = require('@plant/plant'); const {createServer} = require('@plant/http2'); const plant = new Plant(); plant.use(({res, socket}) => { res.body = 'Hello, World!' }) createServer(plant, { key: '...', cert: '...', }) .listen(443) Create requests manually:const plant = new Plant() plant.use(({res}) => { res.body = 'Hi' }) const url = new URL('http://localhost:8080/') // Create HTTP context's params const req = new Plant.Request({ url, }); const res = new Plant.Response({ url, }); // Request peer. Peer represents other side of connection. const peer = new Plant.Peer({ uri: new Plant.URI({ protocol: 'ws:', hostname: window.location.hostname, port: window.location.port, }), }); // Create connection socket const socket = new Plant.Socket({ peer, // If socket allows write upstream, then onPush method could be defined to handle pushes. // onPush should return Promise which resolves when response sending completes. onPush(response) {}, }); const handleRequest = plant.getHandler() handleRequest({req, res, socket}) .then(() => { // Request handled. All requests (even faulty) should get there. }, (error) => { // Something went wrong }) ModularPlant is trying to separate responsibility between modules and not to bloat own size. Everything, especially transport related, is moved out of server package and could be replaced with you own code.Additional packages:httpNode.js native http module transporthttpsNode.js native https module transporthttp2Node.js native http2 module transporthttps2Node.js native http2 module with TLS transportrouterRouter packageSecure by defaultPlant is using the most strict Content-Security-Policy out of the box. And this is the only web server which bring security first and doesn't sacrifice it. This policy doesn't allow webpage to do anything, even run a single piece of JS. Default value of Content-Security-Policy header is very denial and should be used in production to protect client and server from accidents. Developers should specify exact permissions which their site requires.const plant = new Plant({ csp: Plant.CSP.STRICT, }) For development should be used Plant.CSP.LOCAL policy.Router exampleconst Plant = require('@plant/plant') const Router = require('@plant/router') const {createServer} = require('@plant/http') const userApi = new Router() router.post('/', () => {}) router.get('/:id', () => {}) router.put('/:id', () => {}) router.delete('/:id', () => {}) plant.use('/api/users/*', userApi) createServer(plant) .listen(8080) ReferencesGithub · NPMP.S.I'm an author of this package, so you could AMA. Also, notify me about grammatical errors. I would very appreciate it.

Submitted July 26, 2019 at 04:39PM by rmkn

No comments:

Post a Comment