Handling File Uploads
File uploads are a common requirement in modern web applications. Minima.js provides a simple and efficient way to handle file uploads using the @minimajs/multipart package, which is context-aware and easy to use.
Prerequisites
First, you need to install the @minimajs/multipart package:
npm install @minimajs/multipart1. Handling a Single File Upload
To handle a single file upload, use the multipart.file() helper. It's context-aware, so you don't need to pass any request objects. It returns a Promise that resolves to a File object.
import { createApp } from "@minimajs/server";
import { multipart } from "@minimajs/multipart";
import { createWriteStream } from "fs";
import { pipeline } from "stream/promises";
const app = createApp();
app.post("/upload/single", async () => {
// If multiple files are uploaded on different fields, you can specify the field name.
// const file = await multipart.file("my-specific-field");
const file = await multipart.file(); // Gets the first file from the request
if (!file) {
return { message: "No file uploaded" };
}
// file is a File object with properties like `filename`, `mimetype`, and `stream`.
await pipeline(file.stream, createWriteStream(`./uploads/${file.filename}`));
return { message: "File uploaded successfully" };
});
await app.listen({ port: 3000 });In this example:
- We use
multipart.file()to get the uploaded file from the request. - The
multipart.file()function returns aPromise<File>. - We then use
stream/promises'spipelineto save the file stream to theuploadsdirectory.
You can test this route using curl:
curl -X POST -F "file=@/path/to/your/file.txt" http://localhost:3000/upload/single2. Handling Multiple File Uploads
To handle multiple file uploads, use the multipart.files() helper. This helper returns an async iterator that yields each uploaded File object.
import { createApp } from "@minimajs/server";
import { multipart } from "@minimajs/multipart";
import { createWriteStream } from "fs";
import { pipeline } from "stream/promises";
const app = createApp();
app.post("/upload/multiple", async () => {
for await (const file of multipart.files()) {
await pipeline(file.stream, createWriteStream(`./uploads/${file.filename}`));
}
return { message: "Files uploaded successfully" };
});
await app.listen({ port: 3000 });You can test this route using curl:
curl -X POST \
-F "file1=@/path/to/your/file1.txt" \
-F "file2=@/path/to/your/file2.txt" \
http://localhost:3000/upload/multiple3. Accessing All Form Parts (Fields and Files)
To access all parts of a multipart form, including both text fields and files, use the multipart() helper. It returns an async iterator that yields a tuple [fieldName, value] for each part, where value can be a string or a File object.
import { createApp } from "@minimajs/server";
import { multipart, isFile } from "@minimajs/multipart";
import { createWriteStream } from "fs";
import { pipeline } from "stream/promises";
const app = createApp();
app.post("/upload/with-fields", async () => {
const fields: Record<string, string> = {};
for await (const [name, value] of multipart()) {
if (isFile(value)) {
// It's a file
console.log(`Processing file: ${value.filename}`);
await pipeline(value.stream, createWriteStream(`./uploads/${value.filename}`));
} else {
// It's a text field
console.log(`Field ${name}: ${value}`);
fields[name] = value;
}
}
return { message: "Form processed successfully", fields };
});This is the most flexible way to process complex forms with mixed data types.