@superhero/http-server

4.4.6 • Public • Published

HTTP-Server

An 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.

Table of Contents

Installation

Install the package using npm:

npm install @superhero/http-server

Getting Started

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.

Usage

Basic Example

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: {
        criteria: '/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.
  • Dispatcher Registration: Register a dispatcher called 'hello-dispatcher' in the locator.
  • Server Settings: Define the routes, and possible other server configurations, in the settings object.
  • Bootstrap and Listen: Bootstrap the server with the settings and start listening on port 3000.
  • Ready to serve requests: Request to http://localhost:3000/hello will reply { "message": "Hello, World!" }.

HTTPS Setup with Self-Signed Certificate

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: {
        criteria: '/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.

Altering Response Body, Headers, and Status

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: {
        criteria: '/custom',
        dispatcher: 'custom-dispatcher',
      },
    },
  },
};

// Bootstrap and start the server
await server.bootstrap(settings);
await server.listen(3000);

Handling Aborted Requests

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: {
        criteria: '/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" }

Streaming Server-Sent Events (SSE)

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: {
        criteria: '/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" }

Custom Logging

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.

API

HttpServer

The main class responsible for handling HTTP requests.

  • Constructor: The server can be instantiated or located via the Locator.

    • Use locator.locate('@superhero/http-server') 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.

request

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.

session.view

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.

session.abortion

An AbortController used to trigger and manage dispatch abortion.

  • Methods:
    • abort(error): Aborts the request with the provided error.

Testing

The test suite uses Node.js's built-in testing module.

Running Tests

To run the tests, execute:

npm test

Test Coverage

▶ @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 | 
---------------------------------------------------------------------------------------------------------------------

License

This project is licensed under the MIT License.

Contributing

Feel free to submit issues or pull requests for improvements or additional features.

Package Sidebar

Install

npm i @superhero/http-server

Weekly Downloads

65

Version

4.4.6

License

MIT

Unpacked Size

64 kB

Total Files

12

Last publish

Collaborators

  • superhero