HTTP(S) server component supporting both HTTP 1.1 and HTTP 2.0
npm install @superhero/http-serverAn HTTP server module for Node.js that supports both HTTP/1.1 and HTTP/2 protocols, with built-in routing, HTTPS support, and stream support that defaults to server-sent events (SSE). Designed to be robust, flexible and extendible, while easy to work with.
- Installation
- Getting Started
- Usage
- Basic Example
- HTTPS Setup with Self-Signed Certificate
- Altering Response Body, Headers, and Status
- Handling Aborted Requests
- Streaming Server-Sent Events (SSE)
- Custom Logging
- API
- HttpServer
- session.view
- session.abortion
- Testing
- Coverage Report
- Contributing
- License
Install the package using npm:
``bash`
npm install @superhero/http-server
The @superhero/http-server module integrates with the @superhero/locator and @superhero/router modules to provide a flexible and modular HTTP server.
To get started, you'll need to set up a Locator instance, register your dispatchers, and then locate the HttpServer module using the locator.
`javascript
import HttpServer from '@superhero/http-server';
import Locator from '@superhero/locator';
import Router from '@superhero/router';
// Instantiate the service locator
const locator = new Locator();
// Instantiate the router
const router = new Router(locator);
// Instantiate the server
const server = new HttpServer(router);
// Register the route dispatcher service
locator.set('hello-dispatcher', {
dispatch: (request, session) => {
session.view.body.message = 'Hello, World!';
},
});
// Routes
const settings = {
router: {
routes: {
hello: {
condition: '/hello',
dispatcher: 'hello-dispatcher',
},
},
},
};
// Bootstrap and start the server
await server.bootstrap(settings);
await server.listen(3000);
`
Explanation:
- Import Statements: We instantiate the required components locator, router and server.'hello-dispatcher'
- Dispatcher Registration: Register a dispatcher called in the locator.settings
- Server Settings: Define the routes, and possible other server configurations, in the object.3000
- Bootstrap and Listen: Bootstrap the server with the settings and start listening on port .http://localhost:3000/hello
- Ready to serve requests: Request to will reply { "message": "Hello, World!" }.
`javascript
import fs from 'node:fs';
import Locator from '@superhero/locator';
// Instantiate the service locator
const locator = new Locator();
// Locate the server
const server = await locator.lazyload('@superhero/http-server');
// Register necessary services
locator.set('secure-dispatcher', {
dispatch: (request, session) => {
session.view.body = { message: 'Secure Hello, World!' };
},
});
// Server settings and routes
const serverSettings = {
server: {
key: fs.readFileSync('path/to/private.key'),
cert: fs.readFileSync('path/to/server.cert'),
},
router: {
routes: {
secure: {
condition: '/secure',
dispatcher: 'secure-dispatcher',
},
},
},
};
await server.bootstrap(serverSettings);
await server.listen(443);
`
> [!NOTE]
> Replace 'path/to/private.key' and 'path/to/server.cert' with the actual paths to your SSL key and certificate files.
`javascript
locator.set('custom-dispatcher', {
dispatch: (request, session) => {
session.view.body = { data: 'Custom Data' };
session.view.headers['Custom-Header'] = 'CustomValue';
session.view.status = 201; // HTTP 201 Created
},
});
// Update the routes in the settings
const settings = {
router: {
routes: {
custom: {
condition: '/custom',
dispatcher: 'custom-dispatcher',
},
},
},
};
// Bootstrap and start the server
await server.bootstrap(settings);
await server.listen(3000);
`
`javascript
locator.set('abort-dispatcher', {
dispatch: (request, session) => {
// Abort the request with a custom error
const error = new Error('Request Aborted');
error.code = 'E_REQUEST_ABORTED';
session.abortion.abort(error);
},
});
// Update the routes in the settings
const settings = {
router: {
routes: {
abort: {
condition: '/abort',
dispatcher: 'abort-dispatcher',
},
},
},
};
// Bootstrap and start the server
await server.bootstrap(settings);
await server.listen(3000);
`
> [!NOTE]
> Will result in a status 500 response { "error": "Request Aborted", "code": "E_REQUEST_ABORTED" }
`javascript
locator.set('sse-dispatcher', {
dispatch: (request, session) => {
// Write events to the stream
session.view.stream.write({ data: 'First message' });
session.view.stream.write({ data: 'Second message' });
// End the stream
session.view.stream.end();
},
});
// Update the routes in the settings
const settings = {
router: {
routes: {
sse: {
condition: '/sse',
dispatcher: 'sse-dispatcher',
},
},
},
};
// Bootstrap and start the server
await server.bootstrap(settings);
await server.listen(3000);
`
> [!NOTE]
> By default responds with a text/event-stream content type:`
> `
> data: { "data": "First message" }
>
> data: { "data": "Second message" }
>
You can override, or hook into, the default logging method to integrate reactions with your logging requirements.
#### Turn of logs
``
server.log.config.mute = true
#### Learn more
Read the github page for the repository this component depend on for logging: @superhero/log.
The main class responsible for handling HTTP requests.
- Constructor: The server can be instantiated or located via the Locator.locator.locate('@superhero/http-server')
- Use to get an instance.
- Methods:
- async bootstrap(settings): Bootstraps the server with the provided settings.settings
- : An object containing server and router configurations.async listen(port)
- : Starts the server on the specified port.port
- : The port number to listen on.async close()
- : Closes the server and all active sessions.
An object used to read
- Properties:
- body: The request body (Promise).method
- : The request HTTP method.headers
- : The request HTTP headers.url
- : The requested URL.
An object used within dispatchers to manipulate the response.
- Properties:
- body: The response body to be sent to the client.headers
- : An object containing response headers.status
- : HTTP status code of the response.stream
- : A writable stream for sending SSE data, or to be configured to stream some other type of response to the client.
An AbortController used to trigger and manage dispatch abortion.
- Methods:
- abort(error): Aborts the request with the provided error.
The test suite uses Node.js's built-in testing module.
To run the tests, execute:
`bash`
npm test
`
▶ @superhero/http-server
▶ Lifecycle
✔ Can instantiate HttpServer (8.609311ms)
✔ Can bootstrap server with non-secure settings (2.813603ms)
✔ Can be configured by the configuration file (37.159723ms)
✔ Listens and closes the server as expected (5.81708ms)
✔ Rejects if server is not available to listen error (2.290967ms)
✔ Rejects if server is not available to close error (1.058432ms)
✔ Lifecycle (59.459503ms)
▶ Routing and Requests
▶ HTTP/1
✔ Can dispatch a request aligned to the route map (42.67787ms)
✔ Can alter the output body (5.709405ms)
✔ Can stream HTML5 standard Server-Sent Events (SSE) (9.72838ms)
✔ Can alter the output headers (9.330729ms)
✔ Can alter the output status (7.159825ms)
✔ Can abort the dispatcher (5.969359ms)
✔ Can describe an abortion in detail (7.225311ms)
✔ Can manage thrown errors in the dispatcher (10.332202ms)
✔ Can not mistakenly access the wrong view property (7.490531ms)
✔ Can not mistakenly assign a value to the wrong view property (5.522195ms)
✔ Support connection keep-alive header (10.362687ms)
✔ HTTP/1 (122.952777ms)
▶ HTTP/2
✔ Can dispatch a request aligned to the route map (24.833859ms)
✔ Can alter the output body (8.516916ms)
✔ Can stream HTML5 standard Server-Sent Events (SSE) (10.336142ms)
✔ Can alter the output headers (8.209538ms)
✔ Can alter the output status (7.35682ms)
✔ Can abort the dispatcher (8.554265ms)
✔ Can describe an abortion in detail (5.330231ms)
✔ Can manage thrown errors in the dispatcher (9.391412ms)
✔ Can not mistakenly access the wrong view property (7.222525ms)
✔ Can not mistakenly assign a value to the wrong view property (8.57349ms)
✔ HTTP/2 (99.758519ms)
✔ Routing and Requests (222.916463ms)
▶ HTTPS server with self-signed certificate
▶ TLSv1.2
▶ RSA:2048
✔ HTTP1 (10.68221ms)
✔ HTTP2 (14.607846ms)
✔ RSA:2048 (184.393685ms)
▶ RSA:4096
✔ HTTP1 (11.166249ms)
✔ HTTP2 (14.376707ms)
✔ RSA:4096 (239.998059ms)
▶ ECDSA:P-256
✔ HTTP1 (6.998372ms)
✔ HTTP2 (9.255564ms)
✔ ECDSA:P-256 (52.737888ms)
▶ ECDSA:P-384
✔ HTTP1 (8.610887ms)
✔ HTTP2 (9.7637ms)
✔ ECDSA:P-384 (52.826908ms)
▶ ECDSA:P-521
✔ HTTP1 (9.391868ms)
✔ HTTP2 (13.179682ms)
✔ ECDSA:P-521 (62.741409ms)
▶ EdDSA:Ed25519
✔ HTTP1 (10.110816ms)
✔ HTTP2 (9.99596ms)
✔ EdDSA:Ed25519 (58.01589ms)
▶ EdDSA:Ed448
✔ HTTP1 (4.651357ms)
✔ HTTP2 (10.031462ms)
✔ EdDSA:Ed448 (51.550013ms)
✔ TLSv1.2 (703.01496ms)
▶ TLSv1.3
▶ RSA:2048
✔ HTTP1 (6.43647ms)
✔ HTTP2 (9.551209ms)
✔ RSA:2048 (113.791235ms)
▶ RSA:4096
✔ HTTP1 (18.396852ms)
✔ HTTP2 (22.414178ms)
✔ RSA:4096 (819.288505ms)
▶ ECDSA:P-256
✔ HTTP1 (7.036644ms)
✔ HTTP2 (11.842337ms)
✔ ECDSA:P-256 (100.196088ms)
▶ ECDSA:P-384
✔ HTTP1 (8.183114ms)
✔ HTTP2 (12.428711ms)
✔ ECDSA:P-384 (61.367513ms)
▶ ECDSA:P-521
✔ HTTP1 (12.446168ms)
✔ HTTP2 (15.564381ms)
✔ ECDSA:P-521 (68.39823ms)
▶ EdDSA:Ed25519
✔ HTTP1 (4.44369ms)
✔ HTTP2 (11.703458ms)
✔ EdDSA:Ed25519 (54.613453ms)
▶ EdDSA:Ed448
✔ HTTP1 (13.499592ms)
✔ HTTP2 (11.474115ms)
✔ EdDSA:Ed448 (68.423656ms)
✔ TLSv1.3 (1287.220809ms)
✔ HTTPS server with self-signed certificate (1990.42993ms)
✔ @superhero/http-server (2273.646154ms)
tests 69
suites 8
pass 69
---------------------------------------------------------------------------------------------------------------------
file | line % | branch % | funcs % | uncovered lines
---------------------------------------------------------------------------------------------------------------------
index.js | 91.75 | 91.18 | 74.07 | 92-94 128-129 135-137 266-269 369-373 389-394 397-402 405-410
index.test.js | 100.00 | 100.00 | 100.00 |
middleware | | | |
upstream | | | |
header | | | |
accept.js | 19.23 | 100.00 | 33.33 | 10-51
content-type.js | 20.00 | 100.00 | 50.00 | 9-44
content-type | | | |
application | | | |
json.js | 31.03 | 100.00 | 0.00 | 9-28
method.js | 23.68 | 100.00 | 50.00 | 9-37
view.js | 92.98 | 88.89 | 84.21 | 133-138 196-200 238-239 247-253
---------------------------------------------------------------------------------------------------------------------
all files | 86.57 | 93.96 | 83.82 |
---------------------------------------------------------------------------------------------------------------------
``
This project is licensed under the MIT License.
Feel free to submit issues or pull requests for improvements or additional features.