File Uploads
Define File Columns
Use the file() utility within your entity definition to mark a column as a file field. This enables multipart middleware support for the entity.
import { defineEntity, file, primaryId, timestamps } from "@codingkiwi/baseline/database/utils.js";
import { mysqlTable, varchar } from "drizzle-orm/mysql-core";
export const userProfile = defineEntity({
table: mysqlTable("user_profile", {
id: primaryId(),
username: varchar({ length: 50 }).notNull(),
// The file column
avatar: file(),
...timestamps,
})
});INFO
If a file column is non-nullable, all POST and PUT requests to that entity must use multipart/form-data. If you are uploading a file, you must use multipart/form-data regardless of whether the column is nullable. If all file columns are nullable and you are only updating non-file fields, you can use standard application/json.
Configure File Constraints
Pass configuration options to the file() function to enforce restrictions. Use maxSize to limit the upload size in bytes.
// Limit upload to 5MB
file({
maxSize: 5 * 1024 * 1024,
}),WARNING
The framework uses the largest maxSize defined among all file columns to deny uploads during the initial upload phase. If no maxSize is specified for a file column, it defaults to 1MB. Individual maxSize constraints are verified only after all files have been uploaded due to technical reasons. If an upload exceeds the limit, the server returns a 413 Payload Too Large error.
Structure Multipart Requests
Use multipart/form-data to send both structured JSON data and binary files in a single request. Include a data field for all non-file entity fields.
Request Body Table
| Field Key | Type | Description |
|---|---|---|
data | string (JSON) | A JSON-stringified object containing all non-file entity fields. |
[column_name] | file | The binary file matching the entity's file column name. |
Example Payload:
If you are uploading a userProfile with a username and an avatar, your multipart/form-data body should look like this:
- data:
{"username": "coding_wizard"} - avatar:
[Binary File Data]
DANGER
If the data field is missing or contains invalid JSON, the request will fail with a 400 Bad Request error.
Use the Baseline Client
The baseline-client automatically detects File instances in your data and transforms the payload into the required multipart/form-data format. You do not need to manually construct FormData or nest JSON fields.
// The client handles all multipart complexity automatically
await baseline.api.create("users", {
username: "coding_wizard",
avatar: fileInstance // An instance of File
});Access Uploaded Files
Access uploaded files through the built-in /files route using the filename stored in your database.
Example:
If the avatar column contains profile_image_abc123.jpg, access it at: http://localhost:3000/files/profile_image_abc123.jpg
If a file is not found, the endpoint returns a 404 Not Found error:
{
"error": "Not Found"
}