Upload di file
Sullo stack Express, Efesto collega Multer
alla catena dei middleware così che un endpoint possa accettare multipart/form-data.
Aderisci per metodo con un flag booleano; Efesto gestisce il resto ed espone il/i file
sulla request.
I flag _<verb>Multer / _<verb>MultipleMulter funzionano su entrambi gli stack.
Su Express, Efesto collega Multer e il file arriva in req.file / req.files. Su
Bun/Elysia, Efesto imposta lo schema del corpo TypeBox a t.File() / t.Files() e il
file arriva in ctx.body (vedi sotto). Puoi anche accettare
file nativamente su Elysia con un tuo schema del corpo t.File().
File singolo
Servono due cose: documentare il corpo come multipart/form-data e impostare il flag
_<method>Multer a true. Il file caricato è poi disponibile come req.file:
import { BaseApiService, SwaggerOptions } from "efesto";
import type { Request, Response } from "express";
class Documents extends BaseApiService {
constructor() {
super(__filename);
}
_postSwagger: SwaggerOptions = {
operationId: "uploadDocument",
requestBody: {
content: {
"multipart/form-data": {
schema: {
type: "object",
properties: {
file: { type: "string", format: "binary" },
},
},
},
},
},
};
// abilita Multer per POST (file singolo)
_postMulter: boolean = true;
_post(req: Request, res: Response) {
const file = req.file; // il file caricato (in memoria)
return res.json({ name: file?.originalname, size: file?.size });
}
}
export default Documents;
Il nome del campo che Multer si aspetta per un upload singolo è file.
File multipli
Aggiungi _<method>MultipleMulter = true accanto al flag singolo, documenta il corpo
come array di binari e leggi req.files:
class Documents extends BaseApiService {
constructor() { super(__filename); }
_postSwagger: SwaggerOptions = {
operationId: "uploadDocuments",
requestBody: {
content: {
"multipart/form-data": {
schema: {
type: "object",
properties: {
files: {
type: "array",
items: { type: "string", format: "binary" },
},
},
},
},
},
},
};
_postMulter: boolean = true;
_postMultipleMulter: boolean = true; // richiesto per file multipli
_post(req: Request, res: Response) {
const files = req.files; // array di file caricati
return res.json({ count: Array.isArray(files) ? files.length : 0 });
}
}
Il nome del campo per upload multipli è files.
Come si comporta
- Efesto usa di default lo storage in memoria di Multer, quindi i file arrivano come
buffer (
req.file.buffer/file.buffer): nulla viene scritto su disco per te. - Il middleware Multer viene eseguito per primo nella catena, prima della validazione
e del tuo handler, così
req.file/req.filessono popolati quando il metodo viene eseguito. - I flag sono letti per nome del metodo:
_postMulter,_putMulter, ecc., corrispondenti al verbo HTTP dell'endpoint.
Sullo stack Bun/Elysia
Gli stessi flag si applicano a una classe che estende BaseApiService. Invece di
collegare Multer, Efesto imposta lo schema del corpo TypeBox della rotta (t.File() per
_<verb>Multer, t.Files() per _<verb>MultipleMulter) quando non ne dichiari uno tu
stesso; il file arriva in ctx.body come un
File web:
import { BaseApiService, type Context, SwaggerOptions } from "efesto/elysia";
export default class extends BaseApiService {
_putSwagger: SwaggerOptions = {
operationId: "uploadFile",
requestBody: {
content: {
"multipart/form-data": {
schema: { type: "object", properties: { file: "string::binary" } },
},
},
},
};
_putMulter = true; // lo schema del corpo diventa t.Object({ file: t.File() })
async _put({ body }: Context) {
const file = (body as { file: File }).file;
return file?.name;
}
}
I nomi dei campi corrispondono a Express: file per un upload singolo, files
per multipli. I flag esistono solo su post / patch / put.
Validare e memorizzare i file
Efesto porta i byte al tuo handler; cosa fai dopo è il tuo codice. Valida tipo e dimensione, poi salva dove vuoi, tutto all'interno del metodo:
_post(req: Request, res: Response) {
const file = req.file;
if (!file) return res.status(400).json({ error: "No file" });
if (file.size > 5 * 1024 * 1024) return res.status(413).json({ error: "Too large" });
if (!file.mimetype.startsWith("image/")) return res.status(415).json({ error: "Images only" });
// memorizza file.buffer dove preferisci: disco, S3, GCS, un database...
const id = persist(file.buffer, file.originalname); // la tua logica di storage
return res.json({ id });
}
Lo storage su cloud (S3, GCS), l'elaborazione delle immagini, la compressione e la
scansione antivirus non sono funzionalità di Efesto. Sono codice ordinario che
esegui su file.buffer usando la libreria che preferisci.