Image Metadata API
Build a Ruby web API that catalogs images: you register images (by upload or file path), it extracts their metadata, such as dimensions, format, file size, camera model, date taken and GPS location from EXIF data, and stores it in Redis, then offers search endpoints to filter images by any combination, for example landscape photos taken with a certain camera in 2025, with sorting and pagination. Redis sets and sorted sets act as indexes, so filters stay fast with many images. You'll learn extracting image metadata, designing indexes in Redis, combining filters with set intersections, building a small API with Sinatra, keeping indexes consistent when images change, and testing.
- Estimate
- ~12h
- Steps
- 6
- Completed by
- 0
- Proposed by
- codeseed.app
RubyGems · Redis
Project roadmap
- 01
Define the API and metadata
~1.5hWrite API.md: POST /images (upload or path), GET /images/:id, DELETE /images/:id and GET /images?format=&camera=&orientation=&taken_from=&taken_to=&min_width=&has_gps=&sort=&page=. List the metadata fields, which ones can be filtered, and the error format. Create a Sinatra app with a Gemfile (sinatra, redis and an EXIF gem such as exifr or mini_exiftool). Done when: API.md defines every endpoint and field.
- 02
Extract metadata
~2hWrite a MetadataExtractor that reads the format and dimensions from the file itself (for example with the fastimage gem or by checking file signatures), and EXIF fields (camera, date taken, orientation and GPS) for JPEG and TIFF files, converting GPS values to decimal degrees. Handle images without EXIF and corrupted files with clear results. Done when: tests extract correct metadata from sample images, with and without EXIF.
- 03
Store and index in Redis
~2.5hStore each image's metadata in a hash, and maintain indexes: sets for exact filters (format, camera, orientation and has GPS) and sorted sets for ranges (date taken, width and file size). Add and remove an image's index entries in one MULTI transaction, so indexes never point to missing images. Detect duplicates by a SHA-256 checksum. Done when: registering and deleting images keeps all indexes consistent.
- 04
Search with filters
~2.5hImplement GET /images: build the result by intersecting the sets for exact filters with ranges from the sorted sets (using ZRANGESTORE with BYSCORE into temporary keys with a short expiry, then ZINTERSTORE), sort by date or size, and page through the results. Validate every query parameter. Done when: combined filters return exactly the matching images in the right order.
- 05
Harden the API
~1.5hLimit upload size and accept only real images (checking the content), strip the GPS location from responses unless requested (it can reveal where someone lives), return 404, 409 and 422 correctly, and handle Redis being unavailable with a 503. Add a task to rebuild all indexes from the stored hashes. Done when: bad uploads and outages are handled clearly, and indexes can be rebuilt.
- 06
Test it
~2hWrite RSpec tests with Rack::Test against a test Redis database: metadata extraction, registration and duplicates, each filter alone and combined, sorting and paging, deletion cleaning up indexes, and invalid parameters. Done when: all tests pass.
Resources
- DocsSinatra documentation
- DocsRedis sets
- DocsRedis sorted sets
- Docsexifr gem
- ArticleExif (Wikipedia)
Ready to build this?
Get a GitHub repo and start building. Your AI reviewer checks each step as you go.
Tech stack