Generar datos de prueba con Faker.js en mi API con Node.js y Express

Para una prueba de concepto con la que estoy jugando estos días necesitaba una API con datos totalmente inventados, pero con unos campos muy concretos. Es por ello que me he apoyado en Faker.js, un módulo de Node.js que te genera datos de prueba para la mayor parte de las temáticas que puedes necesitar. En este artículo te comparto cómo me ha quedado la API, por si algún dia también necesitas una 🙂

Contoso API

En mi caso, quería que la API devolviera los siguientes recursos: Accounts, Invoices y Support cases. Para que tuviera sentido, los datos generados tenían que tener relación entre sí, por lo que las cuentas de las facturas tenían que ser las mismas que las que devolvía el endpoint Accounts. Parece mucho lío, pero en realidad con Faker.js es mucho más fácil de lo que piensas, sin perder mucho tiempo:

En primer lugar necesitas instalar la librería faker, en mi caso en mi proyecto de Express.js:

npm install @faker-js/faker --save-dev

Luego me he creado un módulo como el siguiente:

const { faker } = require('@faker-js/faker');
let ACCOUNTS = [], INVOICES = [], SUPPORT_CASES = [];
const init = () => {
    // First create the accounts
    for (let i = 0; i < 10; i++) {
        ACCOUNTS.push({
            id: i + 1,
            accountName: faker.company.name(),
            primaryContact: faker.person.fullName(),
            email: faker.internet.email()
        });
    }
    permittedStatus = ['Paid', 'Uninvoiced', 'Invoiced'];
    // Next the invoices using the accounts
    for (let i = 0; i < 10; i++) {
        INVOICES.push({
            id: i + 1,
            date: faker.date.past().toLocaleDateString('es-ES'),
            accountName: ACCOUNTS[i].accountName,
            contact: ACCOUNTS[i].email,
            price: parseFloat(faker.commerce.price()),
            status: permittedStatus[Math.floor(Math.random() * permittedStatus.length)]
        });
    }
    // Finally the support cases using the accounts
    for (let i = 0; i < 10; i++) {
        SUPPORT_CASES.push({
            id: i + 1,
            name: ACCOUNTS[i].primaryContact,
            address: faker.location.streetAddress(),
            phone: faker.phone.number(),
            email: ACCOUNTS[i].email,
            notes: faker.lorem.paragraph(),
        });
    }
};
module.exports = {
    init,
    ACCOUNTS,
    INVOICES,
    SUPPORT_CASES
};

Como puedes ver, en este archivo llamado util/data.js, lo que tengo es una función que genera todos los datos de prueba relacionados entre sí para que finalmente pueda exportarlos, a través de module.exports y que estén disponibles para el resto de archivos.

Por otro lado, en los controladores de cada uno de los recursos los utilizo de la siguiente manera:

const express = require('express');
const router = express.Router();
const { INVOICES } = require('../util/data');
router.get('/invoices', (req, res) => {
    /*#swagger.tags = ['Invoices']
    ##swagger.operationId = 'getInvoices'
    #swagger.description = 'Endpoint to return invoices'
    #swagger.responses[200] = {
        description: 'Invoices returned successfully',       
        schema: { $ref: '#/definitions/Invoices' }       
    }
    */
    console.log(INVOICES);
    res.json(INVOICES);
});
router.get('/invoices/:id', (req, res) => {
    /*#swagger.tags = ['Invoices']
    ##swagger.operationId = 'getInvoiceById'
    #swagger.parameters['id'] = {
        in: 'path',
        description: 'Invoice ID',
        required: true,
        type: 'integer'
    }
    #swagger.responses[200] = {
        description: 'Invoice returned successfully',
        schema: { $ref: '#/definitions/Invoice' }
    }
    #swagger.responses[404] = {
        description: 'Invoice not found'
    }
    */
    const invoice = INVOICES.find(invoice => invoice.id === parseInt(req.params.id));
    if (!invoice) return res.status(404).send('The invoice with the given ID was not found.');
    res.json(invoice);
});
router.post('/invoices', (req, res) => {
    /*#swagger.tags = ['Invoices']
    ##swagger.operationId = 'createInvoice'
    #swagger.parameters['newInvoice'] = {
        in: 'body',
        description: 'Invoice to be created',
        required: true,
        schema: { $ref: '#/definitions/Invoice' }
    }
    #swagger.responses[201] = {
        description: 'Invoice created successfully',
        schema: { $ref: '#/definitions/Invoice' }
    }
    */
    console.log(req.body);
    const invoice = {
        id: INVOICES.length + 1,
        date: req.body.date,
        accountName: req.body.accountName,
        contact: req.body.contact,
        price: req.body.price,
        status: req.body.status
    };
    INVOICES.push(invoice);
    res.status(201).json(invoice);
});
router.put('/invoices/:id', (req, res) => {
    /*#swagger.tags = ['Invoices']
    ##swagger.operationId = 'updateInvoice'
    #swagger.parameters['id'] = {
        in: 'path',
        description: 'Invoice ID',
        required: true,
        type: 'integer'
    }
    #swagger.parameters['updatedInvoice'] = {
        in: 'body',
        description: 'Invoice to be updated',
        required: true,
        schema: { $ref: '#/definitions/Invoice' }
    }
    #swagger.responses[200] = {
        description: 'Invoice updated successfully',
        schema: { $ref: '#/definitions/Invoice' }
    }
    #swagger.responses[404] = {
        description: 'Invoice not found'
    }
    */
    const invoice = INVOICES.find(invoice => invoice.id === parseInt(req.params.id));
    if (!invoice) return res.status(404).send('The invoice with the given ID was not found.');
    invoice.date = req.body.date;
    invoice.accountName = req.body.accountName;
    invoice.contact = req.body.contact;
    invoice.price = req.body.price;
    invoice.status = req.body.status;
    res.json(invoice);
});
router.delete('/invoices/:id', (req, res) => {
    /*#swagger.tags = ['Invoices']
    ##swagger.operationId = 'deleteInvoice'
    
    #swagger.parameters['id'] = {
        in: 'path',
        description: 'Invoice ID',
        required: true,
        type: 'integer'
    }
    #swagger.responses[200] = {
        description: 'Invoice deleted successfully'
    }
    #swagger.responses[404] = {
        description: 'Invoice not found'
    }
    */
    const invoice = INVOICES.find(invoice => invoice.id === parseInt(req.params.id));
    if (!invoice) return res.status(404).send('The invoice with the given ID was not found.');
    const index = INVOICES.indexOf(invoice);
    INVOICES.splice(index, 1);
    res.json(invoice);
});
module.exports = router;

El código del ejemplo lo tienes en mi GitHub.

¡Saludos!