POST /image-pipeline/upload
POST /image-pipeline/upload
Accepts a multipart form upload, validates the file (MIME type, size, sourceType), uploads it to the R2 staging prefix, creates a MediaQueue row with PENDING status, and returns a jobId immediately. Processing happens asynchronously in the background worker.
@fastify/multipart must be registered before this plugin.
Request
Method: POST
Path: /image-pipeline/upload
Content-Type: multipart/form-data
| Field | Type | Required | Description |
|---|---|---|---|
file | binary | Yes | Image file (JPEG, PNG, WebP, or GIF by default) |
sourceType | string | Yes | One of the configured source types (e.g. avatar, gallery) |
sourceId | string | Yes | Identifier for the owning resource (e.g. user ID, post ID) |
Response
202 Accepted
{
"jobId": "clx1234abcd",
"message": "File uploaded. Processing started.",
"statusUrl": "/image-pipeline/status/clx1234abcd"
}
Throws
| Error | HTTP | Cause |
|---|---|---|
No file provided | 400 | Request has no file field |
sourceType and sourceId are required | 400 | Missing form fields |
Unknown sourceType: {type} | 400 | sourceType not in variant presets |
File type {mime} not allowed | 400 | MIME type not in allowedMimeTypes |
File too large. Maximum size: {n}MB | 400 | File exceeds maxFileSize |
Failed to upload file to storage | 500 | R2 upload error |
Failed to create processing job | 500 | Database error creating the job |
Examples
cURL upload
curl -X POST http://localhost:3000/image-pipeline/upload \
-F "file=@/path/to/photo.jpg" \
-F "sourceType=avatar" \
-F "sourceId=user-abc123"
Fastify route that proxies a user avatar upload
fastify.post("/users/:id/avatar", async (request, reply) => {
const data = await request.file();
const form = new FormData();
form.append("file", data.file, { filename: data.filename, contentType: data.mimetype });
form.append("sourceType", "avatar");
form.append("sourceId", request.params.id);
const response = await fetch("http://localhost:3000/image-pipeline/upload", {
method: "POST",
body: form,
});
const { jobId, statusUrl } = await response.json();
// Store jobId and poll statusUrl until COMPLETE
return { jobId, statusUrl };
});
See Also
- GET /image-pipeline/status/:jobId — Poll processing status after upload
- getStatus(jobId) — Programmatic status fetch via decorator
AI Context
package: "@xenterprises/fastify-ximagepipeline"
route: POST /image-pipeline/upload (multipart)
use-when: Upload an image file for async processing — returns jobId immediately; worker processes in background
fields: file (multipart), sourceType (string), sourceId (string)
returns: { jobId, status: "PENDING" }
S3 / R2 Utilities
Low-level S3-compatible storage helpers for uploading, downloading, deleting, listing, and signing objects — importable standalone from the pipeline plugin.
fastify-xpdf
Fastify 5 plugin for PDF generation and manipulation — HTML/Markdown/URL to PDF via Puppeteer, form filling, merging, page extraction, and metadata via pdf-lib, with optional S3 storage.
