HTTP nodes for Node-RED, built with
@bonsae/nrg on the platform-native
fetch API — no
request/axios/body-parser dependency. The package mirrors the config
surface of Node-RED's core http request / http in / http response nodes so
a flow author migrating over sees the same knobs.
Makes an outbound HTTP request with fetch and emits the response under
msg.output. A handful of msg properties override the configured values at
runtime (msg.method / msg.url / msg.headers / msg.payload).
| Field | Notes |
|---|---|
| method | GET · POST · PUT · DELETE · HEAD · OPTIONS · PATCH · use (read msg.method at runtime) |
| url | typed input (str / msg); supports {{mustache}} tags resolved against the message. A scheme-less URL is assumed http:// |
| return | txt = UTF-8 string · bin = Buffer · obj = parsed JSON (falls back to raw text if the body isn't JSON) |
| **payload → ** | ignore (default) · query (append msg.payload object to the URL) · body (send as the request body) |
| headers | typed input (json / msg); merged with msg.headers (which wins). Object payloads default to application/json |
| auth | `` (none) · basic (user + password) · `bearer` (token) — credentials are stored encrypted. `digest` is not supported yet |
| keep-alive / insecure parser / send errors | persist reuses the TCP connection; senderr emits request errors as a normal message (statusCode: 0) instead of failing the node |
Output — msg.output = { statusCode, headers, payload, responseUrl }.
Listens on a path of Node-RED's user HTTP server (RED.httpNode) and emits one
message per request. No wire input.
| Field | Notes |
|---|---|
| method | get · post · put · delete · patch |
| url | path to listen on, e.g. /hello or /user/:id |
Output — msg.output = { payload, req }, where payload is the query object
(GET) or the parsed body (POST/PUT/PATCH/DELETE), and req is a clone-safe
snapshot { method, url, headers, query, params, body }. The live res
socket never rides the wire — it travels on the off-the-wire private lane (see
below), so http-response can recover it from anywhere downstream.
Writes the reply for a request started by http-in. No wire output.
| Field | Notes |
|---|---|
| statusCode | blank = msg.statusCode, else 200 |
| headers | typed input (json / msg); merged with msg.headers (which wins). Object payloads default to application/json |
It reads the live socket off msg.private.res, replies with msg.output
(from another nrg node) or the top-level message (a raw/injected message), and
claims the socket so a second http-response for the same request is a no-op.
A live request/response socket is a non-serializable live object — it cannot ride
the message wire (Node-RED clones messages), and threading a correlation id
through every intermediate node is brittle. Instead this package uses nrg's
private lane: an off-the-wire, package-scoped store keyed by the message's
_msgid, which nrg carries forward across every node.
http-inparks the livereson the private lane (msg.private.res) and emits only the clone-safe snapshot.- nrg preserves
_msgidthrough any intermediate nodes, so the lane entry stays reachable no matter how the flow is wired. http-responsereadsmsg.private.resback and replies — the socket survived the trip without ever being serialized.
Because the lane is keyed per request, concurrent requests never cross
responses — each caller is answered on its own socket even when completion
order is scrambled. If a request is never answered, http-in ends it with a
504 after an idle timeout so an abandoned socket can't hang the client.
pnpm install
pnpm build # bundles the nodes into dist/ (declares @bonsae/nrg-runtime)
pnpm dev # boots a Node-RED editor with the nodes loadedpnpm validate # tsc (server/client/tests) + eslint + prettier
pnpm test # server unit + integration (real HTTP round-trip)
pnpm test:server:unit
pnpm test:server:integration[inject] --> [http-request GET https://api.example.com/thing] --> [debug]
[http-in GET /hello] --> [function / any nrg node] --> [http-response]
Wire an http-in to an http-response (optionally through any number of nodes)
to serve a route; wire http-request after an inject/function to call an
external API and route msg.output.payload onward.
MIT © Allan Oricil