logo
eng-flag

Formidable Cheatsheet for Node.js

Formidable is a powerful Node.js module for parsing form data, especially file uploads. This cheatsheet provides an extensive overview of Formidable's features, usage, and best practices.

Table of Contents

  1. Installation
  2. Basic Usage
  3. Parsing Options
  4. File Uploads
  5. Handling Multiple Files
  6. Custom File Names
  7. Progress Tracking
  8. Error Handling
  9. Working with Fields
  10. JSON Parsing
  11. Using with Express
  12. Streaming Files
  13. Security Considerations
  14. Testing

Installation

Install Formidable using npm:

npm install formidable

Basic Usage

Here's a simple example of using Formidable in a Node.js application:

const http = require('http');
const formidable = require('formidable');

http.createServer((req, res) => {
  if (req.url === '/api/upload' && req.method.toLowerCase() === 'post') {
    // Parse a file upload
    const form = formidable({ multiples: true });

    form.parse(req, (err, fields, files) => {
      if (err) {
        res.writeHead(err.httpCode || 400, { 'Content-Type': 'text/plain' });
        res.end(String(err));
        return;
      }
      res.writeHead(200, { 'Content-Type': 'application/json' });
      res.end(JSON.stringify({ fields, files }, null, 2));
    });

    return;
  }

  // Show a file upload form
  res.writeHead(200, { 'Content-Type': 'text/html' });
  res.end(`
    <h2>With Node.js <code>"http"</code> module</h2>
    <form action="/api/upload" enctype="multipart/form-data" method="post">
      <div>Text field title: <input type="text" name="title" /></div>
      <div>File: <input type="file" name="multipleFiles" multiple="multiple" /></div>
      <input type="submit" value="Upload" />
    </form>
  `);
}).listen(8080);

Parsing Options

Formidable supports various options for parsing:

const form = formidable({
  multiples: true,
  uploadDir: '/tmp',
  keepExtensions: true,
  maxFileSize: 200 * 1024 * 1024, // 200MB
  filter: function ({ name, originalFilename, mimetype }) {
    // keep only images
    return mimetype && mimetype.includes("image");
  }
});

File Uploads

Handle file uploads easily:

const form = formidable({ uploadDir: '/tmp', keepExtensions: true });

form.parse(req, (err, fields, files) => {
  if (err) {
    console.error('Error', err);
    throw err;
  }
  console.log('Fields', fields);
  console.log('Files', files);
});

Handling Multiple Files

Work with multiple file uploads:

const form = formidable({ multiples: true });

form.parse(req, (err, fields, files) => {
  if (err) {
    console.error('Error', err);
    throw err;
  }
  
  if (Array.isArray(files.upload)) {
    // Multiple files
    files.upload.forEach(file => {
      console.log('Uploaded file:', file.originalFilename);
    });
  } else {
    // Single file
    console.log('Uploaded file:', files.upload.originalFilename);
  }
});

Custom File Names

Customize uploaded file names:

const form = formidable({
  uploadDir: '/tmp',
  keepExtensions: true,
  filename: (name, ext, part, form) => {
    return 'file_' + part.originalFilename;
  }
});

Progress Tracking

Track upload progress:

form.on('progress', (bytesReceived, bytesExpected) => {
  const percent = (bytesReceived / bytesExpected * 100) | 0;
  process.stdout.write(`
Progress: ${percent}%`);
});

Error Handling

Handle errors during parsing:

form.parse(req, (err, fields, files) => {
  if (err) {
    if (err.code === 'ETOOBIG') {
      console.error('File size limit exceeded');
    } else {
      console.error('Parsing error:', err);
    }
    res.writeHead(err.httpCode || 400, { 'Content-Type': 'text/plain' });
    res.end(String(err));
    return;
  }
  // Process fields and files
});

Working with Fields

Access form fields:

form.parse(req, (err, fields, files) => {
  if (err) throw err;
  console.log('Username:', fields.username);
  console.log('Email:', fields.email);
});

JSON Parsing

Parse JSON data:

const form = formidable({ encoding: 'utf-8', multiples: true });

form.parse(req, (err, fields, files) => {
  if (err) throw err;
  
  if (req.headers['content-type'] === 'application/json') {
    const jsonData = JSON.parse(fields.data);
    console.log('Parsed JSON:', jsonData);
  }
});

Using with Express

Integrate Formidable with Express:

const express = require('express');
const formidable = require('formidable');

const app = express();

app.post('/upload', (req, res, next) => {
  const form = formidable({ multiples: true });

  form.parse(req, (err, fields, files) => {
    if (err) {
      next(err);
      return;
    }
    res.json({ fields, files });
  });
});

app.listen(3000, () => console.log('Server started on port 3000'));

Streaming Files

Stream uploaded files:

const fs = require('fs');

form.onPart = (part) => {
  if (part.filename) {
    // Stream to file
    const writeStream = fs.createWriteStream(`/tmp/${part.filename}`);
    part.pipe(writeStream);
  } else {
    // Handle non-file parts
    form.handlePart(part);
  }
};

Security Considerations

Implement security measures:

const form = formidable({
  uploadDir: '/tmp',
  maxFileSize: 50 * 1024 * 1024, // 50MB
  filter: function ({ name, originalFilename, mimetype }) {
    // Allow only specific file types
    const allowedTypes = ['image/jpeg', 'image/png', 'application/pdf'];
    return allowedTypes.includes(mimetype);
  }
});

Testing

Test file uploads using supertest:

const request = require('supertest');
const app = require('./app'); // Your Express app

describe('File Upload', () => {
  it('should upload a file', async () => {
    const response = await request(app)
      .post('/upload')
      .attach('file', 'test/fixtures/test-file.txt')
      .field('name', 'Test File');

    expect(response.status).toBe(200);
    expect(response.body.files.file).toBeDefined();
    expect(response.body.fields.name).toBe('Test File');
  });
});

2024 © All rights reserved - buraxta.com