Image Upload API
Build an image upload service in JavaScript: a Node.js API accepts image uploads, checks they are real images within the size limits, creates thumbnails in a few sizes with the sharp library, and returns information about each image (dimensions, format, file size and thumbnail URLs), plus a small React page built with Vite for uploading by drag and drop with progress bars and previews. The service strips hidden metadata such as GPS location from photos, detects duplicate uploads, and never leaves half-processed files behind. You'll learn handling file uploads safely, image processing with sharp, streaming, designing an API response, building an upload interface with progress, and testing.
- Estimate
- ~11h
- Steps
- 6
- Completed by
- 0
- Proposed by
- codeseed.app
Node.js · Express · sharp · Vite · React
Project roadmap
- 01
Define the API
~1.5hWrite API.md: POST /images (multipart form upload), GET /images/:id (metadata and thumbnail URLs), GET /images (a paginated list) and DELETE /images/:id, the limits (maximum file size, maximum dimensions, allowed formats JPEG, PNG and WebP, and at most 10 files per request), the thumbnail sizes (for example 150, 400 and 1200 pixels wide) and the error format. Done when: API.md defines the endpoints, limits and errors.
- 02
Accept uploads safely
~2hBuild the server with Express and multer (or busboy), enforcing the size and file count limits while receiving. Check the real type from the file's first bytes (for example with the file-type package), not the name, and read the dimensions with sharp's metadata(), refusing images too large before processing them. Store originals under random names outside the public folder. Done when: a renamed text file, an oversized file and a huge-dimension image are rejected with clear errors.
- 03
Create thumbnails
~2hWith sharp, rotate each image according to its EXIF orientation, remove its metadata (including GPS), and create the thumbnail sizes in WebP (without enlarging small images). Write outputs to temporary files and move them into place only when all succeeded, cleaning up otherwise. Done when: uploads produce correctly oriented thumbnails with no metadata.
- 04
Store metadata and detect duplicates
~1.5hStore each image's metadata in SQLite (or a JSON store): id, original name, format, dimensions, file size, SHA-256 checksum (unique), thumbnails and created time. When the same checksum is uploaded again, return the existing image instead of processing it again. Implement the list and delete endpoints (deleting files too). Done when: duplicate uploads return the existing image, and deletes remove everything.
- 05
Build the upload page
~2hBuild a React page with Vite: a drop zone and file picker, a check of type and size before uploading, uploads with progress bars (using XMLHttpRequest's upload progress event, since fetch doesn't report it), previews of the returned thumbnails, and clear error messages per file. Show a gallery of uploaded images with delete buttons. Done when: several images can be dropped and uploaded with visible progress.
- 06
Test it
~2hWrite tests with Vitest and supertest using small generated images: each validation rule, thumbnail sizes and orientation, metadata removal, duplicate detection, cleanup after a simulated processing failure, and listing and deleting. Done when: all tests pass.
Resources
Ready to build this?
Get a GitHub repo and start building. Your AI reviewer checks each step as you go.
Tech stack