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?
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 could do this:
// 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(/*...*/)
});