Skip to main content

File Storage (S3)

The storage module provides presigned URL-based file uploads to Amazon S3 with content-type validation and filename sanitization.

Endpoints

MethodPathAuthDescription
POST/storage/upload-urlYesGenerate a presigned S3 upload URL
DELETE/storage/*keyYesDelete a file by its S3 object key

Upload Flow

  1. The client calls POST /storage/upload-url with filename and contentType.
  2. The API validates the content type, sanitizes the filename, and generates a presigned PUT URL (valid for 10 minutes).
  3. The response includes:
    • uploadUrl -- the presigned S3 URL for the client to PUT the file directly
    • key -- the S3 object key (e.g., uploads/<userId>/<uuid>-<filename>)
    • publicUrl -- the public URL of the uploaded file
  4. The client uploads the file directly to S3 using the presigned URL.

Allowed Content Types

MIME TypeDescription
image/jpegJPEG images
image/pngPNG images
image/gifGIF images
image/webpWebP images
image/svg+xmlSVG images
application/pdfPDF documents
text/plainPlain text
text/csvCSV files

Requests with a content type not in this list receive a 400 Bad Request.

Filename Sanitization

Uploaded filenames are sanitized before becoming part of the S3 key:

  • Non-alphanumeric characters (except ., -, _) are replaced with underscores.
  • Consecutive underscores are collapsed.
  • The filename is truncated to 200 characters.

CloudFront CDN

For production, place a CloudFront distribution in front of the S3 bucket. The publicUrl returned by the API uses the S3 URL by default. To serve files through CloudFront, configure CLOUDFRONT_DOMAIN and update the URL construction in StorageService.

Graceful Fallback

When AWS_S3_BUCKET, AWS_ACCESS_KEY_ID, or AWS_SECRET_ACCESS_KEY are not set, the service logs a warning at startup. Any call to generate an upload URL or delete a file returns 400 Bad Request with the message "Storage is not configured". This allows the rest of the application to start without AWS credentials during local development.

Environment Variables

AWS_S3_BUCKET=my-bucket
AWS_REGION=ap-south-1
AWS_ACCESS_KEY_ID=AKIA...
AWS_SECRET_ACCESS_KEY=...