Skip to content
Snippets Groups Projects
Commit 12645f17 authored by Vytor Calixto's avatar Vytor Calixto :space_invader:
Browse files

Merge branch 'refactor_enrollments' into 'development'

Refactor enrollments route to include query building

Changes:
- Add error handling in the database query function. When a database error
occurs, it is logged in the server and a plain text response is returned to the
user.
- Implement building of SQL queries inside the API, which removes the
  need to have stored functions/procedures on the database, since the former
approach is not flexible or efficient to maintain/extend.
- Use route chaining to determine which function will build the query
  that needs to be executed. The last function is the one that actually
  sends the query to the database and send the response.

Future Work:
- Instead of returning a plain text response, return a HTTP 501 status,
  which is currently not possible. When one attempts to send such status
  the framework throws an error that the headers were already sent for
  the current request.
- Chaining based on the route might not be the best solution here.

See merge request !7
parents 55ff5eca 501b00e6
No related branches found
No related tags found
1 merge request!7Refactor enrollments route to include query building
Pipeline #
const libs = `${process.cwd()}/libs`;
const log = require(`${libs}/log`)(module);
const conn = require(`${libs}/db/monet`);
/**
* Promise that executes an SQL query with optional parameters
*
* Examples:
* Query with no parameters:
* execSqlQuery('SELECT * FROM people');
* Query with one parameter:
* execSqlQuery('SELECT name, age FROM people WHERE id = ?', [1]);
* Query with more than one parameter:
* execSqlQuery('SELECT name, age FROM people WHERE city = ? AND age > ?', ['São Paulo', 35]);
*
* @param {string} sqlQuery - SQL query to be executed by the Promise
* @param {array} sqlQueryParams - SQL query parameters
*/
function execSqlQuery(sqlQuery, sqlQueryParams = []) {
log.debug(`Executing SQL query '${sqlQuery}' with params '${sqlQueryParams}'`);
return new Promise((resolve, reject) => {
conn.prepare(sqlQuery, true).then(
(dbQuery) => {
dbQuery.exec(sqlQueryParams).then(
(dbResult) => {
log.debug(`Query result: ${dbResult.data}`);
log.debug(dbResult.data);
resolve(dbResult.data);
},
(dbError) => {
log.error(`SQL query execution error: ${dbError.message}`);
reject(new Error(dbError.message));
}
);
// release resources allocated for prepared statement
conn.release();
}
);
});
}
module.exports = execSqlQuery;
var winston = require('winston')
const config = require('./config');
winston.emitErrs = true
const winston = require('winston');
function logger(module) {
winston.emitErrs = true;
function getFilePath(module) {
// using filename in log statements
return module.filename.split('/').slice(-2).join('/');
}
return new winston.Logger({
transports : [
function logger(module) {
const log = new winston.Logger({
transports: [
new winston.transports.File({
name: 'info-log',
level: 'info',
filename: process.cwd() + '/logs/all.log',
filename: `${process.cwd()}/logs/all.log`,
handleException: true,
json: false,
maxSize: 5242880, //5mb
maxSize: 5242880, // 5MB
maxFiles: 2,
colorize: false
colorize: false,
}),
new winston.transports.Console({
name: 'debug-log',
level: 'debug',
label: getFilePath(module),
handleException: true,
json: true,
colorize: true
})
json: false,
colorize: true,
}),
],
exitOnError: false
})
}
function getFilePath (module ) {
//using filename in log statements
return module.filename.split('/').slice(-2).join('/')
exitOnError: false,
});
if (!config.get('debug')) {
log.remove('debug-log');
}
return log;
}
module.exports = logger
module.exports = logger;
......@@ -13,36 +13,40 @@
*/
function intersect(a, b) {
var t
if (b.length > a.length) t = b, b = a, a = t
return a.filter(function (e) {
if (b.indexOf(e) !== -1) return true
})
let t;
if (b.length > a.length) {
t = b; b = a; a = t;
}
return a.filter((e) => b.indexOf(e) !== -1);
}
function dimensions(dims) {
return function(req, res, next) {
req.dims = {}
if(req.query.dims) {
var params = req.query.dims.split(",")
var dimObj = {}
for(var i=0; i<params.length; ++i) {
var kv = params[i].split(":")
dimObj[kv[0]] = (typeof kv[1] === 'undefined') ? null : kv[1]
return (req, res, next) => {
req.dims = {};
if (req.query.dims) {
const params = req.query.dims.split(',');
const dimObj = {};
for (const param of params) {
const kv = param.split(':');
dimObj[kv[0]] = (typeof kv[1] === 'undefined') ? null : kv[1];
}
// for(let i=0; i<params.length; ++i) {
// let kv = params[i].split(':');
// dimObj[kv[0]] = (typeof kv[1] === 'undefined') ? null : kv[1];
// }
// If the dims array exists and is not empty
if(typeof dims !== 'undefined' && dims.length > 0) {
var intersection = intersect(dims, Object.keys(dimObj))
for(var i=0; i<intersection.length; ++i) {
req.dims[intersection[i]] = dimObj[intersection[i]]
if (typeof dims !== 'undefined' && dims.length > 0) {
const intersection = intersect(dims, Object.keys(dimObj));
for (let i = 0; i < intersection.length; ++i) {
req.dims[intersection[i]] = dimObj[intersection[i]];
}
} else {
req.dims = dimObj
req.dims = dimObj;
}
}
console.log(req.dims)
next()
}
next();
};
}
module.exports = dimensions
module.exports = dimensions;
const libs = `${process.cwd()}/libs`;
const log = require(`${libs}/log`)(module);
const execQuery = require(`${libs}/db/query_exec`);
function query(req, res, next) {
log.debug(req.query);
execQuery(req.query.text, req.query.values).then((result) => {
log.debug(result);
req.result = result;
next();
}, (error) => {
next(error);
});
}
module.exports = query;
const xml = require('js2xmlparser');
function response(req, res) {
if (req.query.format === 'csv') {
res.csv(req.result);
} else if (req.query.format === 'xml') {
res.send(xml('result', JSON.stringify({ city: req.result })));
} else {
res.json({ result: req.result });
}
}
module.exports = response;
const express = require('express');
const api = express();
const enrollment = require('./enrollment');
const state = require('./state');
const region = require('./region');
const city = require('./city');
api.get('/', (req, res) => {
res.json({ msg: 'SimCAQ API is running' });
});
// mount API routes
api.use('/v1/enrollment', enrollment);
api.use('/v1/state', state);
api.use('/v1/region', region);
api.use('/v1/city', city);
module.exports = api;
const express = require('express');
const cityApp = express();
const libs = `${process.cwd()}/libs`;
const squel = require('squel');
const query = require(`${libs}/middlewares/query`);
const response = require(`${libs}/middlewares/response`);
cityApp.get('/', (req, res, next) => {
req.query = squel.select().from('municipios').toParam();
next();
}, query, response);
cityApp.get('/:id', (req, res, next) => {
req.query = squel.select().from('municipios').where('pk_municipio_id = ?',
parseInt(req.params.id, 10)).toParam();
next();
}, query, response);
cityApp.get('/ibge/:id', (req, res, next) => {
req.query = squel.select().from('municipios').where('codigo_ibge = ?',
req.params.id).toParam();
next();
}, query, response);
cityApp.get('/state/:id', (req, res, next) => {
req.query = squel.select().from('municipios').where('fk_estado_id = ?',
parseInt(req.params.id, 10));
next();
}, query, response);
module.exports = cityApp;
const express = require('express');
const enrollmentApp = express();
const libs = `${process.cwd()}/libs`;
const log = require(`${libs}/log`)(module);
const dbQuery = require('../db/query_exec');
const response = require('../middlewares/response');
/**
* Complete range of the enrollments dataset
*
* Returns a tuple of start and ending years of the complete enrollments dataset.
*/
enrollmentApp.get('/year_range', (req, res, next) => {
const yearSql = 'SELECT MIN(t.ano_censo) AS start_year, MAX(t.ano_censo)'
+ 'AS end_year FROM turmas AS t';
dbQuery(yearSql).then((result) => {
const record = result['0'];
log.debug(record);
req.result = { start_year: record.start_year, end_year: record.end_year };
return response(req, res);
}, (error) => {
log.error(`[${req.originalUrl}] SQL query error: ${error}`);
next('Internal error, request could not be satisfied at this moment. Please, '
+ 'try again later');
});
});
enrollmentApp.get('/education_level', (req, res, next) => {
const edLevelSql = 'SELECT pk_etapa_ensino_id AS id, desc_etapa AS '
+ 'education_level FROM etapa_ensino';
dbQuery(edLevelSql).then((result) => {
req.result = result;
return response(req, res);
}, (error) => {
log.error(`[${req.originalUrl}] SQL query error: ${error}`);
next('Internal error, request could not be satisfied at this moment. Please, '
+ 'try again later');
});
});
enrollmentApp.get('/data', (req, res, next) => {
const schoolClassSql = 'SELECT * FROM turmas';
dbQuery(schoolClassSql).then((result) => {
req.result = result;
return response(req, res);
}, (error) => {
log.error(`[${req.originalUrl}] SQL query error: ${error}`);
next('Internal error, request could not be satisfied at this moment. Please, '
+ 'try again later');
});
});
enrollmentApp.use('/', (req, res, next) => {
const params = req.query;
req.paramCnt = 0;
if (typeof params.id !== 'undefined') {
req.id = parseInt(params.id, 10);
req.paramCnt += 1;
}
if (typeof params.location_id !== 'undefined') {
req.location_id = parseInt(params.location_id, 10);
req.paramCnt += 1;
}
if (typeof params.adm_dependency_id !== 'undefined') {
req.adm_dependency_id = parseInt(params.adm_dependency_id, 10);
req.paramCnt += 1;
}
if (typeof params.census_year !== 'undefined') {
req.census_year = parseInt(params.census_year, 10);
req.paramCnt += 1;
}
if (typeof params.education_level_id !== 'undefined') {
req.education_level_id = parseInt(params.education_level_id, 10);
req.paramCnt += 1;
}
next();
});
enrollmentApp.use('/', (req, res, next) => {
const params = req.query;
if (typeof params.aggregate !== 'undefined' && params.aggregate === 'region') {
log.debug('Using enrollments query for regions');
req.sqlQuery = 'SELECT r.nome AS name, COALESCE(SUM(t.num_matriculas), 0) AS total '
+ 'FROM regioes AS r '
+ 'INNER JOIN estados AS e ON r.pk_regiao_id = e.fk_regiao_id '
+ 'INNER JOIN municipios AS m ON e.pk_estado_id = m.fk_estado_id '
+ 'LEFT OUTER JOIN turmas AS t ON ( '
+ 'm.pk_municipio_id = t.fk_municipio_id ';
req.sqlQueryParams = [];
if (typeof req.census_year !== 'undefined') {
req.sqlQuery += ' AND ';
req.sqlQuery += 't.ano_censo = ?';
req.sqlQueryParams.push(req.census_year);
}
if (typeof req.adm_dependency_id !== 'undefined') {
req.sqlQuery += ' AND ';
req.sqlQuery += 't.fk_dependencia_adm_id = ?';
req.sqlQueryParams.push(req.adm_dependency_id);
}
if (typeof req.location_id !== 'undefined') {
req.sqlQuery += ' AND ';
req.sqlQuery += 't.id_localizacao = ?';
req.sqlQueryParams.push(req.location_id);
}
if (typeof req.education_level_id !== 'undefined') {
req.sqlQuery += ' AND ';
req.sqlQuery += 't.fk_etapa_ensino_id = ?';
req.sqlQueryParams.push(req.education_level_id);
}
req.sqlQuery += ')';
if (typeof req.id !== 'undefined') {
req.sqlQuery += ' WHERE ';
req.sqlQuery += 'r.pk_regiao_id = ?';
req.sqlQueryParams.push(req.id);
}
req.sqlQuery += ' GROUP BY r.nome';
}
next();
});
enrollmentApp.use('/', (req, res, next) => {
const params = req.query;
if (typeof params.aggregate !== 'undefined' && params.aggregate === 'state') {
log.debug('Using enrollments query for states');
req.sqlQuery = 'SELECT e.nome AS name, COALESCE(SUM(t.num_matriculas), 0) as total '
+ 'FROM estados AS e '
+ 'INNER JOIN municipios AS m ON m.fk_estado_id = e.pk_estado_id '
+ 'LEFT OUTER JOIN turmas AS t ON ('
+ 'm.pk_municipio_id = t.fk_municipio_id ';
req.sqlQueryParams = [];
if (typeof req.census_year !== 'undefined') {
req.sqlQuery += ' AND ';
req.sqlQuery += 't.ano_censo = ?';
req.sqlQueryParams.push(req.census_year);
}
if (typeof req.adm_dependency_id !== 'undefined') {
req.sqlQuery += ' AND ';
req.sqlQuery += 't.fk_dependencia_adm_id = ?';
req.sqlQueryParams.push(req.adm_dependency_id);
}
if (typeof req.location_id !== 'undefined') {
req.sqlQuery += ' AND ';
req.sqlQuery += 't.id_localizacao = ?';
req.sqlQueryParams.push(req.location_id);
}
if (typeof req.education_level_id !== 'undefined') {
req.sqlQuery += ' AND ';
req.sqlQuery += 't.fk_etapa_ensino_id = ?';
req.sqlQueryParams.push(req.education_level_id);
}
req.sqlQuery += ')';
if (typeof req.id !== 'undefined') {
req.sqlQuery += ' WHERE ';
req.sqlQuery += 'e.pk_estado_id = ?';
req.sqlQueryParams.push(req.id);
}
req.sqlQuery += ' GROUP BY e.nome';
}
next();
});
enrollmentApp.use('/', (req, res, next) => {
const params = req.query;
if (typeof params.aggregate !== 'undefined' && params.aggregate === 'city') {
log.debug('Using enrollments query for cities');
req.sqlQuery = 'SELECT m.nome AS name, COALESCE(SUM(t.num_matriculas), 0) as total '
+ 'FROM municipios AS m '
+ 'LEFT OUTER JOIN turmas AS t ON ( '
+ 'm.pk_municipio_id = t.fk_municipio_id';
req.sqlQueryParams = [];
if (typeof req.census_year !== 'undefined') {
req.sqlQuery += ' AND ';
req.sqlQuery += 't.ano_censo = ?';
req.sqlQueryParams.push(req.census_year);
}
if (typeof req.adm_dependency_id !== 'undefined') {
req.sqlQuery += ' AND ';
req.sqlQuery += 't.fk_dependencia_adm_id = ?';
req.sqlQueryParams.push(req.adm_dependency_id);
}
if (typeof req.location_id !== 'undefined') {
req.sqlQuery += ' AND ';
req.sqlQuery += 't.id_localizacao = ?';
req.sqlQueryParams.push(req.location_id);
}
if (typeof req.education_level_id !== 'undefined') {
req.sqlQuery += ' AND ';
req.sqlQuery += 't.fk_etapa_ensino_id = ?';
req.sqlQueryParams.push(req.education_level_id);
}
req.sqlQuery += ')';
if (typeof req.id !== 'undefined') {
req.sqlQuery += ' WHERE ';
req.sqlQuery += 'm.pk_municipio_id = ?';
req.sqlQueryParams.push(req.id);
}
req.sqlQuery += 'GROUP BY m.nome';
}
next();
});
enrollmentApp.use('/', (req, res, next) => {
const params = req.query;
if (typeof params.aggregate === 'undefined') {
log.debug('Using enrollments query for the whole country');
req.sqlQuery = 'SELECT \'Brasil\' AS name, COALESCE(SUM(t.num_matriculas),0) AS total '
+ 'FROM turmas AS t';
req.sqlQueryParams = [];
if (req.paramCnt > 0) {
req.sqlQuery += ' WHERE ';
}
if (typeof req.census_year !== 'undefined') {
req.sqlQuery += 't.ano_censo = ?';
req.sqlQueryParams.push(req.census_year);
}
if (typeof req.adm_dependency_id !== 'undefined') {
if (req.sqlQueryParams.length > 0) {
req.sqlQuery += ' AND ';
}
req.sqlQuery += 't.fk_dependencia_adm_id = ?';
req.sqlQueryParams.push(req.adm_dependency_id);
}
if (typeof req.location_id !== 'undefined') {
if (req.sqlQueryParams.length > 0) {
req.sqlQuery += ' AND ';
}
req.sqlQuery += 't.id_localizacao = ?';
req.sqlQueryParams.push(req.location_id);
}
if (typeof req.education_level_id !== 'undefined') {
if (req.sqlQueryParams.length > 0) {
req.sqlQuery += ' AND ';
}
req.sqlQuery += 't.fk_etapa_ensino_id = ?';
req.sqlQueryParams.push(req.education_level_id);
}
}
next();
});
enrollmentApp.get('/', (req, res, next) => {
log.debug(`Request parameters: ${req}`);
if (typeof req.sqlQuery === 'undefined') {
// Should only happen if there is a bug in the chaining of the
// '/enrollments' route, since when no +aggregate+ parameter is given,
// it defaults to use the query for the whole country.
log.error('BUG -- No SQL query was found to be executed!');
next('Internal error, request could not be satisfied at this moment. Please, '
+ 'try again later');
} else {
log.debug('SQL query: ${ req.sqlQuery }?');
log.debug(req.sqlQuery);
dbQuery(req.sqlQuery).then((result) => {
req.result = result;
return response(req, res);
}, (error) => {
log.error(`[${req.originalUrl}] SQL query error: ${error}`);
next('Internal error, request could not be satisfied at this moment. Please, '
+ 'try again later');
});
}
});
module.exports = enrollmentApp;
const express = require('express');
const regionApp = express();
const libs = `${process.cwd()}/libs`;
const squel = require('squel');
const query = require(`${libs}/middlewares/query`);
const response = require(`${libs}/middlewares/response`);
regionApp.get('/', (req, res, next) => {
req.query = squel.select().from('regioes').toParam();
next();
}, query, response);
regionApp.get('/:id', (req, res, next) => {
req.query = squel.select().from('regioes').where('pk_regiao_id = ?',
parseInt(req.params.id, 10)).toParam();
next();
}, query, response);
module.exports = regionApp;
const express = require('express');
const stateApp = express();
const libs = `${process.cwd()}/libs`;
const squel = require('squel');
const query = require(`${libs}/middlewares/query`);
const response = require(`${libs}/middlewares/response`);
stateApp.get('/', (req, res, next) => {
req.query = squel.select().from('estados').toParam();
next();
}, query, response);
stateApp.get('/:id', (req, res, next) => {
req.query = squel.select().from('estados').where('pk_estado_id = ?',
parseInt(req.params.id, 10)).toParam();
next();
}, query, response);
stateApp.get('/region/:id', (req, res, next) => {
req.query = squel.select().from('estados').where('fk_regiao_id = ?',
parseInt(req.params.id, 10)).toParam();
next();
}, query, response);
module.exports = stateApp;
const debug = require('debug')('node-express-base');
const libs = `${process.cwd()}/libs`;
const config = require(`${libs}/config`);
const log = require(`${libs}/log`)(module);
const app = require(`${libs}/app`);
app.set('port', config.get('port') || 3000);
const server = app.listen(app.get('port'), () => {
debug(`Express server listening on port ${server.address().port}`);
log.info(`Express server listening on port ${config.get('port')}`);
});
const chai = require('chai');
const dirtyChai = require('dirty-chai');
chai.use(dirtyChai);
const chaiHttp = require('chai-http');
const assert = chai.assert;
const expect = chai.expect;
const should = chai.should(); // actually call the function
const server = require('../libs/app');
chai.use(chaiHttp);
describe('request enrollments', () => {
it('should list enrollments', (done) => {
chai.request(server)
.get('/v1/enrollment')
.end((err, res) => {
res.should.have.status(200);
res.should.be.json;
res.body.should.have.property('result');
res.body.result.should.be.a('array');
res.body.result[0].should.have.property('name');
res.body.result[0].should.have.property('total');
done();
});
});
});
describe('request regions', () => {
it('should list all regions', (done) => {
chai.request(server)
.get('/v1/region')
.end((err, res) => {
res.should.have.status(200);
res.should.be.json;
res.body.should.have.property('result');
res.body.result.should.be.a('array');
res.body.result[0].should.have.property('pk_regiao_id');
res.body.result[0].should.have.property('nome');
done();
});
});
it('should list region by id', (done) => {
chai.request(server)
.get('/v1/region/1')
.end((err, res) => {
res.should.have.status(200);
res.should.be.json;
res.body.should.have.property('result');
res.body.result.should.be.a('array');
res.body.result.should.have.length(1);
res.body.result[0].should.have.property('pk_regiao_id');
res.body.result[0].should.have.property('nome');
done();
});
});
});
describe('request states', () => {
it('should list all states', (done) => {
chai.request(server)
.get('/v1/state')
.end((err, res) => {
res.should.have.status(200);
res.should.be.json;
res.body.should.have.property('result');
res.body.result.should.be.a('array');
res.body.result[0].should.have.property('pk_estado_id');
res.body.result[0].should.have.property('fk_regiao_id');
res.body.result[0].should.have.property('nome');
done();
});
});
it('should list a state by id', (done) => {
chai.request(server)
.get('/v1/state/11')
.end((err, res) => {
res.should.have.status(200);
res.should.be.json;
res.body.should.have.property('result');
res.body.result.should.be.a('array');
res.body.result.should.have.length(1);
res.body.result[0].should.have.property('pk_estado_id');
res.body.result[0].should.have.property('fk_regiao_id');
res.body.result[0].should.have.property('nome');
done();
});
});
it('should list states by region id', (done) => {
chai.request(server)
.get('/v1/state/region/1')
.end((err, res) => {
res.should.have.status(200);
res.should.be.json;
res.body.should.have.property('result');
res.body.result.should.be.a('array');
res.body.result[0].should.have.property('pk_estado_id');
res.body.result[0].should.have.property('fk_regiao_id');
res.body.result[0].should.have.property('nome');
done();
});
});
});
describe('request cities', () => {
it('should list all cities', (done) => {
chai.request(server)
.get('/v1/city')
.end((err, res) => {
res.should.have.status(200);
res.should.be.json;
res.body.should.have.property('result');
res.body.result.should.be.a('array');
res.body.result[0].should.have.property('pk_municipio_id');
res.body.result[0].should.have.property('fk_estado_id');
res.body.result[0].should.have.property('nome');
res.body.result[0].should.have.property('codigo_ibge');
done();
});
});
it('should list a city by id', (done) => {
chai.request(server)
.get('/v1/city/1')
.end((err, res) => {
res.should.have.status(200);
res.should.be.json;
res.body.should.have.property('result');
res.body.result.should.be.a('array');
res.body.result[0].should.have.property('pk_municipio_id');
res.body.result[0].should.have.property('fk_estado_id');
res.body.result[0].should.have.property('nome');
res.body.result[0].should.have.property('codigo_ibge');
done();
});
});
it('should list a city by codigo_ibge', (done) => {
chai.request(server)
.get('/v1/city/ibge/1200013')
.end((err, res) => {
res.should.have.status(200);
res.should.be.json;
res.body.should.have.property('result');
res.body.result.should.be.a('array');
res.body.result[0].should.have.property('pk_municipio_id');
res.body.result[0].should.have.property('fk_estado_id');
res.body.result[0].should.have.property('nome');
res.body.result[0].should.have.property('codigo_ibge');
done();
});
});
});
var chai = require('chai');
var chaiHttp = require('chai-http');
var assert = chai.assert;
var expect = chai.expect;
var should = chai.should(); //actually call the function
var server = require('../libs/app');
chai.use(chaiHttp);
describe('request enrollments', function(){
it('should list enrollments', function(done){
chai.request(server)
.get('/api/v1/enrollments')
.end(function(err, res){
res.should.have.status(200);
res.should.be.json;
res.body.should.have.property('result');
res.body.result.should.be.a('array');
res.body.result[0].should.have.property('name');
res.body.result[0].should.have.property('total');
done();
})
});
});
describe('request regions', function(){
it('should list all regions', function(done){
chai.request(server)
.get('/api/v1/regions')
.end(function(err, res){
res.should.have.status(200);
res.should.be.json;
res.body.should.have.property('result');
res.body.result.should.be.a('array');
res.body.result[0].should.have.property('pk_regiao_id');
res.body.result[0].should.have.property('nome');
done();
})
});
it('should list region by id', function(done){
chai.request(server)
.get('/api/v1/regions/1')
.end(function(err, res){
res.should.have.status(200);
res.should.be.json;
res.body.should.have.property('result');
res.body.result.should.be.a('array');
res.body.result.should.have.length(1);
res.body.result[0].should.have.property('pk_regiao_id');
res.body.result[0].should.have.property('nome');
done();
})
});
});
describe('request states', function(){
it('should list all states', function(done){
chai.request(server)
.get('/api/v1/states')
.end(function(err, res){
res.should.have.status(200);
res.should.be.json;
res.body.should.have.property('result');
res.body.result.should.be.a('array');
res.body.result[0].should.have.property('pk_estado_id');
res.body.result[0].should.have.property('fk_regiao_id');
res.body.result[0].should.have.property('nome');
done();
})
});
it('should list a state by id', function(done){
chai.request(server)
.get('/api/v1/states/11')
.end(function(err, res){
res.should.have.status(200);
res.should.be.json;
res.body.should.have.property('result');
res.body.result.should.be.a('array');
res.body.result.should.have.length(1);
res.body.result[0].should.have.property('pk_estado_id');
res.body.result[0].should.have.property('fk_regiao_id');
res.body.result[0].should.have.property('nome');
done();
})
});
it('should list states by region id', function(done){
chai.request(server)
.get('/api/v1/states/region/1')
.end(function(err, res){
res.should.have.status(200);
res.should.be.json;
res.body.should.have.property('result');
res.body.result.should.be.a('array');
res.body.result[0].should.have.property('pk_estado_id');
res.body.result[0].should.have.property('fk_regiao_id');
res.body.result[0].should.have.property('nome');
done();
})
});
});
describe('request cities', function(){
it('should list all cities', function(done){
chai.request(server)
.get('/api/v1/cities')
.end(function(err, res){
res.should.have.status(200);
res.should.be.json;
res.body.should.have.property('result');
res.body.result.should.be.a('array');
res.body.result[0].should.have.property('pk_municipio_id');
res.body.result[0].should.have.property('fk_estado_id');
res.body.result[0].should.have.property('nome');
res.body.result[0].should.have.property('codigo_ibge');
done();
})
});
it('should list a city by id', function(done){
chai.request(server)
.get('/api/v1/cities/1')
.end(function(err, res){
res.should.have.status(200);
res.should.be.json;
res.body.should.have.property('result');
res.body.result.should.be.a('array');
res.body.result[0].should.have.property('pk_municipio_id');
res.body.result[0].should.have.property('fk_estado_id');
res.body.result[0].should.have.property('nome');
res.body.result[0].should.have.property('codigo_ibge');
done();
})
});
});
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment