What this package owns
@spraxium/http is the transport boundary between your Discord bot and external HTTP clients. It boots a Hono-based server, applies shared middleware and guards, turns controller metadata into executable routes, and exposes a BotBridge abstraction so controllers can interact with guilds, members, and moderation APIs without depending on a specific Discord runtime mode. Every piece of this pipeline, from plugin resolution to graceful shutdown, is managed by a single service called HttpServer.
The package follows a three-layer model. Plugin configuration defines behavior such as host, port, sharding mode, and security policy. Module metadata declares the controllers, services, guards, and middleware that form the API surface. HttpServer reads both layers at startup and produces a fully wired Hono application bound to @hono/node-server. This separation means configuration decisions live outside code, route contracts live in decorators, and runtime wiring is hidden behind a predictable lifecycle.
Understanding this ownership model is the key to using the package effectively. Every other page in the HTTP category builds on this foundation, so spending time here prevents confusion when you reach routing, security, or bridge topics later.
Internal package map
Hono as the HTTP foundation
The package uses Hono as its HTTP framework instead of Express or Fastify. Hono is a lightweight, edge-compatible web framework that runs on any standard JavaScript runtime. HttpServer creates a new Hono() instance during startup, registers all middleware and route handlers on it, then passes app.fetch to @hono/node-server via the serve() function with the configured host and port.
This design means controllers and middleware interact with Hono's Context and Next types. Parameter decorators like @HttpParam, @HttpQuery, and @HttpHeader read from ctx.req, while handlers can return plain objects (auto-serialized to JSON) or native Response instances for full control. Understanding this Hono foundation helps when you need to access features outside the decorator surface, such as reading raw request bodies or setting custom response headers through ctx.res.
Global ownership model
Use one global HTTP ownership path
Do not create a local wrapper module only for HTTP. Use your root AppModule as the metadata source in defineHttp() and import HttpModule once inside AppModule. Multiple metadata roots cause ambiguous guard, middleware, and lifecycle behavior.
The single-ownership model means one plugin entry in spraxium.config.ts, one @HttpClientModule decorator on your AppModule, and one HttpModule import in the module graph. This pattern keeps lifecycle ownership explicit: the server binds once, guard policy is declared once, and middleware order is visible in one place. When teams split responsibilities, they add controllers and services to the same module metadata instead of creating competing module trees.
This constraint exists because HttpServer reads HttpClientModule metadata from the class referenced in defineHttp({ module }). If you create a second module with its own HttpClientModule, the server ignores it because only the root reference is resolved. Keeping everything on AppModule avoids silent configuration drift.
Minimal integration snapshot
import { defineHttp } from '@spraxium/http';
import { AppModule } from '../src/app.module';
export const httpPlugin = defineHttp({
enabled: true,
host: process.env.HTTP_HOST ?? '0.0.0.0',
port: Number(process.env.HTTP_PORT ?? 3000),
apiKey: process.env.HTTP_API_KEY ?? '',
sharding: false,
security: {
hidePoweredBy: true,
cors: { origins: ['https://admin.example.com'], credentials: true },
},
module: AppModule,
});Startup modes: direct vs sharded
HttpServer supports two startup paths depending on the sharding flag in HttpConfig. Understanding the difference is important because it affects when the server starts, which bridge implementation is selected, and whether a Discord Client is available in the DI container.
In direct mode (sharding: false), the server starts during onBoot and requires an injected Discord Client. If the client is missing, startup is aborted with a logged error. BridgeFactory creates a DirectBotBridge that accesses guilds, members, and bans through the client's cache and API methods directly.
In sharded mode (sharding: true), the server does not start during onBoot. Instead, a static block in HttpServer registers a hook with ParentHookRegistry. When the parent process spawns shards, this hook receives the ShardingManager instance and starts the server from outside the normal boot lifecycle. BridgeFactory creates a ShardedBotBridge that uses manager.broadcastEval() to reach guilds across shards. This mode also stores the manager reference in HttpRegistry so it survives the static initialization context.
Runtime flow at a glance
Resolve plugin configuration
HttpServer reads the HTTP plugin entry from ConfigStore via getPluginConfig(defineHttp). That object carries host, port, sharding mode, security policy, and the module class reference. If no config is found or enabled is false, the server skips startup entirely and logs a warning.
Select startup strategy
In direct mode, onBoot requires an injected Discord Client. In sharded mode, a static ParentHookRegistry hook receives the ShardingManager and calls server.start() from outside the normal lifecycle. Both paths converge on the same start() method that builds the Hono application.
Create BotBridge
BridgeFactory.create() checks whether a ShardingManager or Client is available and returns the matching bridge. The bridge instance is added to the DI dependency map so controllers and services can inject BotBridge as a constructor parameter.
Apply global security layer
The server registers middleware in this fixed order: X-Powered-By removal, SecurityHeadersMiddleware, CorsMiddleware, BodyLimitMiddleware, then any custom global middleware from HttpClientModule metadata. Each middleware is bound to the '*' path so it runs before all route handlers.
Execute global guards
If HttpClientModule declares guards, GuardExecutor wraps them in a Hono middleware that runs sequentially. When any guard returns false, execution stops and the server responds with { ok: false, error: 'Unauthorized' } at status 401. No further middleware or handlers run.
Register controllers and services
RouteRegistry resolves services first using topological sort to handle dependency ordering, then instantiates controllers with the resolved dependency map. RouteBuilder reads route metadata from each controller and binds handlers into Hono with merged class-level and method-level middleware chains.
Resolve parameters and validate DTOs
When a request reaches a handler, ParamResolver reads parameter decorator metadata and extracts values from params, query, body, headers, or the full Hono Context. If a @HttpBody decorator includes a DTO class, ValidationPipe transforms the raw body into a typed instance and validates it with class-validator rules before the handler executes.
Normalize errors and return response
Handlers that return plain objects get auto-serialized to JSON with status 200 (or a custom status from @HttpStatus). If a handler returns a native Response, Hono passes it through unchanged. The onError handler normalizes thrown exceptions: ValidationError returns 400 with details, any HttpError returns its own status code, and unknown exceptions return 500 after logging.
Graceful shutdown
During onShutdown, the server closes the underlying Node.js Server instance and waits for active connections to drain. The shutdown handler is also registered on SIGINT and SIGTERM in sharded mode to ensure the server stops cleanly when the parent process terminates.
Documentation roadmap
Each page in this category covers one layer of the HTTP stack in depth. Read them in order for a complete understanding, or jump to a specific topic when you need targeted reference.
- Configuration and Single-Module Setup, covering defineHttp, HttpConfig, and the module ownership model.
- HTTP Folder Architecture, covering recommended file organization as endpoint count grows.
- Routing Pipeline and Decorators, covering decorators, parameter resolution, DTO validation, and response shaping.
- Security, Guards, and Middleware, covering the hardening stack, guard interface, and middleware composition.
- Bot Bridge Runtime Modes, covering BotBridge contract, direct vs sharded implementations, and serializers.
- Exceptions and Error Handling, covering the HttpError hierarchy, ValidationError details, and the centralized normalization layer.