Postman

How to upload file in node.JS, express and Multer with Typescript.

 

Hello, everyone!

In this post, we’ll look at how to upload files in a Node.js application using Express, Multer, and TypeScript. We’ll go through the prerequisites, setting up your Node.js app with TypeScript, adding controllers and routes, integrating Multer to handle file uploads, and finally, connecting it all to a template.

Note: The GitHub repository for this project, including all the code, will be provided below.

Let’s get started!


Prerequisites

For this tutorial, make sure you have the following set up:

  • Node.js in your environment. If you don’t have it installed, you can download it here.
  • VS Code as your IDE (or an IDE of your choice). You can download it here.

Note: Familiarity with Multer for handling file uploads and TypeScript for adding static types to JavaScript is recommended.

Setting Up the App

In this section, we’ll create the initial folder structure for our application and set up our project dependencies. We’ll be using npm to manage dependencies, but you can also use Yarn if you prefer.

  1. Create the project folderFirst, open your terminal, navigate to your desired directory, and run the following commands to create and enter the project folder:
    mkdir file-upload-app
    cd file-upload-app
    
  2. Initialize the projectNext, initialize the project with npm (or Yarn if that’s your preference). This will create a package.json file to manage dependencies for our project. To initialize with npm, run:
    npm init -y
    

    This command will create a package.json file with default settings, which we’ll modify as we add more dependencies.

  3. Install project dependenciesNow, let’s install the required dependencies: Express, Multer, and their corresponding types for TypeScript. Run the following command:
    npm install express multer
    npm install --save-dev @types/express @types/multer typescript ts-node
    

    This will install Express and Multer as regular dependencies, and the type definitions for Express, Multer, and TypeScript as dev dependencies.

Project Structure

To give you an overview of how the app will be structured, here’s what our folder layout will look like:

└── file-upload-app/
		│
		├── src/
		│   ├── index.ts
		│   ├── routes/
		│   │   └── fileRoute.ts
		│   └── controllers/
		│       └── fileController.ts
		│
		├── node_modules/
		├── package.json
		├── tsconfig.json
		└── package-lock.json

In this structure:

  • The src/ folder will contain all of our TypeScript code.
  • index.ts will be the entry point to our application.
  • The routes/ folder will store our route files, and the fileRoute.ts file will handle the routing for file uploads.
  • The controllers/ folder will contain our controller files, such as fileController.ts, where the logic for file handling will reside.

Setting Up TypeScript

Now, let’s set up TypeScript for the project. To do this, we need to configure the tsconfig.json file, which will define how TypeScript compiles our code.

  1. Create the tsconfig.json fileRun the following command to create the TypeScript configuration file:
    npx tsc --init
    
  2. Configure the tsconfig.jsonOpen the generated tsconfig.json file and update it to the following settings to properly handle the TypeScript compilation for this project:
    {
      "compilerOptions": {
        "target": "ES6",
        "module": "commonjs",
        "strict": true,
        "esModuleInterop": true,
        "skipLibCheck": true,
        "forceConsistentCasingInFileNames": true,
        "outDir": "./dist",
        "rootDir": "./src"
      },
      "include": ["src/**/*"],
      "exclude": ["node_modules"]
    }
    
    • "target": "ES6" ensures that the JavaScript output is compatible with modern environments.
    • "module": "commonjs" is the module system used by Node.js.
    • "outDir": "./dist" specifies the folder where compiled JavaScript files will be stored.
    • "rootDir": "./src" defines where the TypeScript source files are located.

Optional Bonus: Setting Up Nodemon

To make the development process easier, you can set up Nodemon to automatically restart the server whenever there are changes to the source files.

  1. Install Nodemon as a dev dependency:
    npm install --save-dev nodemon
    
  2. Update package.json scriptsAdd a script to the package.json file to run the app with Nodemon. Modify the "scripts" section as follows:
      "scripts": {
        "dev": "nodemon src/index.ts",
        "start": "ts-node src/index.ts"
      }
    
  3. Running the app with NodemonNow, you can run the app with:
    npm run dev
    

    This will start the app and automatically restart the server whenever you modify the TypeScript files.

     

GitHub console launching file upload app with Express, Multer, TypeScript Node.js
GitHub console upload app Express Multer TypeScript

Setting Up the Folder Structure and Files

In this part, we’re going to set up the folder structure and create the necessary files. We’ll configure the main index.ts file, set up routes in the fileRoute.ts file, and handle the upload logic in the fileController.ts file. Here’s how each file should look:


1. src/controllers/fileController.ts

This controller will handle the logic for file uploads. We’ll create a function uploadFile to manage file uploads.

import { Request, Response } from 'express';
import fs from 'fs';
import path from 'path';

export const uploadFile = (req: Request, res: Response): void => {
    if (!req.file) {
        res.status(400).send('No file uploaded.');
        return;
    }

    const filePath = path.join(__dirname, '../../', req.file.path);

    // Set headers for file streaming
    res.setHeader('Content-Type', req.file.mimetype);
    res.setHeader('Content-Disposition', `attachment; filename="${req.file.originalname}"`);

    // Stream the file to the response
    const fileStream = fs.createReadStream(filePath);
    fileStream.pipe(res);

    fileStream.on('error', (error) => {
        console.error('File streaming error:', error);
        res.status(500).send('Error streaming the file.');
    });
};

Explanation:

  • File Path: We use path.join(__dirname, '../../', req.file.path) to locate the uploaded file based on the dest specified in Multer.
  • Headers: We set Content-Type to the file’s MIME type and Content-Disposition to allow the client to download the file with its original name.
  • Streaming: We create a readable stream with fs.createReadStream and pipe it to the response.
  • Error Handling: An error listener is added to handle any issues during streaming.

    2. src/routes/fileRoute.ts

    This route file will define the endpoint for handling file uploads.

    import express from 'express';
    import multer from 'multer';
    import { uploadFile } from '../controllers/fileController';
    
    const router = express.Router();
    const upload = multer({ dest: 'uploads/' });
    
    router.post('/upload', upload.single('file'), uploadFile);
    
    export default router;
    

    In this file:

    • We use Multer to handle file uploads. The dest: 'uploads/' option specifies where uploaded files will be stored.
    • The upload.single('file') middleware is configured to handle a single file upload with the field name file.

    3. src/index.ts

    This is the main entry point for your app, where you’ll set up the Express server and include the routes.

    import express, { Application } from 'express';
    import fileRoute from './routes/fileRoute';
    
    const app: Application = express();
    const PORT = process.env.PORT || 3000;
    
    app.use(express.json());
    app.use('/api', fileRoute);
    
    app.listen(PORT, () => {
        console.log(`Server is running on <http://localhost>:${PORT}`);
    });
    

    Here:

    • We import and configure Express.
    • fileRoute is added to handle requests under the /api path.
    • The server listens on the specified PORT, with a default of 3000 if no environment variable is set.

    This setup provides a basic structure where:

    • fileController.ts handles the upload logic.
    • fileRoute.ts defines the route for file uploads.
    • index.ts sets up and runs the server.

Testing the App

To test the app at this stage, you can use Postman or other API testing tools like Insomnia or Hoppscotch.

  1. Clone the GitHub repositoryYou can find the complete project setup on GitHub: GitHub Repository.
    git clone https://github.com/dev-luckymhz/upload-file-node.js-typescript.git
    cd upload-file-node.js-typescript
    npm install
    npm run dev
    
  2. Testing with Postman (or alternative tools)
    • Open Postman or your preferred API testing tool.
    • Send a POST request to http://localhost:3000/api/upload with form data.
    • Add a file with the key file and choose any file to upload.

If the setup is correct, the app should respond with the file data, or return it as a stream if you configured it that way in the controller.

Postman, server testing, file upload testing
Postman file upload testing Express Multer server

 

Integrating EJS (Optional)

To add a template to your app using EJS, you need to configure Express to use EJS as the view engine and set up the appropriate folder for views. Here’s how you can do that:

  1. Install EJS:
    npm install ejs
    
  2. Update src/index.ts to include EJS:Here’s how you set EJS as the view engine in your index.ts file:
    import express, { Application } from 'express';
    import path from 'path';
    import fileRoute from './routes/fileRoute';
    
    const app: Application = express();
    const PORT = process.env.PORT || 3000;
    
    // Set EJS as the view engine
    app.set("view engine", "ejs");
    app.set('views', path.join(__dirname, '/views'));
    
    app.use(express.json());
    app.use('/api', fileRoute);
    
    // Serve the upload form
    app.get('/', (req, res) => {
        res.render('uploadForm');
    });
    
    app.listen(PORT, () => {
        console.log(`Server is running on <http://localhost>:${PORT}`);
    });
    

Updated Project Structure

Your updated project structure with the views folder for the EJS templates will look like this:

file-upload-app/
│
├── src/
│   ├── index.ts
│   ├── routes/
│   │   └── fileRoute.ts
│   ├── controllers/
│   │   └── fileController.ts
│   └── views/
│       └── uploadForm.ejs
│
├── node_modules/
├── package.json
├── tsconfig.json
└── package-lock.json


Creating the EJS Form

In the views folder, create a file called uploadForm.ejs with the following content. This will be a Bootstrap-style form for uploading files:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Upload File</title>
    <link href="<https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css>" rel="stylesheet">
</head>
<body>
    <div class="container mt-5">
        <div class="card">
            <div class="card-header">
                <h3>Upload a File</h3>
            </div>
            <div class="card-body">
                <form id="uploadForm" enctype="multipart/form-data">
                    <div class="mb-3">
                        <label for="file" class="form-label">Choose File</label>
                        <input type="file" class="form-control" id="file" name="file" required>
                    </div>
                    <button type="submit" class="btn btn-primary">Upload</button>
                </form>
            </div>
        </div>
    </div>

    <!-- Modal to display the uploaded file -->
    <div class="modal fade" id="fileModal" tabindex="-1" aria-labelledby="fileModalLabel" aria-hidden="true">
        <div class="modal-dialog modal-lg">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title" id="fileModalLabel">Uploaded File</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                </div>
                <div class="modal-body">
                    <iframe id="fileFrame" width="100%" height="400px"></iframe>
                </div>
            </div>
        </div>
    </div>

    <script src="<https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js>"></script>
    <script>
        document.getElementById('uploadForm').addEventListener('submit', async function(event) {
            event.preventDefault();

            const formData = new FormData();
            formData.append('file', document.getElementById('file').files[0]);

            const response = await fetch('/api/upload', {
                method: 'POST',
                body: formData
            });

            if (response.ok) {
                const fileBlob = await response.blob();
                const fileURL = URL.createObjectURL(fileBlob);

                // Show the uploaded file in the modal
                const fileFrame = document.getElementById('fileFrame');
                fileFrame.src = fileURL;
                const fileModal = new bootstrap.Modal(document.getElementById('fileModal'));
                fileModal.show();
            } else {
                alert('File upload failed!');
            }
        });
    </script>
</body>
</html>

Explanation:

  • Form: This is a simple file upload form using Bootstrap. It includes an input field for selecting a file and a submit button.
  • Modal: After a successful upload, a modal is shown containing an <iframe> where the uploaded file is streamed and displayed.
  • JavaScript: Handles form submission asynchronously using the Fetch API. Upon successful upload, the file is displayed inside the modal.
Postman request

How to generate excel file in node.JS express

Welcome, everyone!

In this post, we’ll explore how to generate Excel files in a Node.js application using Express and ExcelJS. We’ll cover everything from setting up your Node.js project, configuring ExcelJS, creating routes and controllers, and outputting data to an Excel file format that’s ready for download.

Note: The GitHub repository for this project, including all code examples, will be provided below.

Let’s dive in!


Prerequisites

If you’re new to setting up a Node.js project, this section is for you. However, if you’re already familiar with the basics, feel free to skip ahead.

For this tutorial, make sure you have the following set up:

  • Node.js installed in your environment. If not, you can download it here.
  • VS Code as your IDE (or another editor of your choice). You can download it here.

Setting Up the App

In this section, we’ll set up the initial project structure and install the necessary dependencies for generating Excel files in our Node.js application. We’ll use npm to manage dependencies, but you’re free to use Yarn if that’s your preference.

  1. Create the project folderOpen your terminal, navigate to the directory where you’d like to set up the project, and use the following commands to create and enter the project folder:
    mkdir excel-generator-app
    cd excel-generator-app
    
  2. Initialize the projectNext, initialize the project using npm (or Yarn if you prefer). This will create a package.json file to manage the dependencies for our app. To initialize with npm, use:
    npm init -y
    

    This will generate a package.json file with default settings, which can be customized as we add dependencies.

  3. Install project dependenciesNow, let’s install the necessary dependencies for this project. We’ll use Express for setting up our server and ExcelJS for generating Excel files. Run the following command:
    npm install express exceljs
    npm install --save-dev @types/express typescript ts-node
    

    This installs Express and ExcelJS as main dependencies and adds the necessary types for Express and TypeScript as dev dependencies.

Project Structure

To give you a clear view of how our application will be organized, here’s the folder layout we’ll use:

└── excel-generator-app/
		│
		├── src/
		│   ├── index.ts
		│   ├── routes/
		│   │   └── excelRoute.ts
		│   ├── controllers/
		│   │   └── excelController.ts
		│   ├── services/
		│   │   └── excelGenerationService.ts
		│   └── interfaces/
		│       └── productInterface.ts
		│
		├── node_modules/
		├── package.json
		├── tsconfig.json
		└── package-lock.json

In this structure:

  • The src/ folder will contain all TypeScript code for the application.
  • index.ts serves as the main entry point, where we’ll set up and run the Express server.
  • The routes/ folder will include route files, with excelRoute.ts handling routes for Excel file generation.
  • The controllers/ folder will store controller files, such as excelController.ts, which contain logic for generating and streaming Excel files.
  • The services/ folder will hold services like excelGenerationService.ts, responsible for generating Excel files using ExcelJS.
  • The interfaces/ folder under src/ will define TypeScript interfaces, including productInterface.ts, to structure data models used in the application.

Setting Up TypeScript

Now, let’s set up TypeScript for the project. To do this, we need to configure the tsconfig.json file, which will define how TypeScript compiles our code.

  1. Create the tsconfig.json fileRun the following command to create the TypeScript configuration file:
    npx tsc --init
    
  2. Configure the tsconfig.jsonOpen the generated tsconfig.json file and update it to the following settings to properly handle the TypeScript compilation for this project:
    {
      "compilerOptions": {
        "target": "ES6",
        "module": "commonjs",
        "strict": true,
        "esModuleInterop": true,
        "skipLibCheck": true,
        "forceConsistentCasingInFileNames": true,
        "outDir": "./dist",
        "rootDir": "./src"
      },
      "include": ["src/**/*"],
      "exclude": ["node_modules"]
    }
    
    • "target": "ES6" ensures that the JavaScript output is compatible with modern environments.
    • "module": "commonjs" is the module system used by Node.js.
    • "outDir": "./dist" specifies the folder where compiled JavaScript files will be stored.
    • "rootDir": "./src" defines where the TypeScript source files are located.

Optional Bonus: Setting Up Nodemon :

To make the development process easier, you can set up Nodemon to automatically restart the server whenever there are changes to the source files.

  1. Install Nodemon as a dev dependency:
    npm install --save-dev nodemon
    
  2. Update package.json scriptsAdd a script to the package.json file to run the app with Nodemon. Modify the "scripts" section as follows:
      "scripts": {
        "dev": "nodemon src/index.ts",
        "start": "ts-node src/index.ts"
      }
    
  3. Running the app with NodemonNow, you can run the app with:
    npm run dev
    

    This will start the app and automatically restart the server whenever you modify the TypeScript files.

     

GitBash console launching Node.js Express app with Nodemon for backend Excel file generation
Running a Node.js Express app with Nodemon in GitBash to enable backend file generation in JavaScript

Here’s the expanded setup for the folder structure and files with all the key components, including explanations for the service, controller, route, interface, and main entry point.


Setting Up the Folder Structure and Files for Excel Generation

In this part, we’ll create the folder structure, configure the main index.ts file, set up routes in excelRoute.ts, implement the Excel generation logic in excelController.ts, define a service in excelGenerationService.ts, and set up a TypeScript interface in productInterface.ts. Here’s an outline of each file and its purpose.

1. src/interfaces/productInterface.ts

The interface file defines the structure of the product data, specifying the types for each property in the Product interface. This makes it easy to enforce structure and provide type safety across our codebase.

export interface Product {
  id: number;
  name: string;
  price: number;
  quantity: number;
};

Explanation:

  • Type Definitions: Each field has a specific type, such as number, string, or boolean, which helps in preventing errors and ensures consistency when creating or modifying products in the application.

2. src/services/excelGenerationService.ts

This service handles the core logic for generating an Excel file from JSON data. It uses the exceljs library to create a workbook, add a worksheet, define headers and rows based on the JSON data, and then send the file as a downloadable response.

import { Response } from 'express';
import exceljs from 'exceljs';
import { Product } from '../interfaces/productInterface';

export default class ExcelGenerationService {
    static async generateExcelFile(jsonData: Product[], res: Response): Promise<void> {
        try {
            const workbook = new exceljs.Workbook();
            const worksheet = workbook.addWorksheet('Products');

            // Define headers based on JSON data keys
            const headers = Object.keys(jsonData[0]);
            worksheet.addRow(headers);

            // Populate rows with data
            jsonData.forEach(data => {
                const row: any[] = [];
                headers.forEach(header => {
                    row.push(data[header as keyof Product]);
                });
                worksheet.addRow(row);
            });

            // Set response headers for downloading
            res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
            res.setHeader('Content-Disposition', `attachment; filename=products-${Date.now()}.xlsx`);

            await workbook.xlsx.write(res);
            res.end();
        } catch (error) {
            console.error('Error generating Excel file:', error);
            throw new Error('Failed to generate Excel file');
        }
    }
};

Explanation:

  • Workbook and Worksheet: An Excel workbook is created with a worksheet titled “Products.”
  • Headers and Rows: Headers are derived from the JSON data’s keys, and each row is populated based on these keys.
  • Response Headers: Headers set the appropriate MIME type and prompt a file download with a unique filename.
  • File Streaming: The workbook is streamed directly to the response, making the Excel file available for download.

3. src/controllers/excelController.ts

This controller is responsible for handling the request to generate an Excel file by calling the service method and passing data from the request body.

import { Request, Response } from 'express';
import ExcelGenerationService from '../services/excelGenerationService';
import { Product } from '../interfaces/productInterface';

export default class ExcelController {
    static async generateExcelFile(req: Request, res: Response) {
        const jsonData: Product[] = req.body;

        try {
            await ExcelGenerationService.generateExcelFile(jsonData, res);
        } catch (error) {
            console.log('Error generating Excel:', error);
            res.status(500).json({ error: 'Failed to generate Excel file' });
        }
    }
};

Explanation:

  • Error Handling: If an error occurs during Excel file generation, it sends a 500 status with an error message.
  • Service Invocation: The controller calls generateExcelFile from the service to handle Excel file creation and download.

4. src/routes/excelRoute.ts

This route file defines the endpoint for generating Excel files, which links the controller’s method to the /generate-excel route.

import express from 'express';
import ExcelController from '../controllers/excelController';

const router = express.Router();
router.post('/generate-excel', ExcelController.generateExcelFile);

export default router;

Explanation:

  • Route Setup: A POST endpoint at /generate-excel is set up to handle requests for Excel file generation.

5. src/index.ts

This is the main entry point of the application, where the Express server is initialized and configured with middleware and routes.

import express, { Application } from 'express';
import excelRoute from './routes/excelRoute';

const app: Application = express();
const PORT = process.env.PORT || 3000;

app.use(express.json());
app.use('/api', excelRoute);

app.listen(PORT, () => {
    console.log(`Server is running on <http://localhost>:${PORT}`);
});

Explanation:

  • Express Setup: Basic Express setup with JSON middleware and integration of the Excel route.
  • Server Listening: The server listens on the specified PORT, defaulting to 3000 if no environment variable is set.

This setup provides a complete structure where:

  • productInterface.ts defines the structure of the product data.
  • excelGenerationService.ts contains the logic to generate the Excel file.
  • excelController.ts manages the request and calls the service to create the Excel file.
  • excelRoute.ts sets up a route for file generation.
  • index.ts initializes the server and applies routing.

This structure provides a clean separation of concerns, ensuring that each part of the application is easy to maintain, test, and expand.

Testing the App

To test the Excel generation feature, you can use Postman or other API testing tools like Insomnia or Hoppscotch.

  1. Clone the GitHub RepositoryStart by cloning the GitHub repository where the complete project is hosted:
    git clone <https://github.com/dev-luckymhz/node.js-express-excel-generator>
    cd node.js-express-excel-generator
    npm install
    npm run dev
    
    
  2. Testing with Postman (or an Alternative Tool)
    • Open Postman or your preferred API testing tool.
    • Set up a POST request to http://localhost:3000/api/generate-excel (adjust the port if necessary).
    • In the Body tab, select raw and set the format to JSON.
    • Use the following sample JSON data to test the Excel generation:
      [
        {
          "id": 1,
          "name": "Laptop",
          "price": 1200,
          "quantity": 5
        },
        {
          "id": 2,
          "name": "Smartphone",
          "price": 800,
          "quantity": 10
        },
        {
          "id": 3,
          "name": "Tablet",
          "price": 450,
          "quantity": 7
        },
        {
          "id": 4,
          "name": "Headphones",
          "price": 150,
          "quantity": 20
        },
        {
          "id": 5,
          "name": "Smartwatch",
          "price": 300,
          "quantity": 12
        }
      ]
      
  3. Send the Request
  • In the Send button on Postman, click the small dropdown arrow.
  • Choose Send and Download from the dropdown options.
  • Postman will automatically prompt you to save the Excel file upon receiving the response.
  • Select a location to save the file, which will contain your JSON data as an .xlsx file.

This test verifies that the Excel generation and download functionality works as expected. You should receive an .xlsx file named something like products-<timestamp>.xlsx, containing the structured product data.

 

Screenshot of Postman API request to generate Excel file using Node.js, Express, and JavaScript backend.
Postman request setup for generating an Excel file in a Node.js and Express backend application.