handsome handsome - 1 month ago 15
Javascript Question

create models in expressjs

node beginner here.
I have an express app that gets its data from an external API

api.com/companies (GET, POST)
api.com/companies/id (GET, PUT)


I want to create a model to make the code easier to maintain as you can see I´m repeating a lot of code here.

router.get('/companies', function(req, res, next) {

http.get({
host: 'http://api.com',
path: '/companies'
}, function(response) {
var body = '';
response.on('data', function(d) {
body += d;
});
});

res.render('companies', {data: body});
});

router.get('/companies/:id', function(req, res, next) {

http.get({
host: 'http://api.com',
path: '/companies/' + req.params.id
}, function(response) {
var body = '';
response.on('data', function(d) {
body += d;
});
});

res.render('company', {data: body});
});


how can I do that?

Answer

First of all: http.get is asynchronous. Rule of thumb: When you see a callback, you are dealing with an asynchronous function. You can not tell, if the http.get() and its callback will be completed when you terminate the request with res.render. This means that res.render always needs to happen within the callback.

I am using ES6 syntax in this example.

// request (https://github.com/request/request) is a module worthwhile installing. 
const request = require('request');
// Note the ? after id - this is a conditional parameter
router.get('/companies/:id?', (req, res, next) => {

    // Init some variables
    let url = ''; 
    let template = ''

    // Distinguish between the two types of requests we want to handle
    if(req.params.id) {
        url = 'http://api.com/companies/' + req.params.id;
        template = 'company';
     } else {
        url = 'http://api.com/companies';
        template = 'companies';
     }

    request.get(url, (err, response, body) => {

        // Terminate the request and pass the error on
        // it will be handled by express error hander then
        if(err) return next(err);
        // Maybe also check for response.statusCode === 200

        // Finally terminate the request
        res.render(template, {data: body})
    });

});

Regarding your 'model' question. I would rather call them 'services' as a model is some collection of data. A service is a collection of logic.

To create a company service module do something like that:

// File companyService.js
const request = require('request');

// This is just one of many ways to encapsulate logic in JavaScript (e.g. classes)
// Pass in a config that contains your service base URIs
module.exports = function companyService(config) {
    return {
        getCompanies: (cb) => {
            request.get(config.endpoints.company.many, (err, response, body) => {
                return cb(err, body);
            });
        },
        getCompany: (cb) => {
            request.get(config.endpoints.company.one, (err, response, body) => {
                return cb(err, body);
            });
        },
    }
};


// Use this module like
const config = require('./path/to/config');
const companyService = require('./companyService')(config);

// In a route
companyService.getCompanies((err, body) => {
    if(err) return next(err);

    res.render(/*...*/)
});