Documenting file upload APIs with Swagger and OpenAPI

Documenting your file upload and download APIs is essential for ensuring maintainability and ease of use in web services. In this post, we'll explore how to effectively document your file APIs using Swagger and the OpenAPI Specification, enabling developers to seamlessly interact with your RESTful services.
Introduction
In modern web development, file APIs are critical to handling file uploads and downloads in web services. Clear documentation is essential for helping developers quickly integrate and maintain these endpoints. This guide demonstrates how to document your file upload and download endpoints using Swagger—now part of the OpenAPI Specification—which helps you create interactive and standardized documentation for your REST API.
Understanding file APIs
What is a file API?
A file API is a set of programmatic interfaces that enable the uploading and downloading of files over the internet. These APIs allow clients to interact with server-side resources to store and retrieve files such as images, documents, or any binary data. Properly designed file APIs are vital for web services that handle file transfers, ensuring efficient and secure communication between clients and servers.
What are Swagger and OpenAPI?
Swagger, originally known by this name, is now part of the OpenAPI Specification—a language-agnostic standard for describing RESTful APIs. The OpenAPI Specification lets you define your API's endpoints, parameters, response models, and other details in a standardized format. Using the latest stable version (OpenAPI 3.1.0) ensures that your documentation is modern and easy to integrate with a variety of tools, such as Swagger UI and Swagger Editor, which generate interactive API documentation to simplify testing and integration.
Benefits of documenting APIs
- Improved Developer Experience: Clear documentation helps developers understand how to use your API without confusion.
- Standardization: Using a standard like OpenAPI promotes consistency across your API documentation.
- Automatic Documentation Generation: Tools can automatically generate interactive documentation from your OpenAPI definition.
- Simplified Maintenance: Updating the documentation is easier when it is defined in a structured, machine-readable format.
- Enhanced API Testing: Developers can utilize tools like Postman or cURL to test your file upload and download endpoints effectively.
Setting up Swagger in your project
We'll use a Node.js project with Express for this example.
Initialize the project
mkdir file-api-swagger
cd file-api-swagger
npm init -y
Install dependencies
npm install express@4.18.2 swagger-ui-express@5.0.0 swagger-jsdoc@6.2.8 multer@1.4.5-lts.1
Note: While Multer is still widely used for handling file uploads, it has not received major updates since 2022. For new projects, consider alternatives like
formidable
orbusboy
.
Basic Express Server setup
const express = require('express')
const app = express()
const port = 3000
app.use(express.json())
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`)
})
Documenting file upload endpoints
Setting up multer for file uploads
const multer = require('multer')
const upload = multer({
dest: 'uploads/',
limits: {
fileSize: 5 * 1024 * 1024, // 5MB limit
},
fileFilter: (req, file, cb) => {
const allowedTypes = ['image/jpeg', 'image/png', 'application/pdf']
if (!allowedTypes.includes(file.mimetype)) {
return cb(new Error('Invalid file type'), false)
}
cb(null, true)
},
})
Single file upload endpoint
app.post('/upload', upload.single('file'), (req, res) => {
try {
if (!req.file) {
return res.status(400).json({ error: 'No file uploaded' })
}
res.json({
message: 'File uploaded successfully',
file: {
name: req.file.originalname,
size: req.file.size,
mimetype: req.file.mimetype,
},
})
} catch (error) {
res.status(500).json({ error: 'File upload failed' })
}
})
Documenting with Swagger
Adding Swagger configuration
Create a swagger.js
file:
const swaggerJsDoc = require('swagger-jsdoc')
const swaggerUi = require('swagger-ui-express')
const swaggerDefinition = {
openapi: '3.1.0',
info: {
title: 'File Upload API',
version: '1.0.0',
description: 'API documentation for file upload and download endpoints',
},
servers: [
{
url: 'http://localhost:3000',
},
],
components: {
securitySchemes: {
ApiKeyAuth: {
type: 'apiKey',
in: 'header',
name: 'X-API-Key',
},
},
},
}
const options = {
swaggerDefinition,
apis: ['./index.js'],
}
const swaggerSpec = swaggerJsDoc(options)
module.exports = {
swaggerUi,
swaggerSpec,
}
Integrate Swagger UI into the server
In your index.js
:
const { swaggerUi, swaggerSpec } = require('./swagger')
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec))
Start your server:
node index.js
Visit http://localhost:3000/api-docs
to view the interactive Swagger UI documentation.
Adding Swagger comments to document the endpoint
Update your index.js
with the following Swagger comments:
/**
* @swagger
* /upload:
* post:
* security:
* - ApiKeyAuth: []
* summary: Uploads a file.
* requestBody:
* required: true
* content:
* multipart/form-data:
* schema:
* type: object
* properties:
* file:
* type: string
* format: binary
* responses:
* 200:
* description: File uploaded successfully.
* content:
* application/json:
* schema:
* type: object
* properties:
* message:
* type: string
* file:
* type: object
* properties:
* name:
* type: string
* size:
* type: number
* mimetype:
* type: string
* 400:
* description: No file uploaded
* 500:
* description: File upload failed
*/
app.post('/upload', upload.single('file'), (req, res) => {
try {
if (!req.file) {
return res.status(400).json({ error: 'No file uploaded' })
}
res.json({
message: 'File uploaded successfully',
file: {
name: req.file.originalname,
size: req.file.size,
mimetype: req.file.mimetype,
},
})
} catch (error) {
res.status(500).json({ error: 'File upload failed' })
}
})
Multiple file uploads
/**
* @swagger
* /uploads:
* post:
* security:
* - ApiKeyAuth: []
* summary: Uploads multiple files.
* requestBody:
* required: true
* content:
* multipart/form-data:
* schema:
* type: object
* properties:
* files:
* type: array
* items:
* type: string
* format: binary
* responses:
* 200:
* description: Files uploaded successfully.
* content:
* application/json:
* schema:
* type: object
* properties:
* message:
* type: string
* files:
* type: array
* items:
* type: object
* properties:
* name:
* type: string
* size:
* type: number
* mimetype:
* type: string
*/
app.post('/uploads', upload.array('files', 10), (req, res) => {
try {
if (!req.files || req.files.length === 0) {
return res.status(400).json({ error: 'No files uploaded' })
}
res.json({
message: 'Files uploaded successfully',
files: req.files.map((file) => ({
name: file.originalname,
size: file.size,
mimetype: file.mimetype,
})),
})
} catch (error) {
res.status(500).json({ error: 'File upload failed' })
}
})
Testing file upload APIs with postman
Postman is a popular tool for testing APIs, including file upload endpoints. To test your file upload endpoints:
- Open Postman and create a new POST request.
- Enter your API endpoint URL (e.g.,
http://localhost:3000/upload
). - In the Body tab, select
form-data
and add a key namedfile
. - Change the type of the
file
key to File and select a file from your system. - Add the
X-API-Key
header with your API key. - Send the request and observe the response.
Alternatively, you can test using cURL:
curl -fsSL -F 'file=@/path/to/your/file.jpg' -H 'X-API-Key: YOUR_API_KEY' http://localhost:3000/upload
Documenting file download endpoints
/**
* @swagger
* /download/{filename}:
* get:
* security:
* - ApiKeyAuth: []
* summary: Downloads a file.
* parameters:
* - in: path
* name: filename
* required: true
* schema:
* type: string
* description: Name of the file to download.
* responses:
* 200:
* description: File downloaded successfully.
* content:
* application/octet-stream:
* schema:
* type: string
* format: binary
* 404:
* description: File not found
* 500:
* description: Download failed
*/
app.get('/download/:filename', (req, res) => {
try {
const file = `${__dirname}/uploads/${req.params.filename}`
res.download(file, (err) => {
if (err) {
res.status(404).json({ error: 'File not found' })
}
})
} catch (error) {
res.status(500).json({ error: 'Download failed' })
}
})
Security considerations
API key management
Implement rate limiting to protect your endpoints:
const rateLimit = require('express-rate-limit')
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per window
})
app.use(limiter)
Secure file transfers
To ensure secure file transfers, follow these best practices:
- Use HTTPS for all API endpoints to encrypt data in transit.
- Apply middleware like Helmet to set secure HTTP headers.
- Validate file types and enforce file size limits, as demonstrated in the Multer configuration.
- Regularly update dependencies and monitor for security advisories.
For example, you can secure your Express app with Helmet:
const helmet = require('helmet')
app.use(helmet())
Conclusion
Documenting your file upload and download APIs using Swagger and the OpenAPI Specification not only clarifies how to interact with your services but also simplifies maintenance and testing. In this guide, we set up an Express server, integrated Swagger for interactive documentation, and implemented essential security measures. For more advanced file handling solutions, consider exploring Uppy, which offers modern, modular approaches to file uploads.
Happy coding!