Files
nick-doc/03 - API Reference/File API.md
2026-05-23 20:35:34 +03:30

4.1 KiB

title, tags
title tags
File API
api
file
reference

File API

Endpoints live under /api/files/*. The router is 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:

{
  "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.