Skip to main content

InversifyUwebSocketsHttpAdapter

The uWebSockets.js HTTP adapter implementation. This adapter allows you to use InversifyJS framework with uWebSockets.js, one of the fastest HTTP server implementations available.

Base class documentation

This adapter extends InversifyHttpAdapter. See the base class documentation for information about common methods like applyGlobalMiddleware, useGlobalFilters, applyGlobalGuards, useGlobalInterceptors, and useGlobalPipe.

Installation

npm install @inversifyjs/http-uwebsockets uWebSockets.js inversify reflect-metadata

Constructor

constructor(
container: Container,
httpAdapterOptions?: UwebSocketsHttpAdapterOptions,
customApp?: TemplatedApp,
)

Creates a uWebSockets adapter instance.

Parameters

  • container: The Inversify container that holds controllers, guards, pipes, middleware, interceptors, and filters.
  • httpAdapterOptions (optional): Configuration options for the adapter. See Options below.
  • customApp (optional): A custom uWebSockets.js TemplatedApp instance (created with App() or SSLApp()). If not provided, a default HTTP app is created.

Default Options

The adapter uses these defaults if not overridden:

{
logger: true,
}

Methods

build

async build(): Promise<TemplatedApp>

Builds and returns the uWebSockets.js application with all configured routes, middleware, and handlers.

Returns: The uWebSockets.js TemplatedApp instance ready to be used with app.listen().

Options

UwebSocketsHttpAdapterOptions

type UwebSocketsHttpAdapterOptions = HttpAdapterOptions;

Currently, the uWebSockets adapter uses the base HttpAdapterOptions:

Properties

  • logger: Set to true to log route mappings on build, or false to disable logging, or provide a custom logger implementing the Logger interface from @inversifyjs/logger. Default: true

Usage Example

const container: Container = new Container();
// ... bind your controllers, services, etc.

// Create the adapter with options
const adapter: InversifyUwebSocketsHttpAdapter =
new InversifyUwebSocketsHttpAdapter(container, {
logger: true,
});

// Build the uWebSockets application
const app = await adapter.build();

// Start the server
app.listen('0.0.0.0', 3000, (socket) => {
if (socket !== false) {
const port: number = us_socket_local_port(socket);
console.log(`Server listening on port ${String(port)}`);
} else {
console.error('Failed to start server');
}
});

uWebSockets.js-Specific Features

Extreme Performance

uWebSockets.js is benchmarked as one of the fastest HTTP server implementations in existence, not just in Node.js. It provides microsecond-level response times and can handle millions of requests with minimal resource usage.

SSL/TLS Support

You can create an SSL-enabled server by passing a custom SSLApp() instance:

import { SSLApp } from 'uWebSockets.js';

const sslApp = SSLApp({
key_file_name: 'path/to/key.pem',
cert_file_name: 'path/to/cert.pem',
});

const adapter = new InversifyUwebSocketsHttpAdapter(
container,
{ logger: true },
sslApp,
);

WebSocket Support

While this adapter focuses on HTTP, uWebSockets.js also provides excellent WebSocket support. You can combine InversifyJS HTTP controllers with native uWebSockets.js WebSocket handlers.

Body Parsing

Body parsing in uWebSockets.js is handled asynchronously due to the streaming nature of the API. The adapter automatically awaits body parameters decorated with @Body().

Backpressure Handling

uWebSockets.js requires careful handling of response streams to respect backpressure. The adapter handles this automatically when using @Response() parameter decorators with streams.

Request transformers

uWebSockets.js invalidates its HttpRequest object as soon as a route handler awaits, so any code reading the request after asynchronous work throws. Request transformers are a uWebSockets-specific, opt-in way to replace the request object at the very start of a matched route, before global middlewares, route middlewares, guards, route value metadata injection and parameter extraction run.

@UseRequestTransformers(...) accepts one or more transformer functions on a class or method. Each transformer receives the current request, the response, and the adapter accessors (getBody, getHeaders, getMethod, getParams, getQuery, getUrl, ...), and returns the request to use for the rest of the chain, either synchronously or as a promise. Transformers are applied sequentially in registration order, so each one receives the request produced by the previous one. Class-level transformers run before method-level ones. Errors thrown (or promise rejections) inside a transformer are handled by the same error filters used for middleware failures.

import { Controller, Get, Request } from '@inversifyjs/http-core';
import {
type RequestTransformer,
UseRequestTransformers,
} from '@inversifyjs/http-uwebsockets';
import { type HttpRequest, type HttpResponse } from 'uWebSockets.js';

export interface TenantHttpRequest extends HttpRequest {
tenantId: string;
}

// Transformers run before middlewares, guards and parameter extraction
const captureTenantId: RequestTransformer<HttpRequest, HttpResponse> = (
request: HttpRequest,
): HttpRequest => {
const tenantHttpRequest: TenantHttpRequest = request as TenantHttpRequest;

tenantHttpRequest.tenantId = request.getHeader('x-tenant-id');

return tenantHttpRequest;
};

@Controller('/tenants')
export class TenantsController {
@UseRequestTransformers(captureTenantId)
@Get('/current')
public async getCurrentTenant(
@Request() request: TenantHttpRequest,
): Promise<string> {
return request.tenantId;
}
}

Routes without transformers keep the same handler shape as before, so this feature adds no per-request cost to routes that do not use it.

uWebSockets.js only

RequestTransformer, @UseRequestTransformers and @CaptureRequestValues are exported from @inversifyjs/http-uwebsockets. The Express, Express v4, Fastify and Hono adapters own a stable request object for the whole chain and do not support request transformers.

Capturing request values

@CaptureRequestValues(options) is a method decorator that registers a request transformer taking a snapshot of the request values you enable, before any await happens, and replaces the request with a Proxy serving those snapshots. Reads of the captured kinds then keep working after asynchronous work. Applying it more than once on the same method throws.

interface CaptureRequestValuesOptions {
headers?: boolean;
method?: boolean;
params?: false | string[];
query?: boolean;
url?: boolean;
}

Omitted or false options are not captured. params takes an explicit list of route parameter names to snapshot.

  • headers: all headers, so getHeader(), forEach() and cookies reads work later.
  • method: the HTTP method.
  • params: only the named route params you list, so later @Params({ name }) reads keep working.
  • query: the raw query string, so full and per-key query reads work later. Capturing url also captures the raw query string, since the query string is part of the URL.
  • url: the URL.

Body is not captured: buffering chunked request bodies in memory can exhaust RAM. Keep using @Body() for body reads; capture the other request values that must survive an await.

import {
Body,
Controller,
Headers,
Params,
Post,
} from '@inversifyjs/http-core';
import { CaptureRequestValues } from '@inversifyjs/http-uwebsockets';

export interface AuditBody {
action: string;
}

export interface AuditEntry {
action: string;
storeId: string;
userAgent: string | string[] | undefined;
userId: string;
}

@Controller('/store/:storeId/users')
export class StoreUsersController {
@CaptureRequestValues({
headers: true,
params: ['storeId', 'userId'],
})
@Post('/:userId/audit')
public async createUserAudit(
@Body() body: AuditBody,
@Headers({ name: 'user-agent' }) userAgent: string | string[] | undefined,
@Params({ name: 'storeId' }) storeId: string,
@Params({ name: 'userId' }) userId: string,
): Promise<AuditEntry> {
return {
action: body.action,
storeId,
userAgent,
userId,
};
}
}

Kinds that were not captured are not served from the native request: calling their APIs on a captured request throws an error stating which kind is missing, instead of failing with the uWebSockets.js post-await access error.

Global pre-handler middlewares

uWebSockets.js has no native global-middleware hook. Global pre-handler middlewares (registered via applyGlobalMiddleware without isPostHandler: true) are implemented by chaining them into the handler list of every registered route. Additionally, a wildcard fallback route (app.any('/*', ...)) is registered after all controller routes to ensure the global pre-handlers also fire for requests to unmatched paths. The fallback route ends the response with HTTP 404 after running the global pre-handler chain.

Type Parameters

The adapter is strongly typed with uWebSockets.js types:

InversifyUwebSocketsHttpAdapter extends InversifyHttpAdapter<
HttpRequest, // uWebSockets.js HttpRequest
HttpResponse, // uWebSockets.js HttpResponse
() => void, // Next function
void, // Handler return type
UwebSocketsHttpAdapterOptions
>

Performance Considerations

  • uWebSockets.js uses a completely different architecture than Node.js's built-in HTTP module
  • Responses must be sent within the callback scope or corked for optimal performance
  • The adapter handles these details automatically, but custom middleware should be aware of these constraints

See Also