Created
April 22, 2025 18:06
-
-
Save Eddie2111/51895b5ccd70d2e537e689922ef44825 to your computer and use it in GitHub Desktop.
Uploading images to Sanity CMS from NextJS App Router
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sharp from "sharp"; | |
// example rate limiter for getting images | |
import RateLimiter_Middleware from "@/lib/rate-limiter.middleware"; | |
function generateUniqueFilename() { | |
const timestamp = new Date().toISOString().replace(/[:.-]/g, "_"); | |
const randomString = Math.random().toString(36).substring(2, 8); | |
return `${timestamp}_${randomString}.webp`; | |
} | |
async function fetchImageDetails(imageId: string) { | |
const imageQuery = `*[_type == "images" && _id == $imageId]{ | |
mainImage { | |
asset->{ | |
url, | |
metadata { | |
dimensions { | |
width, | |
height | |
} | |
} | |
}, | |
alt | |
} | |
}`; | |
return await client.fetch(imageQuery, { imageId }); | |
} | |
export async function GET(request: Request) { | |
await RateLimiter_Middleware(request); | |
try { | |
const url = new URL(request.url); | |
const imageId = url.searchParams.get("id"); | |
if (!imageId) { | |
return Response.json({ error: "Image ID is required" }, { status: 400 }); | |
} | |
const result = await fetchImageDetails(imageId); | |
if (!result || result.length === 0) { | |
return Response.json({ error: "Image not found" }, { status: 404 }); | |
} | |
const imageData = result[0].mainImage; | |
return Response.json({ | |
message: "Image retrieved successfully", | |
imageUrl: imageData.asset.url, | |
altText: imageData.alt, | |
dimensions: imageData.asset.metadata.dimensions, | |
}); | |
} catch (error) { | |
console.error("Error retrieving image:", error); | |
return Response.json( | |
{ error: "Failed to retrieve image" }, | |
{ status: 500 }, | |
); | |
} | |
} | |
export async function POST(request: Request) { | |
await RateLimiter_Middleware(request); | |
try { | |
const formData = await request.formData(); | |
const file = formData.get("file"); | |
if (!file) { | |
return Response.json({ error: "No file uploaded" }, { status: 400 }); | |
} | |
const allowedMimeTypes = ["image/jpeg", "image/png", "image/webp"]; | |
const mimeType = (file as File).type; | |
if (!allowedMimeTypes.includes(mimeType)) { | |
return Response.json( | |
{ | |
error: | |
"Invalid file type. Only JPEG, PNG, and WebP images are allowed.", | |
}, | |
{ status: 400 }, | |
); | |
} | |
const arrayBuffer = await (file as File).arrayBuffer(); | |
const buffer = Buffer.from(arrayBuffer); | |
// eslint-disable-next-line @typescript-eslint/no-explicit-any | |
let imageMetadata: any; | |
try { | |
imageMetadata = await sharp(buffer).metadata(); | |
} catch (error) { | |
console.log(error); | |
return Response.json( | |
{ error: "Uploaded file is not a valid image." }, | |
{ status: 400 }, | |
); | |
} | |
if (!["jpeg", "png", "webp"].includes(imageMetadata.format)) { | |
return Response.json( | |
{ | |
error: | |
"Unsupported image format. Only JPEG, PNG, and WebP are allowed.", | |
}, | |
{ status: 400 }, | |
); | |
} | |
const optimizedImageBuffer = await sharp(buffer) | |
.webp({ quality: 70, effort: 3 }) | |
.toBuffer(); | |
const uniqueFilename = generateUniqueFilename(); | |
const assetResponse = await client.assets.upload( | |
"image", | |
optimizedImageBuffer, | |
{ | |
filename: uniqueFilename, | |
contentType: "image/webp", | |
}, | |
); | |
const docResponse = await client.create({ | |
_type: "images", | |
mainImage: { | |
_type: "image", | |
asset: { | |
_type: "reference", | |
_ref: assetResponse._id, | |
}, | |
alt: uniqueFilename.split(".")[0], | |
}, | |
}); | |
return Response.json({ | |
message: "File uploaded, optimized, and stored in Sanity successfully", | |
optimizedSize: optimizedImageBuffer.length, | |
uniqueFilename, | |
sanityAssetId: assetResponse._id, | |
imageId: docResponse._id, | |
}); | |
} catch (error) { | |
console.error("Error processing file upload:", error); | |
return Response.json({ error: "Failed to process file" }, { status: 500 }); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
note: I was uploading multiple files using formdata