fastify-ximagepipeline
GET /image-pipeline/status/:jobId
Poll the processing status of an upload job — returns variant URLs, blurhash, and dimensions when COMPLETE.
GET /image-pipeline/status/:jobId
Poll the status of an image processing job. Returns different HTTP codes and payloads depending on the current job state.
Request
Method: GET
Path: /image-pipeline/status/:jobId
| Param | Type | Required | Description |
|---|---|---|---|
jobId | string | Yes | Job ID returned by the upload endpoint |
Response by Status
| Job Status | HTTP | Extra Fields |
|---|---|---|
PENDING | 202 | — |
PROCESSING | 202 | — |
COMPLETE | 200 | media object |
REJECTED | 400 | reason, moderationDetails |
FAILED | 500 | error, attempts |
COMPLETE response (200)
{
"jobId": "clx1234abcd",
"status": "COMPLETE",
"media": {
"id": "med_abc",
"sourceType": "avatar",
"sourceId": "user-abc123",
"urls": {
"xs": "https://cdn.example.com/media/avatar/user-abc123/med_abc/xs.webp",
"sm": "https://cdn.example.com/media/avatar/user-abc123/med_abc/sm.webp"
},
"originalUrl": "https://cdn.example.com/originals/avatar/user-abc123/med_abc/original.jpg",
"width": 1200,
"height": 800,
"aspectRatio": "3:2",
"blurhash": "LEHV6nWB2yk8pyo0adR*.7kCMdnj"
}
}
REJECTED response (400)
{
"jobId": "clx1234abcd",
"status": "REJECTED",
"reason": "Content moderation failed",
"moderationDetails": { "flags": ["explicit"], "confidence": 0.97 }
}
FAILED response (500)
{
"jobId": "clx1234abcd",
"status": "FAILED",
"error": "Sharp processing error",
"attempts": 3
}
Examples
Poll until complete (client-side)
async function waitForProcessing(jobId, maxPolls = 30) {
for (let i = 0; i < maxPolls; i++) {
const res = await fetch(`/image-pipeline/status/${jobId}`);
const body = await res.json();
if (res.status === 200) return body.media; // COMPLETE
if (res.status === 400) throw new Error(body.reason); // REJECTED
if (res.status === 500) throw new Error(body.error); // FAILED
await new Promise((r) => setTimeout(r, 1500)); // 1.5 s between polls
}
throw new Error("Processing timed out");
}
// Usage
const jobId = (await uploadFile(file)).jobId;
const media = await waitForProcessing(jobId);
console.log(media.urls.sm); // ready-to-use URL
Server-side webhook — check status and notify user
fastify.post("/webhooks/image-ready", async (request, reply) => {
const { jobId, userId } = request.body;
const res = await fetch(`http://localhost:3000/image-pipeline/status/${jobId}`);
const data = await res.json();
if (data.status === "COMPLETE") {
await fastify.notifications.send(userId, {
type: "image_ready",
avatarUrl: data.media.urls.sm,
});
}
return { ok: true };
});
See Also
- POST /image-pipeline/upload — Create the job
- getStatus(jobId) — Programmatic status fetch via decorator
- deleteMedia(mediaId) — Clean up after processing
AI Context
package: "@xenterprises/fastify-ximagepipeline"
route: GET /image-pipeline/status/:jobId
use-when: Poll job processing status — returns variant URLs and blurhash when COMPLETE
returns: { status (PENDING|PROCESSING|COMPLETE|REJECTED|FAILED), media? { variants, blurhash, metadata } }
