HttpIncoming
In the request/response life cycle of an HTTP request handled by Podium,
different information needs to be accessible at different stages. To cater to
this, Podium has an HttpIncoming
object which is passed between the different
parts of Podium throughout the request/response life cycle.
This HttpIncoming
object holds different values during the various stages in a
request/response life cycle. The most important values are:
- The Podium context
- View properties for use by the document template
- A URL object for the servers request object (holds query params etc)
HttpIncoming
is used in both @podium/layout and
@podium/podlet.
The HttpIncoming
class is located in the @podium/utils
module and when writing an HTTP server without using the supported HTTP
framework plugins, it will be necessary to instantiate an instance of this
object and pass it between the different parts of Podium.
When using the supported HTTP framework plugins an instance of HttpIncoming
is
created for you under the hood and passed on as a property on the request
between the different parts of the request/response life cycle of the HTTP
framework.
- Express
- Hapi
- Fastify
- HTTP
import express from 'express';
import Layout from '@podium/layout';
const app = express();
const layout = new Layout({
name: 'myLayout',
pathname: '/',
});
const podlet = layout.client.register({
name: 'myPodlet',
uri: 'http://localhost:7100/manifest.json',
});
// Set up a document template which take HttpIncoming and a body content.
// This template will be used when .render() is called in a request.
layout.view = (incoming, body) => {
return `
<html>
<head><title>${incoming.view.title}</title></head>
<body>${body}</body>
</html>
`;
};
// Attach the middleware on Express. This will create HttpIncoming under the
// hood plus generate the context and store it on HttpIncoming among other
// things. HttpIncoming will be stored at res.locals.podium
app.use(layout.middleware());
app.get(layout.pathname(), (req, res) => {
// Get the HttpIncoming object generated by the layout.middleware()
let incoming = res.locals.podium;
// Set a view property on HttpIncoming. This can now be used in the
// document template or anywhere one have access to HttpIncoming.
incoming.view = {
title: 'My pretty site'
};
// Pass HttpIncoming on to the fetch method. This will pass the generated
// context on to the request to the podlet.
const { content } = await podlet.fetch(incoming);
// Call podiumSend with the content of the podlet. This will now call the
// document template set on the layout.view property send the response.
// This will pass on HttpIncoming to the document template under the hood.
res.podiumSend(content);
});
app.listen(7000);
import HapiLayout from '@podium/hapi-layout';
import Layout from '@podium/layout';
import Hapi from 'hapi';
const app = Hapi.Server({
host: 'localhost',
port: 7000,
});
const layout = new Layout({
name: 'myLayout',
pathname: '/',
});
const podlet = layout.client.register({
name: 'myPodlet',
uri: 'http://localhost:7100/manifest.json',
});
// Set up a document template which take HttpIncoming and a body content.
// This template will be used when .render() is called in a request.
layout.view = (incoming, body) => {
return `
<html>
<head><title>${incoming.view.title}</title></head>
<body>${body}</body>
</html>
`;
};
app.register({
plugin: new HapiLayout(),
options: layout,
});
app.route({
method: 'GET',
path: layout.pathname(),
handler: (request, h) => {
// Get the HttpIncoming object generated by the pre-hook in the plugin
let incoming = request.app.podium;
// Set a view property on HttpIncoming. This can now be used in the
// document template or anywhere one have access to HttpIncoming.
incoming.view = {
title: 'My pretty site'
};
// Pass HttpIncoming on to the fetch method. This will pass the
// generated context on to the request to the podlet.
const { content } = await podlet.fetch(incoming);
// Call podiumSend with the content of the podlet. This will now call
// the document template set on the layout.view property send the
// response. This will pass on HttpIncoming to the document template
// under the hood.
return h.podiumSend(content);
},
});
app.start();
import FastifyLayout from '@podium/fastify-layout';
import fastify from 'fastify';
import Layout from '@podium/layout';
const app = fastify({ logger: true });
const layout = new Layout({
name: 'myLayout',
pathname: '/',
});
const podlet = layout.client.register({
name: 'myPodlet',
uri: 'http://localhost:7100/manifest.json',
});
// Set up a document template which take HttpIncoming and a body content.
// This template will be used when .render() is called in a request.
layout.view = (incoming, body) => {
return `
<html>
<head><title>${incoming.view.title}</title></head>
<body>${body}</body>
</html>
`;
};
app.register(FastifyLayout, layout);
app.get(layout.pathname(), async (request, reply) => {
// Get the HttpIncoming object generated by the pre-hook in the plugin
const incoming = reply.app.podium;
// Set a view property on HttpIncoming. This can now be used in the
// document template or anywhere one have access to HttpIncoming.
incoming.view = {
title: 'My pretty site'
};
// Pass HttpIncoming on to the fetch method. This will pass the
// generated context on to the request to the podlet.
const { content } = await podlet.fetch(incoming);
// Call podiumSend with the content of the podlet. This will now call
// the document template set on the layout.view property send the
// response. This will pass on HttpIncoming to the document template
// under the hood.
reply.podiumSend(content);
});
const start = async () => {
try {
await app.listen(7000);
app.log.info(`server listening on ${app.server.address().port}`);
} catch (err) {
app.log.error(err);
process.exit(1);
}
}
start();
import { HttpIncoming } from '@podium/utils';
import Layout from '@podium/layout';
import http from 'http';
const layout = new Layout({
name: 'myLayout',
pathname: '/',
});
const podlet = layout.client.register({
name: 'myPodlet',
uri: 'http://localhost:7100/manifest.json',
});
// Set up a document template which take HttpIncoming and a body content.
// This template will be used when .render() is called in a request.
layout.view = (incoming, body) => {
return `
<html>
<head><title>${incoming.view.title}</title></head>
<body>${body}</body>
</html>
`;
};
const server = http.createServer(async (req, res) => {
// Create a HttpIncoming object
let incoming = new HttpIncoming(req, res);
// Set a view property on HttpIncoming. This can now be used in the
// document template or anywhere one have access to HttpIncoming.
incoming.view = {
title: 'My pretty site',
};
// Pass HttpIncoming on to the layout processor. This will generate
// the context and store it on HttpIncoming among other things
incoming = await layout.process(incoming);
// Pass HttpIncoming on to the fetch method. This will pass the generated
// context on to the request to the podlet.
const { content } = await podlet.fetch(incoming);
// Pass HttpIncoming and the content of the podlet to the render method.
// This will now call the document template set on the layout.view property.
const html = layout.render(incoming, content);
res.statusCode = 200;
res.setHeader('Content-Type', 'text/html');
res.end(html);
});
server.listen(7000);
Constructor
Create a new HttpIncoming instance.
import { HttpIncoming } from '@podium/utils';
const incoming = new HttpIncoming(request, response, params);
options
option | type | default | required | details |
---|---|---|---|---|
request | http.IncomingMessage | null | ✓ | A raw Node.js HTTP request object |
response | http.ServerResponse | null | ✓ | A raw Node.js HTTP response object |
params | object | {} | Request scoped parameters |
request
A raw Node.js http.IncomingMessage
object.
If used with an HTTP framework please note that some frameworks operate with
their own "request" objects as a wrapper around http.IncomingMessage
. In such
cases it is often necessary to gain access to the raw http.IncomingMessage
object through a property or method.
response
A raw Node.js http.ServerResponse
object.
If used with an HTTP framework please note that some frameworks operate with
their own "request" objects as a wrapper around http.IncomingMessage
. In such
cases it is often necessary to gain access to the raw http.IncomingMessage
object through a property or method.
params
An object for passing arbitrary property values for Podium to use.
Note: When using any of the supported HTTP frameworks, params
is usually
picked up from a special properties object on the request (eg. res.locals
in
Express.js). Please see the the relevant plugin for the appropriate HTTP
framework for further information.
One very common use case for this is to pass a request bound property to a
context parser. There are cases where you may want to perform operations on
requests prior to running the .middleware()
or .process()
methods in a
layout or podlet and then pass the results of these operations on to a context
parser.
The locale context parser does this when setting the request bound locale value:
- Express
- Hapi
- Fastify
- HTTP
const app = express();
const layout = new Layout({
name: 'myLayout',
pathname: '/',
});
const podlet = layout.client.register({
name: 'myPodlet',
uri: 'http://localhost:7100/manifest.json',
});
// Set a locale param to 'nb-NO' on res.locals
app.use((req, res, next) => {
res.locals = {
locale: 'nb-NO',
};
next();
});
// Attach the middleware on Express. This will create HttpIncoming under the
// hood plus generate the context where the locale param will be picked up from
// res.locals
app.use(layout.middleware());
app.get('/', (req, res) => {
// Get the HttpIncoming object generated by the layout.middleware()
let incoming = res.locals.podium;
// Pass HttpIncoming on to the fetch method. This will pass the generated
// context where locale now is `nb-NO` on to the request to the podlet.
const { content } = await podlet.fetch(incoming);
[ ... snip ...]
});
const app = Hapi.Server({
host: 'localhost',
port: 7000,
});
const layout = new Layout({
name: 'myLayout',
pathname: '/',
});
const podlet = layout.client.register({
name: 'myPodlet',
uri: 'http://localhost:7100/manifest.json',
});
// Register the Hapi Layout Plugin. This will create HttpIncoming under the
// hood plus generate the context where the locale param will be picked up from
// request.app.params
app.register({
plugin: new HapiLayout(),
options: layout,
});
// Set a locale param to 'nb-NO' on request.app.params
app.ext({
type: 'onRequest',
method: async (request, h) => {
request.app.params = {
locale: 'nb-NO',
};
return h.continue;
},
});
app.route({
method: 'GET',
path: layout.pathname(),
handler: (request, h) => {
// Get the HttpIncoming object generated by the pre-hook in the plugin
let incoming = request.app.podium;
// Pass HttpIncoming on to the fetch method. This will pass the generated
// context where locale now is `nb-NO` on to the request to the podlet.
const { content } = await podlet.fetch(incoming);
[ ... snip ...]
},
});
const app = fastify();
const layout = new Layout({
name: 'myLayout',
pathname: '/',
});
const podlet = layout.client.register({
name: 'myPodlet',
uri: 'http://localhost:7100/manifest.json',
});
// Register the Fastify Layout Plugin. This will create HttpIncoming under the
// hood plus generate the context where the locale param will be picked up from
// reply.app.params
app.register(FastifyLayout, layout);
// Set a locale param to 'nb-NO' on reply.app.params
app.addHook('onRequest', (request, reply, next) => {
reply.app.params = {
locale: 'nb-NO',
};
next()
})
app.get(layout.pathname(), async (request, reply) => {
// Get the HttpIncoming object generated by the pre-hook in the plugin
const incoming = reply.app.podium;
// Pass HttpIncoming on to the fetch method. This will pass the
// generated context on to the request to the podlet.
const { content } = await podlet.fetch(incoming);
[ ... snip ...]
});
const layout = new Layout({
name: 'myLayout',
pathname: '/',
});
const podlet = layout.client.register({
name: 'myPodlet',
uri: 'http://localhost:7100/manifest.json',
});
const server = http.createServer(async (req, res) => {
// Create a HttpIncoming object and set a locale param to 'nb-NO'
let incoming = new HttpIncoming(req, res, {
locale: 'nb-NO',
});
// Pass HttpIncoming on to the layout processor. This will generate
// the context where the local parser will read the locale parameter
// from HttpIncoming.
incoming = await layout.process(incoming);
// Pass HttpIncoming on to the fetch method. This will pass the generated
// context where locale now is `nb-NO` on to the request to the podlet.
const { content } = await podlet.fetch(incoming);
[ ... snip ...]
});
Properties
An HttpIncoming instance has the following properties:
property | type | getter | setter | default | details |
---|---|---|---|---|---|
development | boolean | ✓ | ✓ | false | Hint regarding whether the podlet / layout are in development mode or not |
response | http.ServerResponse | ✓ | null | A raw Node.js HTTP response object set through the response argument in the constructor | |
request | http.IncomingMessage | ✓ | null | A raw Node.js HTTP request object set through the request argument in the constructor | |
context | object | ✓ | ✓ | {} | The context created by the context parser |
podlets | array | ✓ | null | Array of client response objects. Used in @podium/layout . | |
params | object | ✓ | {} | Params set through the params argument in the constructor | |
proxy | boolean | ✓ | ✓ | false | Whether the request was handled by the proxy or not |
name | string | ✓ | ✓ | '' | The name of the podlet / layout |
view | object | ✓ | ✓ | {} | View parameters for the document template |
url | URL | ✓ | {} | A URL object created out of the original request | |
css | array | ✓ | ✓ | [] | An array of AssetCSS objects |
js | array | ✓ | ✓ | [] | An array of AssetJS objects |
Methods
An HttpIncoming instance has the following methods:
.toJSON()
Returns JSON representation of the HttpIncoming
instance.