Riferimento API
La superficie pubblica di entrambi gli entrypoint. I tipi Express provengono da
"efesto"; lo stack Bun/Elysia da "efesto/elysia".
efesto (Express)
import efesto from "efesto";
efesto(params: {
authMiddleware: Middleware; // Middleware express-validator; eseguito prima di ogni resolver
errorMiddleware: Middleware; // gestisce errori / risultati di validazione
isProduction: boolean; // analizza .js (true) o .ts (false)
options?: ForgeOptions;
}): Router // un'istanza express-promise-router, monta con app.use(prefix, ...)
Esportati anche da "efesto": tutto ciò che è in serviceUtils/types (sotto), il tipo
ConfigObject e mongoIdParserErrorHandler (un error handler Express usato con
mongoIdParser).
ForgeOptions
interface ForgeOptions {
absoluteDirRoutes?: string | string[]; // dir delle rotte; default "/v1/routes"
generatedTypesFolder?: string; // dove vengono scritti i tipi .d.ts
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 (campi obbligatori salvo `?`)
defaultNullableOnOptionalFields?: boolean; // default false
customTypes?: { [key: string]: SwaggerDataTypes | SwaggerSchemaItems };
optionalFieldsType?: "null" | "undefined"; // default "undefined"
canMagicallyEditCode?: boolean; // default true (solo dev)
verbose?: boolean; // default false
mongoIdParser?: boolean; // default false (mappa _id -> id nelle risposte)
abacPermissions?: {
actions?: string[];
models?: string[];
checkPermissionBeforeResolver?: boolean; // default true
reqAbilityField?: string; // default "ability"
};
redis?: { host: string; port: number; defaultExpiresInSeconds: number };
};
Vedi Configurazione per descrizioni e default.
BaseApiService (classe di servizio Express)
La classe che ogni file di rotta Express estende. Il costruttore riceve __filename
così Efesto può risolvere i segmenti [param].
abstract class BaseApiService {
constructor(filename: string);
paramName: string; // nome dell'ultimo [param] del file, se presente
getParamFrom(req: Request): any; // req.params[this.paramName]
swaggerModel: SwaggerModel;
// membri per verbo (verbo ∈ get|post|put|patch|delete|head|options|trace|connect)
_<verb>?(req, res, next): any; // handler
_<verb>Swagger?: SwaggerOptions; // documentazione (_getSwagger omette requestBody)
_<verb>Validation?: ValidationType[]; // catene express-validator
_<verb>OverrideAuth?: Middleware; // sostituisce l'authMiddleware globale
// i flag multer esistono solo per post/patch/put:
_<verb>Multer?: boolean; // file singolo (req.file)
_<verb>MultipleMulter?: boolean; // file multipli (req.files)
}
SwaggerModel
interface SwaggerModel {
modelName: string; // categoria di raggruppamento (ricade su "n-a" se omessa)
schemas?: SwaggerSchema[]; // condivisi nell'intero progetto, referenziati con @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 }; // schema enum
SwaggerOptions (l'oggetto _<verb>Swagger)
interface SwaggerOptions {
operationId: string;
summary?: string;
description?: string | string[];
parameters?: SwaggerParameter[];
responses?: SwaggerResponses; // { [statusCode]: SchemaType | oggetto completo }
requestBody?: SwaggerRequestBody | SwaggerSchemaType; // non disponibile su _getSwagger
permission?: [ABACAction, ABACModel]; // tupla ABAC
cache?: { key: `\`${string}\``; expiresInSeconds?: number }; // chiave Redis valutata
purgeKey?: `\`${string}\`` | `\`${string}\``[]; // chiave/i Redis valutata/e
flags?: { deprecated?: boolean };
}
Stringhe Magic Type
La forma a stringa accettata ovunque sia atteso uno schema/tipo. Tipi base:
string, number, integer, boolean, array, object, Date, ObjectId. Formati
delle stringhe: date, date-time, password, byte, binary.
type[::format][|example][!|?][[]] // grammatica
"string" // semplice
"string::email" // formato
"string::email|john@x.com" // formato + esempio
"number!" "boolean?" // override obbligatorio / opzionale
"string[]" "@User" "@User[]" "@User?"// array e riferimenti a modelli
Vedi Magic Types per la sintassi completa.
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 }; // estende il DSL di _<verb>Swagger
models?: { [name: string]: unknown }; // schemi @Model condivisi -> componenti OpenAPI
}): Elysia;
Ri-esporta: Elysia, t (TypeBox) e Context da Elysia; la classe BaseApiService;
e i tipi HttpVerb, RouteHandler, RouteValidation, SwaggerOptions.
BaseApiService (rotte Elysia basate su classe)
La stessa convenzione di prefisso per metodo del BaseApiService di Express. Gli
handler sono scritti in sintassi a metodo; _<verb>Swagger usa il tipo condiviso
SwaggerOptions (il DSL Magic Types è espanso in OpenAPI nativo). Per ogni verbo
(verbo ∈ get|post|put|patch|delete|head|options):
abstract class BaseApiService {
static readonly __efestoApiService = true; // brand usato per il rilevamento
constructor(filename?: string); // super(__filename), opzionale (parità con Express)
_<verb>?(ctx: Context): unknown; // handler, sintassi a metodo: _get(ctx) { return value }
_<verb>Validation?: RouteValidation; // { body, query, params, response } TypeBox
_<verb>Swagger?: SwaggerOptions; // DSL OpenAPI + permission (stesso tipo di Express)
// i flag multer esistono solo per post/patch/put; il file arriva in ctx.body:
_<verb>Multer?: boolean; // file singolo
_<verb>MultipleMulter?: boolean; // file multipli
}
type RouteHandler = (ctx: Context) => unknown;
interface RouteValidation {
body?: TSchema;
query?: TSchema;
params?: TSchema;
response?: TSchema | Record<number, TSchema>;
}
_<verb>Swagger è lo stesso SwaggerOptions
dello stack Express: operationId, summary, requestBody, responses, parameters
(Magic Types espansi in OpenAPI nativo) più permission: [action, model]. Su Elysia
hanno effetto solo permission (guard ABAC) e flags.deprecated; cache/purgeKey
sono accettati dal tipo ma non collegati (il caching si compone nativamente, vedi
Caching).
Annota _<verb>Swagger: SwaggerOptions e _<verb>Validation: RouteValidation così che
permission venga inferito come tupla; l'handler legge l'input validato da
ctx.body/ctx.query/ctx.params (con cast alla forma dichiarata in
_<verb>Validation). Per l'inferenza nativa completa, scrivi invece un'istanza Elysia
nativa.
Tipi generati (Express)
Quando generatedTypesFolder è impostato (in sviluppo), Efesto scrive, per una rotta il
cui file fa export default di una classe chiamata Foo, un namespace globale
FooTypes in <generatedTypesFolder>/Foo.d.ts. Per ogni verbo contiene:
GetRequest,GetResponse,GetReturn(ePost*,Put*, ... con iniziale maiuscola).
Con canMagicallyEditCode (default true) Efesto riscrive anche le firme dei metodi
in-place, es. _get(req, res) diventa
_get(req: FooTypes.GetRequest, res: FooTypes.GetResponse): Promise<FooTypes.GetReturn>.
Vedi Generazione dei tipi.