Passa al contenuto principale

Configurazione

Efesto si configura tramite l'oggetto che passi a efesto(). Ogni opzione, con il suo tipo e default, è elencata qui sotto.

Due oggetti di configurazione

I due stack accettano oggetti di configurazione diversi. Gran parte di questa pagina documenta l'oggetto Express (efesto da "efesto"). Il più piccolo oggetto Bun/Elysia (efesto/elysia) è documentato nella sua sezione alla fine.

Costruisci la tua configurazione

Attiva/disattiva le opzioni per assemblare una chiamata efesto({ ... }) di partenza per entrambi gli stack, poi copiala. Ogni campo corrisponde a un'opzione reale documentata sotto.

import efesto from "efesto";

app.use(
  "/api/v1",
  efesto({
    authMiddleware: (req, res, next) => next(),
    errorMiddleware: (req, res, next) => next(),
    isProduction: false,
    options: {
      absoluteDirRoutes: `${__dirname}/routes`,
      generatedTypesFolder: `${__dirname}/efesto-types`,
      config: {
        defaultRequiredValueForModels: true,
      },
    },
  })
);

Oggetto di configurazione Efesto (Express)

La configurazione Express viene passata alla funzione efesto() e contiene la seguente struttura:

efesto({
authMiddleware: Middleware, // Obbligatorio
errorMiddleware: Middleware, // Obbligatorio
isProduction: boolean, // Obbligatorio
options?: { // Opzionale
absoluteDirRoutes?: string | string[];
generatedTypesFolder?: string;
relativeDirSwaggerDeclarationsPath?: string;
customFormats?: SwaggerFormats;
automaticTypesGenerationInlineFile?: boolean;
config?: ConfigObject;
}
})

Parametri obbligatori

authMiddleware

Tipo: Middleware
Obbligatorio: ✅
Descrizione: il middleware di autenticazione che verrà applicato a tutti gli endpoint.

authMiddleware: (req, res, next) => {
// La tua logica di autenticazione qui
// Esempio: verifica JWT, validazione della sessione, ecc.

// Se l'autenticazione fallisce:
// return res.status(401).json({ error: 'Unauthorized' });

// Se l'autenticazione ha successo:
next();
};

errorMiddleware

Tipo: Middleware
Obbligatorio: ✅
Descrizione: il middleware di gestione degli errori per processare gli errori.

errorMiddleware: (req, res, next) => {
// La tua logica di gestione degli errori qui
// Esempio: logging, formattazione degli errori, ecc.

next();
};

isProduction

Tipo: boolean
Obbligatorio: ✅
Descrizione: abilita la modalità produzione. Quando true, Efesto analizza i file di rotta .js compilati; quando false analizza i file sorgente .ts (e abilita funzionalità riservate allo sviluppo come la generazione dei tipi e la modifica magica del codice).

isProduction: process.env.NODE_ENV === "production";

Parametri opzionali

options.absoluteDirRoutes

Tipo: string | string[]
Default: "/v1/routes"
Descrizione: percorso/i in cui Efesto troverà i file di rotta da analizzare.

// Percorso singolo
absoluteDirRoutes: path.join(__dirname, "routes");

// Percorsi multipli
absoluteDirRoutes: [
path.join(__dirname, "routes"),
path.join(__dirname, "api"),
];

options.generatedTypesFolder

Tipo: string
Default: undefined
Descrizione: cartella in cui Efesto genererà le definizioni dei tipi TypeScript.

generatedTypesFolder: path.join(__dirname, "types");

options.relativeDirSwaggerDeclarationsPath

Tipo: string
Default: "swagger-declarations"
Descrizione: cartella in cui Efesto creerà i file YAML di Swagger.

relativeDirSwaggerDeclarationsPath: "docs/swagger";

options.customFormats

Tipo: SwaggerFormats
Default: undefined
Descrizione: formati Swagger personalizzati per la validazione.

customFormats: {
'custom-format': {
example: 'custom-value'
}
}

options.automaticTypesGenerationInlineFile

Tipo: boolean
Default: false
Descrizione: se generare i tipi inline nello stesso file.

Oggetto Config

L'oggetto config contiene opzioni di configurazione avanzate:

config: {
createdAtField?: string;
updatedAtField?: string;
dynamicParameterType?: "string" | "number";
defaultRequiredValueForModels?: boolean;
defaultNullableOnOptionalFields?: boolean;
customTypes?: { [key: string]: SwaggerDataTypes | SwaggerSchemaItems };
optionalFieldsType?: "null" | "undefined";
canMagicallyEditCode?: boolean;
verbose?: boolean;
mongoIdParser?: boolean;
abacPermissions?: AbacConfigurationObject;
redis?: RedisConfigurationObject;
}
OpzioneTipoDefaultDescrizione
createdAtFieldstring"createdAt"Campo usato come timestamp di creazione
updatedAtFieldstring"updatedAt"Campo usato come timestamp di aggiornamento
dynamicParameterType"string" | "number""string"Tipo documentato dei parametri di percorso [param]
defaultRequiredValueForModelsbooleantrueI campi sono obbligatori salvo che siano marcati ?
defaultNullableOnOptionalFieldsbooleanfalseI campi opzionali (?) diventano anche nullable
optionalFieldsType"null" | "undefined""undefined"Tipo dei campi opzionali (usa "null" con Prisma)
customTypesRecord<string, …>undefinedTipi nominati riutilizzabili per i Magic Types (vedi sotto)
canMagicallyEditCodebooleantruePermetti a Efesto di riscrivere le firme dei metodi (solo dev)
verbosebooleanfalseLogging di avvio dettagliato
mongoIdParserbooleanfalseMappa _id su id nelle risposte
abacPermissionsobjectundefinedConfig ABAC
redisobjectundefinedConfig Redis

customTypes mappa un nome su un tipo base o uno schema, poi usi il nome come qualsiasi Magic Type:

customTypes: {
ObjectId: "string",
Date: { type: "string", format: "date-time" },
Decimal: { type: "number", format: "decimal" },
}

Le opzioni di generazione dei tipi (generatedTypesFolder, automaticTypesGenerationInlineFile, canMagicallyEditCode) sono trattate in Generazione dei tipi.

Configurazione ABAC

abacPermissions

Tipo: AbacConfigurationObject
Default: undefined
Descrizione: configurazione per il controllo degli accessi basato sugli attributi.

abacPermissions: {
actions?: string[];
models?: string[];
checkPermissionBeforeResolver?: boolean;
reqAbilityField?: string;
}

Opzioni di configurazione ABAC

  • actions: array di azioni consentite (es. ["read", "write", "delete"])
  • models: array di nomi di modello a cui applicare i permessi
  • checkPermissionBeforeResolver: se verificare i permessi prima di eseguire i resolver
  • reqAbilityField: nome del campo nell'oggetto request che contiene l'ability (default: "ability")
abacPermissions: {
actions: ["read", "write", "delete"],
models: ["User", "Post", "Comment"],
checkPermissionBeforeResolver: true,
reqAbilityField: "userAbility"
}

Configurazione Redis

redis

Tipo: RedisConfigurationObject
Default: undefined
Descrizione: configurazione per il caching con Redis.

redis: {
host: string;
port: number;
defaultExpiresInSeconds: number;
}

Opzioni di configurazione Redis

  • host: hostname del server Redis
  • port: porta del server Redis
  • defaultExpiresInSeconds: tempo di scadenza della cache di default
redis: {
host: "127.0.0.1",
port: 6379,
defaultExpiresInSeconds: 600
}

Variabili d'ambiente

Puoi usare le variabili d'ambiente per configurare Efesto:

// file .env
NODE_ENV=development
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_EXPIRES=600
EFESTO_VERBOSE=true
EFESTO_TYPES_FOLDER=./types
// Nella tua configurazione
efesto({
authMiddleware: authMiddleware,
errorMiddleware: errorMiddleware,
isProduction: process.env.NODE_ENV === "production",
options: {
absoluteDirRoutes: "./routes",
generatedTypesFolder: process.env.EFESTO_TYPES_FOLDER,
config: {
verbose: process.env.EFESTO_VERBOSE === "true",
redis: process.env.REDIS_HOST
? {
host: process.env.REDIS_HOST,
port: parseInt(process.env.REDIS_PORT || "6379"),
defaultExpiresInSeconds: parseInt(
process.env.REDIS_EXPIRES || "600"
),
}
: undefined,
},
},
});

Esempio di configurazione completa

import express from "express";
import efesto from "efesto";
import path from "path";

const app = express();

// Middleware
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// Middleware di autenticazione
const authMiddleware = (req, res, next) => {
const token = req.headers.authorization?.replace("Bearer ", "");

if (!token) {
return res.status(401).json({ error: "No token provided" });
}

try {
// Verifica del token JWT
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded;
next();
} catch (error) {
return res.status(401).json({ error: "Invalid token" });
}
};

// Middleware degli errori
const errorMiddleware = (req, res, next) => {
console.error("Error:", req.error);
res.status(500).json({
error: "Internal Server Error",
message:
process.env.NODE_ENV === "development" ? req.error?.message : undefined,
});
};

// Configurazione di Efesto
app.use(
"/api/v1",
efesto({
authMiddleware,
errorMiddleware,
isProduction: process.env.NODE_ENV === "production",
options: {
absoluteDirRoutes: path.join(__dirname, "routes"),
generatedTypesFolder: path.join(__dirname, "types"),
relativeDirSwaggerDeclarationsPath: "swagger-declarations",
automaticTypesGenerationInlineFile: false,
config: {
createdAtField: "createdAt",
updatedAtField: "updatedAt",
dynamicParameterType: "string",
defaultRequiredValueForModels: true,
defaultNullableOnOptionalFields: false,
optionalFieldsType: "undefined",
canMagicallyEditCode: true,
verbose: process.env.NODE_ENV === "development",
mongoIdParser: false,
customTypes: {
ObjectId: "string",
Date: { type: "string", format: "date-time" },
Email: { type: "string", format: "email" },
},
abacPermissions: {
actions: ["read", "write", "delete"],
models: ["User", "Post", "Comment"],
checkPermissionBeforeResolver: true,
reqAbilityField: "ability",
},
redis: process.env.REDIS_HOST
? {
host: process.env.REDIS_HOST,
port: parseInt(process.env.REDIS_PORT || "6379"),
defaultExpiresInSeconds: parseInt(
process.env.REDIS_EXPIRES || "600"
),
}
: undefined,
},
},
})
);

export default app;

Configurazione Bun/Elysia (efesto/elysia)

L'entrypoint Elysia accetta un oggetto più piccolo. Non ha authMiddleware, errorMiddleware, swaggerModel o generazione di YAML: validazione, OpenAPI e hook sono tutti nativi di Elysia.

import efesto from "efesto/elysia";

const app = efesto({
isProduction: process.env.NODE_ENV === "production", // obbligatorio
routesDir: `${import.meta.dir}/routes`, // obbligatorio
prefix: "/api/v1", // opzionale
swagger: true, // opzionale (default true)
setup: (root) => { // opzionale
// aggiungi plugin/hook globali prima del mount delle rotte (auth, ability ABAC, cors, ...)
},
abac: { // opzionale
abilityField: "ability",
checkPermissionBeforeResolver: true,
},
}).listen(2014);
ParametroTipoObbligatorioDescrizioneDefault
isProductionbooleanAnalizza i file di rotta .js compilati invece dei .ts
routesDirstring | string[]Directory (o directory) analizzate per i moduli di rotta
prefixstringPrefisso di mount per l'intera app, es. /api/v1nessuno
swaggerboolean | OpenApiOptionsAbilita il plugin OpenAPI nativo; passa un oggetto per personalizzarlotrue
setup(app) => unknownAggiungi plugin/hook globali sulla root prima del mount delle rotte
abac{ abilityField?, checkPermissionBeforeResolver? }Regola l'applicazione dei permission basati su classevedi ABAC

efesto(...) restituisce un'istanza Elysia nativa, quindi puoi farne .listen(...) o montarla come plugin con new Elysia().use(efesto(...)).