Node.js
This module provides the integration between Gruber and Node.js, along with platform-specific utilitites and Gruber primatives.
There are also opt-in modules for specific integrations and a polyfill if you are using an older Node.js. You have to import these with specific paths, they are not included in the default export.
Install
Gruber is available through NPM for Node.js.
npm install gruber
Integrations
There are platform-specific integrations with the Configuration, Postgres & Terminator modules:
import postgres from "postgres";
import { getConfiguration, getPostgresMigrator, getTerminator } from "gruber";
// Get a Node.js specific Configuration instance that
// loads files using 'fs' and parses them through JSON
const config = getConfiguration();
// Get a Migrator using the Node.js filesystem and
// the postgres.js library
const migrator = getPostgresMigrator({
sql: postgres("postgres://…"),
directory: new URL("./migrations/", import.meta.url),
});
// Get a terminator that listens to Node.js' process signals
const arnie = getTerminator();
Utilities
There are some Node.js specific utilities too, to help with Gruber integration and web-standards.
import { serveHTTP } from "gruber";
// Create a node:http server, wrapped with the Fetch API Request/Response objects.
serveHTTP({ port: 3000 }, async (request) => {
return Response.json({ message: "ok" });
});
Polyfil
// Import this as soon as possible to ensure
// the web-standards primatives Gruber expects are available.
import "gruber/polyfill.js";
Express
There is a middleware for using a FetchRouter
with an Express application.
import express from "express"
import { FetchRouter } from "gruber";
import { expressMiddleware } from "gruber/express-router.js";
const router = new FetchRouter(…)
const app = express()
.use(…)
.use(expressMiddleware(router))
.use(…)
Koa
There is a middleware for using a FetchRouter
with a koa application.
import Koa from "koa"
import { FetchRouter } from "gruber";
import { koaMiddleware } from "gruber/koa-router.js";
const router = new FetchRouter(…)
const app = new Koa()
.use(…)
.use(koaMiddleware(router));
.use(…)
Miscellaneous
getConfigurationOptions
Generate standardish options to create a Configuration from the Node.js environment that reads JSON files.
- It uses parseArgs from
node:util
to parse CLI arguments - It uses promises.readFile from
node:fs
to read text files - It reads environment variables from
node:process
- It parses and stringifies configuration using
JSON
const options = getConfigurationOptions()
getConfiguration
Create a standardish Node.js Configuration. It creates a new Configuration object using getConfigurationOptions.
const config = getConfiguration()
createStoppable
A port of stoppable.js, ported to Gruber to reduce external dependencies.
Adapted from stoppable.js
NodeRouter
A HTTP router for pure Node.js, you should probably use serveHTTP
import http from "node:http";
const router = new NodeRouter(...)
const server = http.createServer(router.forHttpServer())
server.listen(3000)
getPostgresMigratorOptions
Create a standardish Postgres Migrator based on the filesystem and an sql connection from postgres.js
const sql = postgres(…)
const migrator = getPostgresMigratorOptions({
sql,
directory: new URL("./migrations/", import.meta.url)
})
getPostgresMigrator
This is a syntax sugar for new Migrator(getPostgresMigratorOptions(...))
HTTP
applyResponse
Send a web-standards Response to a Node.js ServerResponse
import http from "node:http"
http.createServer((req, res) => {
applyResponse(
Response.json({ msg: "ok" }),
res
)
})
getFetchRequest
Convert a Node.js IncomingMessage into a web-standards Request
import http from "node:http"
http.createServer((req, res) => {
let request = getFetchRequest(req)
// ...
})
getFetchHeaders
Parse Node.js IncomingHttpHeaders into a web-standards Headers object
const headers = getFetchHeaders({ accept: "text/plain" }) // Headers
getIncomingMessageBody
Convert the body of a Node.js IncomingMessage into a Streams API ReadableStream
import http from "node:http"
http.createServer((req, res) => {
let stream = getIncomingMessageBody(req)
// ...
})
getResponseReadable
Convert a Streams API ReadableStream into a Readable to later be piped to a Node.js ServerResponse
import http from "node:http"
http.createServer((req, res) => {
const webResponse = Response.json({ msg: "OK" })
getResponseReadable(webResponse, res).pipe(res)
})
Pass the second, res
parameter if you'd like to terminate the web Response if Node.js is terminated.
serveHTTP
unstable
A simple abstraction for creating a HTTP server, converting Node.js primatives into Fetch API objects and handling requests through a FetchRouter.
const server = await serveHTTP({ port: 3000 }, async (request) => {
return new Response('Hello, There!')
})
This method returns a node:http
Server after waiting for it to start listening.
The server has an extra stop
method and also implements [Symbol.asyncDispose]
.
When stop is called, or it is dispoed with the using
keyword, it will attempt to gracefully shutdown the HTTP server,
attempting to terminate each connection. If you created the server with a grace
option,
it will wait for that maximum time before forcing every connection to close.
To quote the author of stoppable, this is "the way you probably expected it to work by default".
async function main() {
await using server = await serveHTTP(
{ port: 3000, grace: 5000 },
() => new Response('ok')
)
}
await main()
When main function exits, it will automatically close the server with a 5 second grace period.
The stop method is also useful when used with a Terminator.
debug
{ "getConfigurationOptions": { "entrypoint": "node/mod.ts", "id": "getConfigurationOptions", "name": "getConfigurationOptions", "content": "Generate standardish options to create a Configuration from the Node.js environment that reads JSON files.\n\n- It uses parseArgs from `node:util` to parse CLI arguments\n- It uses promises.readFile from `node:fs` to read text files\n- It reads environment variables from `node:process`\n- It parses and stringifies configuration using `JSON`\n\n```js\nconst options = getConfigurationOptions()\n```", "tags": { "group": "Miscellaneous" }, "children": {} }, "getConfiguration": { "entrypoint": "node/mod.ts", "id": "getConfiguration", "name": "getConfiguration", "content": "Create a standardish Node.js Configuration.\nIt creates a new Configuration object using [getConfigurationOptions](#getconfigurationoptions).\n\n```js\nconst config = getConfiguration()\n```", "tags": { "group": "Miscellaneous" }, "children": {} }, "applyResponse": { "entrypoint": "node/mod.ts", "id": "applyResponse", "name": "applyResponse", "content": "Send a web-standards Response to a Node.js [ServerResponse](https://nodejs.org/api/http.html#class-httpserverresponse)\n\n```js\nimport http from \"node:http\"\n\nhttp.createServer((req, res) => {\n\tapplyResponse(\n\t\tResponse.json({ msg: \"ok\" }),\n\t\tres\n\t)\n})\n```", "tags": { "group": "HTTP" }, "children": {} }, "getFetchRequest": { "entrypoint": "node/mod.ts", "id": "getFetchRequest", "name": "getFetchRequest", "content": "Convert a Node.js [IncomingMessage](https://nodejs.org/api/http.html#class-httpincomingmessage) into a\nweb-standards [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request)\n\n```js\nimport http from \"node:http\"\n\nhttp.createServer((req, res) => {\n\tlet request = getFetchRequest(req)\n\t// ...\n})\n```", "tags": { "group": "HTTP" }, "children": {} }, "getFetchHeaders": { "entrypoint": "node/mod.ts", "id": "getFetchHeaders", "name": "getFetchHeaders", "content": "Parse Node.js IncomingHttpHeaders into a web-standards [Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers) object\n\n```js\nconst headers = getFetchHeaders({ accept: \"text/plain\" }) // Headers\n```", "tags": { "group": "HTTP" }, "children": {} }, "getIncomingMessageBody": { "entrypoint": "node/mod.ts", "id": "getIncomingMessageBody", "name": "getIncomingMessageBody", "content": "Convert the body of a Node.js [IncomingMessage](https://nodejs.org/api/http.html#class-httpincomingmessage) into a Streams API ReadableStream\n\n```js\nimport http from \"node:http\"\n\nhttp.createServer((req, res) => {\n\tlet stream = getIncomingMessageBody(req)\n\t// ...\n})\n```", "tags": { "group": "HTTP" }, "children": {} }, "getResponseReadable": { "entrypoint": "node/mod.ts", "id": "getResponseReadable", "name": "getResponseReadable", "content": "Convert a Streams API ReadableStream into a Readable to later be piped to a Node.js [ServerResponse](https://nodejs.org/api/http.html#class-httpserverresponse)\n\n```js\nimport http from \"node:http\"\n\nhttp.createServer((req, res) => {\n\tconst webResponse = Response.json({ msg: \"OK\" })\n\tgetResponseReadable(webResponse, res).pipe(res)\n})\n```\n\nPass the second, `res` parameter if you'd like to terminate the web Response if Node.js is terminated.", "tags": { "group": "HTTP" }, "children": {} }, "serveHTTP": { "entrypoint": "node/mod.ts", "id": "serveHTTP", "name": "serveHTTP", "content": "A simple abstraction for creating a HTTP server, converting Node.js primatives into Fetch API objects and handling requests through a FetchRouter.\n\n```js\nconst server = await serveHTTP({ port: 3000 }, async (request) => {\n\treturn new Response('Hello, There!')\n})\n```\n\nThis method returns a `node:http` Server after waiting for it to start listening.\nThe server has an extra `stop` method and also implements `[Symbol.asyncDispose]`.\n\nWhen stop is called, or it is dispoed with the `using` keyword, it will attempt to gracefully shutdown the HTTP server,\nattempting to terminate each connection. If you created the server with a `grace` option,\nit will wait for that maximum time before forcing every connection to close.\nTo quote the author of stoppable, this is \"the way you probably expected it to work by default\".\n\n```js\nasync function main() {\n\tawait using server = await serveHTTP(\n\t\t{ port: 3000, grace: 5000 },\n\t\t() => new Response('ok')\n\t)\n}\n\nawait main()\n```\n\nWhen main function exits, it will automatically close the server with a 5 second grace period.\n\nThe stop method is also useful when used with a [Terminator](/core/#terminator).", "tags": { "unstable": "true", "group": "HTTP" }, "children": {} }, "createStoppable": { "entrypoint": "node/mod.ts", "id": "createStoppable", "name": "createStoppable", "content": "A port of stoppable.js, ported to Gruber to reduce external dependencies.\n\nAdapted from [stoppable.js](https://github.com/hunterloftis/stoppable/blob/master/lib/stoppable.js)", "tags": { "hidden": "true", "group": "Miscellaneous" }, "children": {} }, "NodeRouter": { "entrypoint": "node/mod.ts", "id": "NodeRouter", "name": "NodeRouter", "content": "A HTTP router for pure Node.js, you should probably use [serveHTTP](#servehttp)\n\n```js\nimport http from \"node:http\";\n\nconst router = new NodeRouter(...)\nconst server = http.createServer(router.forHttpServer())\nserver.listen(3000)\n```", "tags": { "hidden": "true", "group": "Miscellaneous" }, "children": {} }, "getPostgresMigratorOptions": { "entrypoint": "node/mod.ts", "id": "getPostgresMigratorOptions", "name": "getPostgresMigratorOptions", "content": "Create a standardish Postgres Migrator based on the filesystem and an sql connection from [postgres.js](https://github.com/porsager/postgres)\n\n```js\nconst sql = postgres(…)\n\nconst migrator = getPostgresMigratorOptions({\n\tsql,\n\tdirectory: new URL(\"./migrations/\", import.meta.url)\n})\n\n```", "tags": { "group": "Miscellaneous" }, "children": {} }, "getPostgresMigrator": { "entrypoint": "node/mod.ts", "id": "getPostgresMigrator", "name": "getPostgresMigrator", "content": "This is a syntax sugar for `new Migrator(getPostgresMigratorOptions(...))`", "tags": { "param": "{PostgresMigratorOptions} options", "group": "Miscellaneous" }, "children": {} } }