@forinda/kickjs-http
Express-based HTTP layer with declarative middleware pipeline, request context, routing, and query string parsing.
Application
Main application class that wires Express, the DI container, modules, adapters, and middleware.
class Application {
constructor(options: ApplicationOptions)
setup(): void
start(): void
rebuild(): void
shutdown(): Promise<void>
getExpressApp(): Express
getHttpServer(): http.Server | null
}
interface ApplicationOptions {
modules: AppModuleClass[]
adapters?: AppAdapter[]
plugins?: KickPlugin[] // see ../api/core.md#plugins
port?: number
apiPrefix?: string // default: '/api'
defaultVersion?: number // default: 1
middleware?: MiddlewareEntry[]
trustProxy?: boolean | number | string | ((ip: string, hopIndex: number) => boolean)
jsonLimit?: string | number
}
type MiddlewareEntry = RequestHandler | { path: string; handler: RequestHandler }Plugins (KickPlugin[]) are the highest-level extension primitive — they can bundle modules, adapters, middleware, DI bindings, and context contributors into one reusable unit. Build them with definePlugin() and pass the factory output here. See the Plugins guide and the definePlugin API reference.
bootstrap
Zero-boilerplate entry point. Handles Vite HMR, graceful shutdown, and global error handlers.
function bootstrap(options: ApplicationOptions): voidRequestContext
Unified request/response abstraction passed to every controller method.
class RequestContext<TBody = any, TParams = any, TQuery = any> {
readonly req: Request
readonly res: Response
readonly next: NextFunction
get body(): TBody
get params(): TParams
get query(): TQuery
get headers(): IncomingHttpHeaders
get requestId(): string | undefined
get file(): any
get files(): any[] | undefined
qs(fieldConfig?: QueryFieldConfig): ParsedQuery
get<T = any>(key: string): T | undefined
set(key: string, value: any): void
// Response helpers
json(data: any, status?: number): Response
created(data: any): Response
noContent(): Response
notFound(message?: string): Response
badRequest(message: string): Response
html(content: string, status?: number): Response
download(buffer: Buffer, filename: string, contentType?: string): Response
// Template rendering (requires ViewAdapter)
render(template: string, data?: Record<string, any>): void
// Pagination — parses query, fetches data, returns paginated JSON
paginate<T>(
fetcher: (parsed: ParsedQuery) => Promise<{ data: T[]; total: number }>,
fieldConfig?: QueryFieldConfig,
): Promise<Response>
// Server-Sent Events
sse(): {
send(data: any, event?: string, id?: string): void
comment(text: string): void
onClose(fn: () => void): void
close(): void
}
}Router Builder
function buildRoutes(controllerClass: any): Router
function getControllerPath(controllerClass: any): string- buildRoutes -- Builds an Express Router from a decorated controller class, resolving it from the DI container.
- getControllerPath -- Returns the path prefix set by
@Controller().
Middleware
requestId
Generates or propagates a unique x-request-id header.
function requestId(): RequestHandler
const REQUEST_ID_HEADER = 'x-request-id'validate
Validates req.body, req.query, and req.params against schemas with .safeParse().
function validate(schema: { body?: any; query?: any; params?: any }): RequestHandlererrorHandler / notFoundHandler
function errorHandler(): ErrorRequestHandler
function notFoundHandler(): RequestHandlercsrf
Double-submit cookie CSRF protection.
function csrf(options?: CsrfOptions): RequestHandler
interface CsrfOptions {
cookie?: string // default: '_csrf'
header?: string // default: 'x-csrf-token'
methods?: string[] // default: ['POST','PUT','PATCH','DELETE']
ignorePaths?: string[]
tokenLength?: number // default: 32
cookieOptions?: {
httpOnly?: boolean
sameSite?: 'strict' | 'lax' | 'none'
secure?: boolean
path?: string
}
}upload
File upload middleware built on multer.
const upload: {
single(fieldName: string, options?: UploadOptions): RequestHandler
array(fieldName: string, maxCount?: number, options?: UploadOptions): RequestHandler
none(options?: UploadOptions): RequestHandler
}
function cleanupFiles(): RequestHandler
interface UploadOptions {
maxSize?: number // default: 5MB
allowedTypes?: string[]
storage?: MulterOptions['storage']
dest?: string
}Query String Parsing
ORM-agnostic query string parsing for filters, sorting, pagination, and search.
function parseQuery(query: Record<string, any>, fieldConfig?: QueryFieldConfig): ParsedQuery
function parseFilters(
filterParam: string | string[] | undefined,
allowedFields?: string[],
): FilterItem[]
function parseSort(sortParam: string | string[] | undefined, allowedFields?: string[]): SortItem[]
function parsePagination(params: {
page?: string | number
limit?: string | number
}): PaginationParams
function parseSearchQuery(q: string | undefined): string
function buildQueryParams(parsed: Partial<ParsedQuery>): Record<string, string | string[] | number>Query Types
type FilterOperator =
| 'eq'
| 'neq'
| 'gt'
| 'gte'
| 'lt'
| 'lte'
| 'between'
| 'in'
| 'contains'
| 'starts'
| 'ends'
interface FilterItem {
field: string
operator: FilterOperator
value: string
}
interface SortItem {
field: string
direction: 'asc' | 'desc'
}
interface PaginationParams {
page: number
limit: number
offset: number
}
interface ParsedQuery {
filters: FilterItem[]
sort: SortItem[]
pagination: PaginationParams
search: string
}
interface QueryFieldConfig {
filterable?: string[]
sortable?: string[]
searchable?: string[]
}
interface QueryBuilderAdapter<TResult = any, TConfig = any> {
readonly name: string
build(parsed: ParsedQuery, config: TConfig): TResult
}