Skip to main content

API Reference

The public surface of both entrypoints. Express types come from "efesto"; the Bun/Elysia stack from "efesto/elysia".

efesto (Express)

import efesto from "efesto";

efesto(params: {
authMiddleware: Middleware; // express-validator Middleware; runs before every resolver
errorMiddleware: Middleware; // handles errors / validation results
isProduction: boolean; // scan .js (true) or .ts (false)
options?: ForgeOptions;
}): Router // an express-promise-router instance, mount with app.use(prefix, ...)

Also exported from "efesto": everything in serviceUtils/types (below), the ConfigObject type, and mongoIdParserErrorHandler (an Express error handler used with mongoIdParser).

ForgeOptions

interface ForgeOptions {
absoluteDirRoutes?: string | string[]; // routes dir(s); default "/v1/routes"
generatedTypesFolder?: string; // where .d.ts types are written
relativeDirSwaggerDeclarationsPath?: string; // default "swagger-declarations"
customFormats?: SwaggerFormats;
automaticTypesGenerationInlineFile?: boolean; // default false
config?: ConfigObject;
}

ConfigObject

type ConfigObject = {
createdAtField?: string; // default "createdAt"
updatedAtField?: string; // default "updatedAt"
dynamicParameterType?: "string" | "number"; // default "string"
defaultRequiredValueForModels?: boolean; // default true (fields required unless `?`)
defaultNullableOnOptionalFields?: boolean; // default false
customTypes?: { [key: string]: SwaggerDataTypes | SwaggerSchemaItems };
optionalFieldsType?: "null" | "undefined"; // default "undefined"
canMagicallyEditCode?: boolean; // default true (dev only)
verbose?: boolean; // default false
mongoIdParser?: boolean; // default false (maps _id -> id in responses)
abacPermissions?: {
actions?: string[];
models?: string[];
checkPermissionBeforeResolver?: boolean; // default true
reqAbilityField?: string; // default "ability"
};
redis?: { host: string; port: number; defaultExpiresInSeconds: number };
};

See Configuration for descriptions and defaults.

BaseApiService (Express service class)

The class every Express route file extends. The constructor takes __filename so Efesto can resolve [param] segments.

abstract class BaseApiService {
constructor(filename: string);
paramName: string; // name of the file's last [param], if any
getParamFrom(req: Request): any; // req.params[this.paramName]
swaggerModel: SwaggerModel;

// per-verb members (verb ∈ get|post|put|patch|delete|head|options|trace|connect)
_<verb>?(req, res, next): any; // handler
_<verb>Swagger?: SwaggerOptions; // documentation (_getSwagger omits requestBody)
_<verb>Validation?: ValidationType[]; // express-validator chains
_<verb>OverrideAuth?: Middleware; // replaces the global authMiddleware
// multer flags exist for post/patch/put only:
_<verb>Multer?: boolean; // single file (req.file)
_<verb>MultipleMulter?: boolean; // multiple files (req.files)
}

SwaggerModel

interface SwaggerModel {
modelName: string; // grouping category (falls back to "n-a" if omitted)
schemas?: SwaggerSchema[]; // shared across the whole project, referenced with @Name
parameters?: SwaggerParameter[];
}

SwaggerSchema

type SwaggerSchema =
| { name: string; properties: SwaggerSchemaProperties; required?: string[]; noTimestamps?: boolean; nullable?: boolean }
| { name: string; type: "string"; enum: readonly string[]; noTimestamps?: boolean }; // enum schema

SwaggerOptions (the _<verb>Swagger object)

interface SwaggerOptions {
operationId: string;
summary?: string;
description?: string | string[];
parameters?: SwaggerParameter[];
responses?: SwaggerResponses; // { [statusCode]: SchemaType | full object }
requestBody?: SwaggerRequestBody | SwaggerSchemaType; // not available on _getSwagger
permission?: [ABACAction, ABACModel]; // ABAC tuple
cache?: { key: `\`${string}\``; expiresInSeconds?: number }; // eval'd Redis key
purgeKey?: `\`${string}\`` | `\`${string}\``[]; // eval'd Redis key(s)
flags?: { deprecated?: boolean };
}

Magic Type strings

The string form accepted wherever a schema/type is expected. Base types: string, number, integer, boolean, array, object, Date, ObjectId. String formats: date, date-time, password, byte, binary.

type[::format][|example][!|?][[]]      // grammar
"string" // simple
"string::email" // format
"string::email|john@x.com" // format + example
"number!" "boolean?" // required / optional override
"string[]" "@User" "@User[]" "@User?"// arrays and model references

See Magic Types for the full syntax.

efesto/elysia (Bun/Elysia)

import efesto, { Elysia, t, type Context, BaseApiService } from "efesto/elysia";

efesto(params: {
isProduction: boolean;
routesDir: string | string[];
prefix?: string;
swagger?: boolean | OpenApiOptions; // default true
setup?: (app: Elysia) => unknown;
abac?: { abilityField?: string; checkPermissionBeforeResolver?: boolean };
swaggerConfig?: { customTypes?: object; customFormats?: object }; // extends the _<verb>Swagger DSL
models?: { [name: string]: unknown }; // shared @Model schemas -> OpenAPI components
}): Elysia;

Re-exports: Elysia, t (TypeBox) and Context from Elysia; the BaseApiService class; and the types HttpVerb, RouteHandler, RouteValidation, SwaggerOptions.

BaseApiService (class-based Elysia routes)

The same per-method prefix convention as the Express BaseApiService. Handlers are written in method syntax; _<verb>Swagger uses the shared SwaggerOptions type (the Magic Types DSL is expanded into native OpenAPI). Per verb (verb ∈ get|post|put|patch|delete|head|options):

abstract class BaseApiService {
static readonly __efestoApiService = true; // brand used for detection
constructor(filename?: string); // super(__filename), optional (Express parity)

_<verb>?(ctx: Context): unknown; // handler, method syntax: _get(ctx) { return value }
_<verb>Validation?: RouteValidation; // { body, query, params, response } TypeBox
_<verb>Swagger?: SwaggerOptions; // OpenAPI DSL + permission (same type as Express)
// multer flags exist for post/patch/put only; the file arrives in ctx.body:
_<verb>Multer?: boolean; // single file
_<verb>MultipleMulter?: boolean; // multiple files
}

type RouteHandler = (ctx: Context) => unknown;

interface RouteValidation {
body?: TSchema;
query?: TSchema;
params?: TSchema;
response?: TSchema | Record<number, TSchema>;
}

_<verb>Swagger is the same SwaggerOptions as the Express stack: operationId, summary, requestBody, responses, parameters (Magic Types expanded into native OpenAPI) plus permission: [action, model]. Only permission (ABAC guard) and flags.deprecated take effect on Elysia; cache/purgeKey are accepted by the type but not wired (caching is composed natively, see Caching).

Annotate _<verb>Swagger: SwaggerOptions and _<verb>Validation: RouteValidation so permission infers as a tuple; the handler reads validated input from ctx.body/ctx.query/ctx.params (cast to the shape you declared in _<verb>Validation). For full native inference, write a native Elysia instance instead.

Generated types (Express)

When generatedTypesFolder is set (development), Efesto writes, for a route whose file export defaults a class named Foo, a global namespace FooTypes into <generatedTypesFolder>/Foo.d.ts. Per verb it contains:

  • GetRequest, GetResponse, GetReturn (and Post*, Put*, ... capitalized).

With canMagicallyEditCode (default true) Efesto also rewrites the method signatures in place, e.g. _get(req, res) becomes _get(req: FooTypes.GetRequest, res: FooTypes.GetResponse): Promise<FooTypes.GetReturn>. See Type Generation.