Overview
API Master provides a robust file upload system built with Multer middleware. Files are uploaded via a POST endpoint and stored on the server with unique filenames. Each uploaded file is immediately accessible via a public URL.
How File Upload Works
The file upload system uses Multer with disk storage configuration. Here’s the actual implementation from the API:
userRoutes.ts
userController.ts
import express from 'express' ;
import userController from '../controllers/userController' ;
import multer from 'multer' ;
import path from 'path' ;
const router = express . Router ();
// Multer configuration
const storage = multer . diskStorage ({
destination : ( req , file , cb ) => {
cb ( null , path . join ( __dirname , '../../uploads' ));
},
filename : ( req , file , cb ) => {
const uniqueName = 'file-' + Date . now () + '-' + Math . random (). toString ( 36 ). substr ( 2 , 9 ) + path . extname ( file . originalname );
cb ( null , uniqueName );
}
});
const upload = multer ({ storage: storage });
router . post ( '/upload' , upload . single ( 'file' ), userController . uploadFile );
export default router ;
File Storage Strategy
The API uses a unique naming strategy to prevent file conflicts:
File Destination
All files are stored in the uploads/ directory relative to the project root.
Unique Filename Generation
Each file is renamed using the pattern: file-{timestamp}-{random}-{extension} Example: file-1709740800000-x5k9m2j4p.jpg
Original Extension Preserved
The file’s original extension is preserved using path.extname(file.originalname)
The naming strategy combines a timestamp and random string to ensure uniqueness, preventing files from being overwritten.
Uploading Files
Endpoint Details
URL: POST /users/upload
Content-Type: multipart/form-data
Field Name: file
Max Files: 1 (single file upload)
Using cURL
curl -X POST http://localhost:3000/users/upload \
-F "file=@/path/to/your/image.jpg"
Using Fetch API
const formData = new FormData ();
const fileInput = document . querySelector ( '#fileInput' );
formData . append ( 'file' , fileInput . files [ 0 ]);
fetch ( 'http://localhost:3000/users/upload' , {
method: 'POST' ,
body: formData
})
. then ( response => response . json ())
. then ( data => {
console . log ( 'Success:' , data );
console . log ( 'File URL:' , data . url );
})
. catch ( error => {
console . error ( 'Error:' , error );
});
Using Axios
import axios from 'axios' ;
const formData = new FormData ();
formData . append ( 'file' , fileObject );
const response = await axios . post ( 'http://localhost:3000/users/upload' , formData , {
headers: {
'Content-Type' : 'multipart/form-data'
}
});
console . log ( response . data );
Success Response
When a file is successfully uploaded, you’ll receive:
{
"message" : "File uploaded successfully" ,
"url" : "http://localhost:3000/uploads/file-1709740800000-x5k9m2j4p.jpg"
}
The url field contains the complete public URL where the file can be accessed immediately.
Error Response
If no file is provided:
{
"message" : "No file uploaded"
}
HTTP Status: 400 Bad Request
Accessing Uploaded Files
Uploaded files are served as static content through Express. The API is configured to serve files from the /uploads route:
app . use ( '/uploads' , express . static ( path . join ( __dirname , 'uploads' )));
This means:
Files are publicly accessible without authentication
Access files via: http://your-domain.com/uploads/{filename}
Direct browser access is supported
Files can be embedded in <img> tags, downloaded, or linked
Complete HTML Example
<! DOCTYPE html >
< html >
< head >
< title > File Upload Example </ title >
</ head >
< body >
< h1 > Upload a File </ h1 >
< input type = "file" id = "fileInput" />
< button onclick = " uploadFile ()" > Upload </ button >
< div id = "result" ></ div >
< script >
async function uploadFile () {
const fileInput = document . getElementById ( 'fileInput' );
const file = fileInput . files [ 0 ];
if ( ! file ) {
alert ( 'Please select a file' );
return ;
}
const formData = new FormData ();
formData . append ( 'file' , file );
try {
const response = await fetch ( 'http://localhost:3000/users/upload' , {
method: 'POST' ,
body: formData
});
const data = await response . json ();
if ( response . ok ) {
document . getElementById ( 'result' ). innerHTML = `
<p>File uploaded successfully!</p>
<p>URL: <a href=" ${ data . url } " target="_blank"> ${ data . url } </a></p>
<img src=" ${ data . url } " style="max-width: 300px;" />
` ;
} else {
document . getElementById ( 'result' ). innerHTML = `
<p style="color: red;">Error: ${ data . message } </p>
` ;
}
} catch ( error ) {
document . getElementById ( 'result' ). innerHTML = `
<p style="color: red;">Upload failed: ${ error . message } </p>
` ;
}
}
</ script >
</ body >
</ html >
Best Practices
Consider adding file type and size validation: const upload = multer ({
storage: storage ,
limits: {
fileSize: 5 * 1024 * 1024 // 5MB limit
},
fileFilter : ( req , file , cb ) => {
const allowedTypes = /jpeg | jpg | png | gif | pdf/ ;
const extname = allowedTypes . test ( path . extname ( file . originalname ). toLowerCase ());
const mimetype = allowedTypes . test ( file . mimetype );
if ( mimetype && extname ) {
return cb ( null , true );
} else {
cb ( new Error ( 'Invalid file type' ));
}
}
});
Always validate file types on the server side
Set file size limits to prevent abuse
Consider virus scanning for production environments
Implement authentication for sensitive file uploads
Use a CDN or cloud storage for production deployments
To upload multiple files, modify the route: router . post ( '/upload-multiple' , upload . array ( 'files' , 10 ), userController . uploadMultipleFiles );
And update the controller: const uploadMultipleFiles = ( req : Request , res : Response ) => {
if ( ! req . files || req . files . length === 0 ) {
return res . status ( 400 ). json ({ message: 'No files uploaded' });
}
const files = req . files as Express . Multer . File [];
const urls = files . map ( file =>
` ${ req . protocol } :// ${ req . get ( 'host' ) } /uploads/ ${ file . filename } `
);
res . json ({
message: 'Files uploaded successfully' ,
urls: urls
});
};
The current implementation allows public access to all uploaded files. For production environments, consider implementing access control and authentication.