REST API File Upload and Download

APIs handle more than JSON. Users upload profile photos, attach PDFs to support tickets, and download invoices and reports. Files are large, binary, and risky, so they need special design.

The Post Office Picture

Sending a letter requires only an address. Sending a heavy parcel requires a box, a label, a weight check, and a customs form. A file upload follows the same pattern. The request carries extra details about the file along with the file itself.

Upload with multipart/form-data

The multipart/form-data format splits a request into parts. One part holds the file, and other parts hold text fields such as a title.

POST /documents
Content-Type: multipart/form-data; boundary=XYZ

--XYZ
Content-Disposition: form-data; name="title"

Quarterly Report
--XYZ
Content-Disposition: form-data; name="file"; filename="report.pdf"
Content-Type: application/pdf

(binary data)
--XYZ--

A successful upload returns 201 Created with a Location header that points to the new file resource.

Direct Upload with Pre-Signed URLs

Large files strain an API server. A better pattern sends the file straight to cloud storage. The API issues a temporary signed URL, and the client uploads to that URL.

Client ── 1. request upload link ──→ API Server
Client ←── 2. signed URL (expires in 10 minutes) ── API Server
Client ── 3. PUT file ──────────────→ Cloud Storage
Client ── 4. confirm upload ────────→ API Server

The API server never touches the file bytes. This design saves bandwidth and scales well.

Download Basics

A download response sets the Content-Type header to the file type and the Content-Length header to the file size. The Content-Disposition header controls browser behavior.

HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Length: 482113
Content-Disposition: attachment; filename="invoice-204.pdf"

The value attachment prompts a save dialog. The value inline displays the file in the browser.

Resumable Downloads with Range Requests

Large downloads break when connections drop. Range requests let a client ask for part of a file.

GET /videos/55/file
Range: bytes=1000000-1999999

HTTP/1.1 206 Partial Content
Content-Range: bytes 1000000-1999999/8400000

Video players use this feature to jump to any point in a clip, and download managers use it to resume after a failure.

Upload Safety Checklist

  • Set a maximum file size and return 413 Content Too Large above it.
  • Allow only approved file types, and check the real content, not just the extension.
  • Generate a new random file name on the server and ignore the client name.
  • Store uploads outside the web root so the server never runs them as code.
  • Scan files for malware before other users can open them.
  • Require authentication and confirm that the user may access each file.

Metadata and Resource Design

Treat a file as a resource with its own record. The record holds the id, name, size, type, owner, and upload date. Use /documents/15 for the metadata and /documents/15/content for the raw bytes. Clients can list files cheaply without downloading any content.

Common Mistakes

Sending Files as Base64 in JSON

Base64 inflates file size by about one third and consumes memory on both sides. Use multipart or direct upload for anything beyond tiny images.

Trusting the Content-Type Header

A client can label any file as an image. Inspect the file signature on the server before accepting it.

Public Links Without Expiry

Permanent open links leak private files. Use signed URLs that expire after a short time.