Initial commit: nick docs
This commit is contained in:
111
03 - API Reference/File API.md
Normal file
111
03 - API Reference/File API.md
Normal file
@@ -0,0 +1,111 @@
|
||||
---
|
||||
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)
|
||||
Reference in New Issue
Block a user