Help us measure site usage?

With your permission, we use self-hosted analytics to understand page usage. It is optional and does not affect the Service. Learn more.

TypeScriptintermediatebackendAI generated

Image Processing API

Build an image processing service in TypeScript with Node.js. Users upload a photo, and the API checks that it's a real image (by reading its actual content, not trusting the file name), creates thumbnails in several sizes, converts them to WebP, and returns typed metadata: dimensions, format, file size and the thumbnail URLs. A small React page lets you upload images and see the results. Duplicate uploads are detected and reused, and uploads are limited in size and rate. You'll learn file uploads with multer, image processing with sharp, validating untrusted files, typed API contracts shared between server and client, and testing an API.

Estimate
~12.5h
Steps
7
Completed by
0
Proposed by
codeseed.app

Node.js · React

Project roadmap

  1. 01

    Set up the project

    ~1.5h

    Create a monorepo-style project with two folders: server (Node.js, TypeScript, Express, multer, sharp, zod) and web (React with Vite and TypeScript), plus a shared folder for types used by both. Configure TypeScript in strict mode. The server exposes GET /health. Done when: both the server and the web app start, and the web app can call /health.

  2. 02

    Accept and validate uploads

    ~2h

    Add POST /images using multer with memory storage and a 10 MB limit. Detect the real file type from its first bytes (with the file-type package or sharp's metadata), accept only JPEG, PNG and WebP, and reject images larger than 8000×8000 pixels. Return 413 for files that are too big, 415 for unsupported types and 400 for corrupted images, as typed JSON errors. Done when: a real image is accepted, and a renamed text file is rejected.

  3. 03

    Create thumbnails with sharp

    ~2h

    For each accepted image, apply the EXIF rotation (.rotate()), then create WebP thumbnails at widths of 150, 400 and 800 pixels, keeping the aspect ratio and never enlarging small images. Remove metadata such as GPS location from the outputs. Save the original and thumbnails in a storage folder under an id. Done when: uploading a photo creates three correctly sized WebP thumbnails.

  4. 04

    Return typed metadata

    ~1.5h

    Define an ImageResult type in the shared folder (id, original width, height, format and size, and the thumbnails with width, size and URL) and a matching zod schema. Return it from POST /images, add GET /images/:id returning the same data, and serve the files from /files. Done when: the response matches the shared type, and the thumbnail URLs open in the browser.

  5. 05

    Detect duplicates and limit abuse

    ~1.5h

    Compute the SHA-256 hash of each upload, and when the same image was already processed, return the existing result instead of processing it again. Keep the hash-to-id mapping in a small JSON file or SQLite database. Add a simple rate limit per IP address (for example 20 uploads per minute) returning 429. Done when: uploading the same image twice returns the same id without creating new files.

  6. 06

    Build the upload page

    ~2h

    In the web app, add a drag-and-drop area (and a file picker), upload with fetch and FormData, show a progress or loading state, then display the original metadata and the three thumbnails with their sizes. Validate the response with the zod schema, and show the server's error messages clearly. Done when: dropping an image on the page shows its thumbnails and details.

  7. 07

    Write tests

    ~2h

    Write server tests with Vitest and supertest using small fixture images: a valid JPEG and PNG, a text file renamed to .jpg, a corrupted image, a file over the limit, and a duplicate upload. Check the status codes, the thumbnail sizes and the response shape. Done when: the tests pass.

Ready to build this?

Get a GitHub repo and start building. Your AI reviewer checks each step as you go.

~12.5h · 7 steps

Tech stack

Node.jsReact