javascript - crearea de modele în expressjs
Am o aplicație express care își obține datele de la un API extern
api.com/companies (GET, POST)
api.com/companies/id (GET, PUT)
Vreau să creez un model pentru a face codul mai ușor de întreținut, așa cum poți vedea, repet mult cod aici.
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});
});
Cum pot face asta?
Răspuns #1
În primul rând: http.get este asincron. Regulă generală: Când vezi un callback, te confrunți cu o funcție asincronă. Nu poți ști dacă http.get() și callback-ul său se vor finaliza atunci când închei cererea cu res.render. Aceasta înseamnă că res.render trebuie întotdeauna să aibă loc în cadrul callback-ului.
Folosesc sintaxa ES6 în acest exemplu.
// 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})
});
});
Referitor la întrebarea ta despre 'model'. Aș prefera să le numesc 'servicii', deoarece un model este o colecție de date. Un serviciu este o colecție de logică.
Pentru a crea un modul de servicii al companiei se poate face acest lucru:
// 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(/*...*/)
});
Răspunsul #2
Nu este nevoie să aveți mai multe rute în acest caz! Puteți folosi un parametru opțional folosind ?. Aruncați o privire la următorul exemplu:
router.get('/companies/:id?', function(req, res, next) {
var id = req.params.id;
http.get({
host: 'http://api.com',
path: '/companies/' + id ? id : ""
}, function(response) {
var body = '';
response.on('data', function(d) {
body += d;
});
});
res.render('companies', {data: body});
});
Bucata de cod de aici:
path: '/companies/' + id ? id : ""
Folosește o instrucțiune if inline, deci ceea ce spune este, dacă id != null, false sau undefined, adaugă id la șirul companies/ și altfel pur și simplu nu adaugă nimic.
Editează
În ceea ce privește clasele js, ai putea face ceva de genul acesta:
// Seperate into a different file and export it
class Companies {
constructor (id) {
this.id= id;
this.body = "";
// You can add more values for this particular object
// Or you can dynamically create them without declaring here
// e.g company.new_value = "value"
}
get (cb) {
http.get({
host: 'http://api.com',
path: '/companies/' + this.id ? this.id : ""
}, function(response) {
response.on('data',(d) => {
this.body += d;
cb (); // callback
});
});
}
post () {
// You can add more methods ... E.g a POST method.
}
put (cb) {
http.put({
host: 'http://api.com',
path: '/companies/' + this.id ? this.id : "",
... Other object values here ...
}, function(response) {
response.on('data',(d) => {
... do something here with the response ...
cb(); //callback
});
});
}
}
Clasa dvs. de router ar putea apoi să folosească această clasă astfel:
router.get('/companies/:id?', function(req, res, next) {
var id = req.params.id;
var company = new Companies(id);
company.get(() => {
// We now have the response from our http.get
// So lets access it now!
// Or run company.put(function () {...})
console.log (company.body);
res.render('companies', {data: company.body});
});
});
Am adăugat callback-uri aici pentru simplitate, dar recomand folosirea promisiunilor: https://developers.google.com/web/fundamentals/getting-started/primers/promises
