All http methods supported by Node.js
Your callback middleware will be called with ctx and lastResult.
Will be await
by the request handler and use the resolved result as lastResult
for the next middleware call
It's for internal use only
private _use(
method support the overloading and normalyze it into the complete signature.
A route can be either :
number
indexed (start at 1
index)You are encouraged to use string Route.
'/:category/:page/'
will provide you a params object with categories
and page
key in Context
populate next to call await app.listen()
with server url
if no callback provided it will use
(err, socket) => socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
Init server asynchronously can auto generate self-signed ssl if https or http2
By default,
options = {protocol: 'http', selfSigned: false, http2Secure: true}
If you wan't auto generate self-signed ssl:
init({protocol: 'https', selfSigned: true})
// or
init({protocol: 'http2', selfSigned: true})
if no port provided, os take one available randomly. Think print resolved string url somewhere
if no provided, 0.0.0.0
a string url of server
Transform into a MiddlewareItem and put it in _routes stack
Transform into a MiddlewareItem and put it in _middlewares stack
Generated using TypeDoc
import App from 'u-http-server';
This class let you create http, https, http2 builtin node server with simple api for middleware and routing.
The api of this class is close to express or koa for easy adoption but all your routes or middlewares are handling in async await manner.
instances of App have two separate stack, one for middlewares, the other for routes.
use()
place in middlewares stackroute()
and shortcut (get()
,post()
, etc.) place in routes stackThey both have same syntax and called in the same way
Lyfecycle of a request
When a server recieve a request, midlewares stack and routes stack are merged (middlewares first, next routes) in order they were declared
Iterate on this merge. If methods and route match:
lastResult = await middleware(ctx, lastResult);
response.finished
break loopNext to last middleware, if not
response.finished
:response.end(typeof lastResult === 'object' ? JSON.stringify(lastResult) : lastResult.toString());
It's for avoiding server never respond to client (and keep open ressources for nothing). And in your route, if you wan't return some data, you can. instead of calling yourselfresponse.end(data)
orresponse.end(JSON.stringify(data))
/!\ For avoiding race exceptions, be sure when your middleware end, it has not open some asynchronous things not awaited. If you need to use some async api working with callback, wrap it in a Promise, resolve (or reject) it in callback and await or return this Promise.
Some examples below
Basic
import App, {parseCookie, sessionInMemory} from 'u-http-server'; const app = new App(); app .use(ctx => console.log(ctx.request.url)) .use(parseCookie) .use(sessionInMemory) .get('/:category/:page', ctx => ctx.response.end(JSON.stringify(ctx.params))) .get('/:test', ctx => ctx.response.end(JSON.stringify(ctx.params))) .route(ctx => ctx.response.end('Hello World !')) app.init({protocol: 'http2', selfSigned: true}) .then(app => app.applyOnClientError()) .then(app => app.listen(3000)) .then(url => console.log('server listening on', url));
lastReturn
mechanismimport fetch from 'node-fetch'; import RSS from 'rss'; import format from 'date-fns/format/index.js'; const hytale_list = 'https://hytale.com/api/blog/post/published'; const hytale_article = 'https://hytale.com/api/blog/post/slug/'; const hytale_feed = feed_url => ({ 'title': 'Hytale', 'description': 'News from Hytale', 'feed_url': feed_url, 'site_url': 'https://hytale.com/news', 'image_url': 'https://hytale.com/static/images/logo.png', }); const getArticleUrl = item => `https://hytale.com/news/${format(item.createdAt, 'yyyy/MM')}/${item.slug}`; // fetch articles list from hytale api app.get('/rss/hytale', async ctx => { const articles_resume = await fetch(hytale_list).then(r => r.json()); return Promise.all( articles_resume.map(a => fetch(hytale_article + a.slug).then(r => r.json())) ); }); // transform in to a rss feed app.get('/rss/hytale', (ctx, articles) => articles.reduce((feed, item) => feed.item({ title: item.title, description: item.body, url: getArticleUrl(item), guid: `${item.slug}-${item._id}`, categories: item.tags, author: item.author, date: item.publishedAt, enclosure: { url: `https://hytale.com/m/variants/blog_cover_${item.coverImage.s3Key}`, type: item.coverImage.mimeType, } }), new RSS(hytale_feed(`${app.address}${ctx.request.url.toString()}`))).xml({indent: true})); // set content-type and end response with generated rss feed app.get('/rss/:flux', (ctx, rss) => { ctx.response.setHeader('Content-Type', 'application/rss+xml'); ctx.response.end(rss); });