Image Upload Service
Build an image upload service in Java: clients upload images through an HTTP API, the service checks that each file really is an image of an allowed type and size (by its content, not its name), creates thumbnails, stores information about each image in PostgreSQL, and lets only the owner download the original and thumbnails through links that expire. Responses and metadata are JSON handled by Jackson, uploads are streamed so large files don't fill memory, and nothing half-finished is left behind when something fails. You'll learn handling uploads safely in Java, image processing with ImageIO (or Thumbnailator), storing metadata with JDBC, signed expiring download links, and testing an HTTP service.
- Estimate
- ~12h
- Steps
- 6
- Completed by
- 0
- Proposed by
- codeseed.app
Spring Boot · PostgreSQL · Jackson · Thumbnailator
Project roadmap
- 01
Define the service
~1.5hWrite API.md: POST /images (multipart upload, with the owner from an API key header), GET /images/{id} (metadata as JSON), GET /images/{id}/download?size=original|small|medium (requires a signed link), POST /images/{id}/links (creates a signed link that expires), and DELETE /images/{id}. Define the limits (maximum size and dimensions, allowed types JPEG, PNG and WebP if supported), thumbnail sizes and error format. Create a project with Spring Boot (or Javalin) and Jackson. Done when: API.md defines every endpoint, limit and error.
- 02
Accept and validate uploads
~2hStream uploads to a temporary file while enforcing the size limit. Detect the real type from the file's first bytes (magic numbers, or Apache Tika), and read the dimensions with ImageIO's ImageReader without decoding the whole image, refusing images larger than the pixel limit. Reject everything else with a clear error. Done when: a renamed text file, an oversized file and a huge-dimension image are all rejected.
- 03
Generate thumbnails
~2hCreate small and medium thumbnails with Thumbnailator (or ImageIO and Graphics2D with good quality settings), keeping proportions, never enlarging, and applying the EXIF orientation. Write each file to a temporary name and move it into its final place only after everything succeeded; otherwise delete what was created. Done when: uploads produce correct thumbnails, and a failure leaves no files behind.
- 04
Store metadata in PostgreSQL
~2hCreate tables for images (id, owner, original name, type, width, height, size, SHA-256 checksum and created at) and their files, with a migration (Flyway). Save everything in one transaction after the files are ready, using JDBC or Spring Data. Return metadata as JSON with Jackson, and detect duplicates for the same owner by checksum. Done when: metadata is saved and returned, and duplicates are detected.
- 05
Serve downloads securely
~2hCreate signed links: a URL with the image id, size, expiry time and an HMAC-SHA256 signature of those values made with a server secret. The download endpoint checks the signature (with a constant-time comparison) and expiry, then streams the file with the right Content-Type and Content-Disposition headers. Only the owner can create links or delete images. Done when: valid links download files, and tampered or expired links get 403.
- 06
Test it
~2.5hWrite tests with a real PostgreSQL (Testcontainers) and small generated images: each validation rule, thumbnail sizes and orientation, cleanup after a simulated failure, duplicates, signed links (valid, tampered, expired and wrong owner), and deletes removing files and rows. 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