Files
reactbin/specs/002-api-image-proxy/contracts/api.md
agatha cd89ba5dea Feat: Proxy image content through the API instead of redirecting to MinIO
Replace the presigned-URL redirect (302) in GET /api/v1/images/{id}/file
with a direct proxy that fetches bytes from S3 server-side and returns them
to the client. The browser never contacts the storage backend, eliminating
the /etc/hosts workaround needed in local development.

- StorageBackend: swap get_presigned_url for get(key) -> bytes
- S3StorageBackend: implement get() via aiobotocore get_object
- serve_image_file: return Response with ETag + Cache-Control: immutable
- test_serving: assert 200 + content-type + ETag; add no-storage-details test
- Spec Kit artifacts for feature 002-api-image-proxy

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03 16:36:43 +00:00

2.0 KiB

API Contract: Image Content Endpoint

Branch: 002-api-image-proxy | Date: 2026-05-03

Changed endpoint

GET /api/v1/images/{image_id}/file

Serves the binary content of the image with the given ID, proxied through the API from object storage.

Path parameters

Parameter Type Description
image_id UUID Unique identifier of the image

Responses

200 OK — Image content

Header Value Notes
Content-Type image/jpeg | image/png | image/gif | image/webp Taken from stored mime_type
ETag "<sha256-hex>" SHA-256 hash of the image content; quoted string per RFC 7232
Cache-Control public, max-age=31536000, immutable Safe: images are immutable after upload

Body: raw image bytes.

404 Not Found — Image not found

{ "detail": "Image not found", "code": "image_not_found" }

500 Internal Server Error — Storage retrieval failure

{ "detail": "Failed to retrieve image content", "code": "storage_error" }

No storage-specific details (bucket name, hostname, credentials) are exposed in error responses.


Breaking change from prior behaviour

Aspect Before After
Status code 302 Found 200 OK
Location header Present (presigned S3 URL) Absent
Body Empty Raw image bytes
Browser behaviour Follows redirect to storage Receives content from API

The endpoint path is unchanged. The UI requires no URL-construction changes.


Removed StorageBackend capability

The get_presigned_url operation is removed from the StorageBackend interface. It was the only mechanism for generating time-limited direct-access URLs to stored objects, and had a single call site (serve_image_file). With the proxy in place it has no remaining callers.

Any future need for presigned URLs (e.g., direct-upload flows) would require a new spec and a new interface method.