---
title: File API
tags: [api, file, reference]
---

# File API

Endpoints live under `/api/files/*`. The router is [`backend/src/services/file/fileRoutes.ts`](../../backend/src/services/file/fileRoutes.ts), delegating to `fileController` and `fileService`. Multer is used for multipart parsing and uploaded files are written under `uploads/<subfolder>`.

All endpoints require `Bearer JWT`. Static serving is wired in `app.ts` at `/uploads/*` with `helmet({ crossOriginResourcePolicy: { policy: "cross-origin" } })` so files can be embedded from the frontend domain.

## Multer configuration

`fileService.getUploadMiddleware(options)` produces a Multer instance per route. Options:

- `subfolder` - where the file lands under `uploads/`
- `fieldName` - form field name
- `fileTypes` - allowed MIME types (default: any)
- `maxFiles` - default 1
- `maxFileSizeMB` - default 10 MB

Global body limits in `app.ts` are `10mb` for `express.json` and `express.urlencoded`.

## Upload

### POST /api/files/upload/avatar

**Description:** Upload an avatar image. Lands in `uploads/temp/` and is then moved when the user persists it on their profile.
**Auth required:** Bearer JWT
**Form fields:** `avatar` (image; JPEG / PNG / GIF / WebP)
**Response 200:**
```json
{
  "success": true,
  "data": {
    "url": "/uploads/temp/avatar-1716459200000.jpg",
    "filename": "avatar-1716459200000.jpg",
    "mimeType": "image/jpeg",
    "size": 51234
  }
}
```
**Errors:** `400` bad type / too large, `401` not authenticated.
**Side effects:** None — caller is responsible for `PUT /api/user/profile` to persist the URL.

### POST /api/files/upload/file

**Description:** Generic single-file upload (any MIME), lands in `uploads/temp/`.
**Auth required:** Bearer JWT
**Form fields:** `file`
**Response 200:** `{ success, data: { url, filename, mimeType, size } }`

### POST /api/files/upload/files

**Description:** Multi-file upload (up to 5).
**Auth required:** Bearer JWT
**Form fields:** `files` (repeated)
**Response 200:** `{ success, data: { files: [{ url, filename, ... }] } }`

### POST /api/files/upload/request-template-images

**Description:** Up to 10 images for a [[RequestTemplate]]. Lands in `uploads/request-templates/`.
**Auth required:** Bearer JWT
**Form fields:** `images` (repeated; JPEG / PNG / GIF / WebP)
**Response 200:** `{ success, data: { files: [...] } }`

### POST /api/files/upload/blog-images

**Description:** Up to 10 images for a [[BlogPost]]. Lands in `uploads/blog/`.
**Auth required:** Bearer JWT
**Form fields:** `images` (repeated; JPEG / PNG / GIF / WebP)
**Response 200:** `{ success, data: { files: [...] } }`

## Delete

### DELETE /api/files/delete

**Description:** Delete a file by relative path.
**Auth required:** Bearer JWT
**Request body:** `{ filePath: string }` (e.g. `"temp/avatar-1716459200000.jpg"`)
**Response 200:** `{ success, message: "File deleted" }`
**Errors:** `400` invalid path (must stay inside `uploads/`), `404` file missing.

## Inspect

### GET /api/files/info/:filePath

**Description:** Returns metadata for a file (URL-encoded `filePath` segment).
**Auth required:** Bearer JWT
**Response 200:** `{ success, data: { url, size, mimeType, createdAt } }`

### GET /api/files/stats

**Description:** Aggregate upload statistics (counts and sizes per subfolder).
**Auth required:** Bearer JWT (admin gating planned per TODO in source)
**Response 200:** `{ success, data: { subfolders: [{ name, count, sizeBytes }], total: { count, sizeBytes } } }`

## Serving

- `GET /uploads/<path>` - static file delivery (no auth, public read). Suitable for embedding avatars and blog/template images.
- The server logs `❌ File not found:` for missing paths and `✅ Serving file:` on hits — useful when debugging frontend image refs.

The on-disk root resolves from `config.uploadPath`. In production this defaults to `/app/uploads`; in development to `<repo>/uploads`. Both are normalised to an absolute path before being passed to `express.static`.

## Related

- [[File Storage Architecture]]
- [[User API]] (avatar consumer)
- [[Marketplace API]] (template image consumer)
- [[Blog API]] (blog image consumer)
- [[Chat API]] (message attachments use a separate multipart route under chat)
