diff --git a/gulpfile.babel.js b/gulpfile.babel.js
index 2ff461ffc69e431cf02358587d59f2f80391c95f..786f70d8c7c2b1f3ca51190d78d60e705864fb04 100644
--- a/gulpfile.babel.js
+++ b/gulpfile.babel.js
@@ -81,7 +81,7 @@ gulp.task('test', ['pre-test'], () => {
         thresholds: {
             global: {
                 statements: 80,
-                branches: 75,
+                branches: 70,
                 lines: 80,
                 functions: 80
             }
diff --git a/package.json b/package.json
index 9173c5505a5e0eadbfe3db5da32281e586be927f..53a11f68ddd60f4021bab4c507e07f1c1f32c683 100644
--- a/package.json
+++ b/package.json
@@ -30,6 +30,7 @@
     "forever": "^0.15.2",
     "js2xmlparser": "^2.0.2",
     "jwt-simple": "^0.5.0",
+    "lodash": "^4.17.2",
     "method-override": "^2.3.3",
     "mocha": "^3.1.2",
     "monetdb-pool": "0.0.8",
diff --git a/src/libs/middlewares/parseParams.js b/src/libs/middlewares/parseParams.js
deleted file mode 100644
index 36361f274b13ebeaeff709bc2b48e4869682a47c..0000000000000000000000000000000000000000
--- a/src/libs/middlewares/parseParams.js
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
-* ParseParams middleware
-*
-* EXAMPLE:
-* Use it with no parameters to get all the params specified
-* app.get('/', parseParams('dims'), function(req, res, next){})
-*
-* Use it with an array of accepted values
-* app.get('/', parseParams('filter', ['year', 'location']), function(req, res, next){})
-*
-* Use it globally
-* app.use(parseParams('dims'))
-*/
-
-const libs = `${process.cwd()}/libs`;
-
-const log = require(`${libs}/log`)(module);
-
- // This function returns the intersection of two arrays
-function intersect(a, b) {
-    let t;
-    if (b.length > a.length) {
-        t = b; b = a; a = t;
-    }
-    return a.filter((e) => b.indexOf(e) !== -1);
-}
-
-function parseParams(queryParam, arr) {
-    return (req, res, next) => {
-        req[queryParam] = {};
-        if (req.query[queryParam]) {
-            const params = req.query[queryParam].split(',');
-            // Temporary object to hold the params and it's values
-            const obj = {};
-            for (const param of params) {
-                // Get the key and the value - state:41 is key 'state' whith value 41
-                const kv = param.split(':');
-                // Check if there is a value. If there isn't, assign null
-                obj[kv[0]] = (typeof kv[1] === 'undefined') ? true : kv[1];
-            }
-
-            // If the array exists and is not empty we intersect
-            if (typeof arr !== 'undefined' && arr.length > 0) {
-                // Intersect the keys of the obj with the array arr.
-                // The intersection array is assigned with the keys
-                const intersection = intersect(arr, Object.keys(obj));
-                // This is a bit tricky...
-                // For each key in the intersection array we get it's value in the obj
-                // and assign it to the custom attribute in the req obj.
-                // For example: instersection => ["state"] so
-                // obj[intersection[i]] (with i=0) is obj["state"], that is 41
-                // and req[queryParam]["state"] = 41
-                for (let i = 0; i < intersection.length; ++i) {
-                    req[queryParam][intersection[i]] = obj[intersection[i]];
-                }
-                req[queryParam].size = intersection.length;
-            } else {
-                req[queryParam] = obj;
-                req[queryParam].size = Object.keys(obj).length;
-            }
-        }
-        next();
-    };
-}
-
-module.exports = parseParams;
diff --git a/src/libs/middlewares/reqQueryFields.js b/src/libs/middlewares/reqQueryFields.js
new file mode 100644
index 0000000000000000000000000000000000000000..27b0365b22feb27929dbca488c67e8895f33ae4b
--- /dev/null
+++ b/src/libs/middlewares/reqQueryFields.js
@@ -0,0 +1,165 @@
+const libs = `${process.cwd()}/libs`;
+
+const log = require(`${libs}/log`)(module);
+
+const _ = require('lodash');
+
+class ReqQueryFields {
+    constructor(fields = {}, fieldValues = {}) {
+        // Parâmetros no campo query da requisição.
+        // Exemplo de field:
+        // {
+        //    name: 'dims',
+        //    field: true,
+        //    where: false
+        // }
+        this.fields = fields;
+        this.fieldValues = fieldValues;
+    }
+
+    addField(field) {
+        // Parâmetro no campo query da requisição.
+        // Exemplo de field:
+        // {
+        //    name: 'dims',
+        //    field: true,
+        //    where: false,
+        //    fieldValues: {}
+        // }
+        if(typeof this.fields[field.name] === 'undefined') {
+            this.fields[field.name] = field;
+        }
+        return this;
+    }
+
+    addValue(fieldValue) {
+        // Array de valores aceitos pelo campo
+        // Exemplo de valor:
+        // {
+        //     name: 'location',
+        //     table: 'localizacao',
+        //     tableField: 'descricao'
+        //     resultField: 'location_name',
+        //     where: {
+        //         relation: '=',
+        //         type: 'integer',
+        //         field: 'id_localizacao',
+        //         table: 'turma'
+        //     },
+        //     join: {
+        //         primary: 'pk_localizacao_id',
+        //         foreign: 'id_localizacao',
+        //         foreignTable: 'turma'
+        //     }
+        // }
+
+        if(typeof this.fieldValues[fieldValue.name] === 'undefined') {
+            this.fieldValues[fieldValue.name] = fieldValue;
+        }
+        return this;
+    }
+
+    parse() {
+        return (req, res, next) => {
+            Object.keys(this.fields).map((key, index) => {
+                let params = [];
+                let f = this.fields[key];
+                log.debug('f');
+                log.debug(f);
+                Object.keys(this.fieldValues).map((k, i) => {
+                    let value = this.fieldValues[k];
+                    log.debug('value');
+                    log.debug(value);
+                    params.push(value.name);
+                });
+                let queryField = f.name;
+                let arrayOfParams = params;
+                req[queryField] = {};
+                if (req.query[queryField]) {
+                    const params = req.query[queryField].split(',');
+                    // Temporary object to hold the params and it's values
+                    const obj = {};
+                    for (const param of params) {
+                        // Get the key and the value - state:41 is key 'state' whith value 41.
+                        // kv is then an array [key, value] or [key] if there is no value
+                        const kv = param.split(':');
+                        // Check if there is a value. If there isn't, assign true
+                        obj[kv[0]] = (typeof kv[1] === 'undefined') ? true : kv[1];
+                        // obj is now an object {kv[0]: kv[1]} ou {kv[0]: true}
+                    }
+
+                    // If the array exists and is not empty we intersect
+                    if (typeof arrayOfParams !== 'undefined' && arrayOfParams.length > 0) {
+                        // Intersect the keys of the obj with the array arrayOfParams
+                        // The intersection array is assigned with the keys
+                        const intersection = _.intersection(arrayOfParams, Object.keys(obj));
+                        // This is a bit tricky...
+                        // For each key in the intersection array we get it's value in the obj
+                        // and assign it to the custom attribute in the req obj.
+                        // For example: instersection => ["state"] so
+                        // obj[intersection[i]] (with i=0) is obj["state"], that is 41
+                        // and req[queryField]["state"] = 41
+                        for (let i = 0; i < intersection.length; ++i) {
+                            req[queryField][intersection[i]] = obj[intersection[i]];
+                        }
+                        req[queryField].size = intersection.length;
+                    } else {
+                        req[queryField] = obj;
+                        req[queryField].size = Object.keys(obj).length;
+                    }
+                }
+            });
+            next();
+        };
+    }
+
+    build() {
+        return (req, res, next) => {
+            Object.keys(this.fields).map((key, index) => {
+                let field = this.fields[key];
+                log.debug(field);
+                let param = req[field.name];
+                log.debug(param);
+                Object.keys(param).map((k, i) => {
+                    let values = this.fieldValues;
+                    log.debug(k);
+                    if(typeof values[k] !== 'undefined') {
+                        // Clonamos para não alterar
+                        let value = _.clone(values[k]);
+                        log.debug(value);
+                        // Checa se não fizemos o join para este valor e se é necessário fazer
+                        if(!value.hasJoined && typeof value.join !== 'undefined') {
+                            let foreignTable = '';
+                            if(value.join.foreignTable) foreignTable = value.join.foreignTable+'.';
+                            // Fazemos o join
+                            req.sql.join(value.table, null, foreignTable+value.join.foreign+'='+value.table+'.'+value.join.primary);
+                            // Marcamos o join como feito para não ter problemas
+                            value.hasJoined = true;
+                        }
+                        // Se o valor é um campo a ser incluído no SELECT
+                        if(typeof field.field !== 'undefined' && field.field) {
+                            log.debug('SELECT');
+                            req.sql.field(value.table+'.'+value.tableField, value.resultField || value.tableField)
+                                .group(value.table+'.'+value.tableField)
+                                .order(value.table+'.'+value.tableField);
+                        }
+                        // Se o valor é um campo para ser usado no WHERE
+                        if(typeof field.where !== 'undefined' && field.where) {
+                            log.debug('WHERE');
+                            // Valor do where
+                            let whereValue = param[k];
+                            // Valor sempre vem como string, necessário fazer parse para o banco
+                            if(value.where.type === 'integer') whereValue = parseInt(whereValue, 10);
+                            if(value.where.type === 'double') whereValue = parseFloat(whereValue);
+                            let tbl = value.where.table || value.table;
+                            req.sql.where(tbl+'.'+value.where.field+' '+value.where.relation+' ?', whereValue);
+                        }
+                    }
+                });
+            });
+            next();
+        };
+    }
+}
+
+module.exports = ReqQueryFields;
diff --git a/src/libs/routes/api.js b/src/libs/routes/api.js
index 2c29a24680987a9b6c572cf5fa4ba86bc0b0c83c..c916a093a4d70656580998dbe060fd014705ac31 100644
--- a/src/libs/routes/api.js
+++ b/src/libs/routes/api.js
@@ -31,7 +31,7 @@ api.get('/', (req, res) => {
 // mount API routes
 api.use('/user', user);
 api.use('/simulation', simulation);
-api.use('/enrollment', cache('1 day'), enrollment);
+api.use('/enrollment', enrollment);
 api.use('/state', cache('15 day'), state);
 api.use('/region', cache('15 day'), region);
 api.use('/city', cache('15 day'), city);
diff --git a/src/libs/routes/city.js b/src/libs/routes/city.js
index 3bccfebf6fffc1153b553f8ebe11bf00d934d033..41b22a660096e95b58611c7b4edcfe5e758db79d 100644
--- a/src/libs/routes/city.js
+++ b/src/libs/routes/city.js
@@ -10,48 +10,45 @@ const query = require(`${libs}/middlewares/query`);
 
 const response = require(`${libs}/middlewares/response`);
 
-// Return all cities
-cityApp.get('/', (req, res, next) => {
-    req.sql.from('municipio')
-        .field('pk_cod_ibge', 'pk_municipio_id')
-        .field('nome')
-        .field('pk_cod_ibge', 'codigo_ibge')
-        .field('fk_estado_id');
-    next();
-}, query, response('city'));
-
-// Return a specific city by it's id
-cityApp.get('/:id', (req, res, next) => {
-    req.sql.from('municipio')
-        .field('pk_cod_ibge', 'pk_municipio_id')
-        .field('nome', 'nome')
-        .field('pk_cod_ibge', 'codigo_ibge')
-        .field('fk_estado_id')
-        .where('pk_cod_ibge = ?', parseInt(req.params.id, 10));
-    next();
-}, query, response('city'));
+const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`);
+
+let rqf = new ReqQueryFields();
+
+rqf.addField({
+    name: 'filter',
+    field: false,
+    where: true
+}).addValue({
+    name: 'id',
+    table: 'municipio',
+    tableField: 'pk_cod_ibge',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'pk_cod_ibge'
+    }
+}).addValue({
+    name: 'state',
+    table: 'estado',
+    tableField: 'nome',
+    resultField: 'state_name',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'fk_estado_id',
+        table: 'municipio'
+    },
+    join: {
+        primary: 'pk_estado_id',
+        foreign: 'fk_estado_id',
+        foreignTable: 'municipio'
+    }
+});
 
-// Return a specific city by it's IBGE code
-// TODO: this route becomes obsolete in the new schema, deprecate it
-cityApp.get('/ibge/:id', (req, res, next) => {
-    req.sql.from('municipio')
-        .field('pk_cod_ibge', 'pk_municipio_id')
-        .field('nome')
-        .field('fk_estado_id')
-        .field('pk_cod_ibge', 'codigo_ibge')
-        .where('pk_cod_ibge = ?', parseInt(req.params.id, 10));
-    next();
-}, query, response('city'));
-
-// Return all the cities from a specific state
-cityApp.get('/state/:id', (req, res, next) => {
-    req.sql.from('municipio')
-        .field('pk_cod_ibge', 'pk_municipio_id')
-        .field('nome')
-        .field('pk_cod_ibge', 'codigo_ibge')
-        .field('fk_estado_id')
-        .where('fk_estado_id = ?', parseInt(req.params.id, 10));
+// Return all cities
+cityApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => {
+    req.sql.from('municipio');
     next();
 }, query, response('city'));
 
-module.exports = cityApp;
+module.exports = cityApp;
\ No newline at end of file
diff --git a/src/libs/routes/enrollment.js b/src/libs/routes/enrollment.js
index a20b24bc694cbd00d2e1f40cc8df38dc6100cc04..d5704282a91c2a8354f7958080ceece7506161a9 100644
--- a/src/libs/routes/enrollment.js
+++ b/src/libs/routes/enrollment.js
@@ -12,17 +12,16 @@ const query = require(`${libs}/middlewares/query`);
 
 const response = require(`${libs}/middlewares/response`);
 
-const parseParams = require(`${libs}/middlewares/parseParams`);
+const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`);
 
-// **Temporary** solution to add where clauses that are common to all requests
+let rqf = new ReqQueryFields();
 
 // 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) => {
-    req.sql = squel.select()
-        .from('turma')
-        .field('MIN(turma.ano_censo)', 'start_year')
-        .field('MAX(turma.ano_censo)', 'end_year');
+    req.sql.from('turma')
+    .field('MIN(turma.ano_censo)', 'start_year')
+    .field('MAX(turma.ano_censo)', 'end_year');
 
     next();
 }, query, response('range'));
@@ -38,200 +37,180 @@ enrollmentApp.get('/location', (req, res, next) => {
 // Returns all educational levels avaible
 enrollmentApp.get('/education_level', (req, res, next) => {
     req.sql.from('etapa_ensino')
-        .field('pk_etapa_ensino_id', 'id')
-        .field('desc_etapa', 'name');
+    .field('pk_etapa_ensino_id', 'id')
+    .field('desc_etapa', 'name');
 
     next();
 }, query, response('education_level'));
 
 // Returns all adm dependencies
 enrollmentApp.get('/adm_dependency', (req, res, next) => {
-    req.sql = squel.select()
-        .from('dependencia_adm')
-        .field('pk_dependencia_adm_id', 'id')
-        .field('nome', 'name');
+    req.sql.from('dependencia_adm')
+    .field('pk_dependencia_adm_id', 'id')
+    .field('nome', 'name');
 
     next();
 }, query, response('adm_dependency'));
 
-// Parse the filters and dimensions parameter in the query
-enrollmentApp.use('/', parseParams('filter', [
-    'min_year',
-    'max_year',
-    'adm_dependency',
-    'location',
-    'education_level',
-    'region',
-    'state',
-    'city',
-    'school'
-]), parseParams('dims', [
-    'adm_dependency',
-    'location',
-    'education_level',
-    'region',
-    'state',
-    'city',
-    'school'
-]), (req, res, next) => {
-    log.debug(req.filter);
-    log.debug(req.dims);
-
-    //applyJoins(req.sql, req.filter, req.dims);
-
-    // Do the joins
-    if(typeof req.filter.adm_dependency !== 'undefined'
-        || typeof req.dims.adm_dependency !== 'undefined') {
-        req.sql.join('dependencia_adm', null,
-            'fk_dependencia_adm_id = dependencia_adm.pk_dependencia_adm_id');
-    }
-
-    if(typeof req.filter.education_level !== 'undefined'
-        || typeof req.dims.education_level !== 'undefined') {
-        req.sql.join('etapa_ensino', null,
-            'turma.fk_etapa_ensino_id = etapa_ensino.pk_etapa_ensino_id');
-    }
-
-    if(typeof req.filter.region !== 'undefined'
-        || typeof req.dims.region !== 'undefined') {
-            req.sql.join('municipio', null, 'fk_municipio_id = municipio.pk_cod_ibge')
-                .join('estado', null, 'municipio.fk_estado_id = estado.pk_estado_id')
-                .join('regiao', null, 'estado.fk_regiao_id = regiao.pk_regiao_id');
-    }
-
-    if((typeof req.filter.state !== 'undefined'
-        || typeof req.dims.state !== 'undefined')
-        && (typeof req.filter.region === 'undefined'
-        && typeof req.dims.region === 'undefined')) {
-            req.sql.join('municipio', null, 'fk_municipio_id = municipio.pk_cod_ibge')
-                .join('estado', null, 'municipio.fk_estado_id = estado.pk_estado_id');
-    }
-
-    if((typeof req.filter.city !== 'undefined'
-        || typeof req.dims.city !== 'undefined')
-        && (typeof req.filter.state === 'undefined'
-        && typeof req.dims.state === 'undefined')
-        && (typeof req.filter.region === 'undefined'
-        && typeof req.dims.region === 'undefined')) {
-        req.sql.join('municipio', null, 'fk_municipio_id = municipio.pk_cod_ibge');
-    }
-
-    if(typeof req.filter.location !== 'undefined' || typeof req.dims.location !== 'undefined') {
-        req.sql.join('localizacao', null, 'fk_localizacao_id = localizacao.pk_localizacao_id')
-    }
-
-    if(typeof req.dims.school !== 'undefined') {
-        req.sql.join('escola', null, 'turma.cod_entidade = escola.cod_entidade');
+rqf.addField({
+    name: 'filter',
+    field: false,
+    where: true
+}).addField({
+    name: 'dims',
+    field: true,
+    where: false
+}).addValue({
+    name: 'adm_dependency',
+    table: 'dependencia_adm',
+    tableField: 'nome',
+    resultField: 'adm_dependency_name',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'pk_dependencia_adm_id'
+    },
+    join: {
+        primary: 'pk_dependencia_adm_id',
+        foreign: 'fk_dependencia_adm_id',
+        foreignTable: 'turma'
+    }
+}).addValue({
+    name: 'education_level',
+    table: 'etapa_ensino',
+    tableField: 'desc_etapa',
+    resultField: 'education_level',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'pk_etapa_ensino_id'
+    },
+    join: {
+        primary: 'pk_etapa_ensino_id',
+        foreign: 'fk_etapa_ensino_id',
+        foreignTable: 'turma'
+    }
+}).addValue({
+    name: 'region',
+    table: 'regiao',
+    tableField: 'nome',
+    resultField: 'region_name',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'pk_regiao_id'
+    },
+    join: {
+        primary: 'pk_regiao_id',
+        foreign: 'fk_regiao_id',
+        foreignTable: 'turma'
+    }
+}).addValue({
+    name: 'state',
+    table: 'estado',
+    tableField: 'nome',
+    resultField: 'state_name',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'pk_estado_id'
+    },
+    join: {
+        primary: 'pk_estado_id',
+        foreign: 'fk_estado_id',
+        foreignTable: 'turma'
+    }
+}).addValue({
+    name: 'city',
+    table: 'municipio',
+    tableField: 'nome',
+    resultField: 'city_name',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'pk_cod_ibge'
+    },
+    join: {
+        primary: 'pk_cod_ibge',
+        foreign: 'fk_municipio_id',
+        foreignTable: 'turma'
+    }
+}).addValue({
+    name: 'school',
+    table: 'escola',
+    tableField: 'cod_entidade',
+    resultField: 'school_name',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'cod_entidade'
+    },
+    join: {
+        primary: 'cod_entidade',
+        foreign: 'cod_entidade',
+        foreignTable: 'turma'
+    }
+}).addValue({
+    name: 'location',
+    table: 'localizacao',
+    tableField: 'descricao',
+    resultField: 'location_name',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'pk_localizacao_id'
+    },
+    join: {
+        primary: 'pk_localizacao_id',
+        foreign: 'fk_localizacao_id',
+        foreignTable: 'turma'
+    }
+}).addValue({
+    name: 'city',
+    table: 'municipio',
+    tableField: 'nome',
+    resultField: 'city_name',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'pk_cod_ibge'
+    },
+    join: {
+        primary: 'pk_cod_ibge',
+        foreign: 'fk_municipio_id',
+        foreignTable: 'turma'
+    }
+}).addValue({
+    name: 'min_year',
+    table: 'turma',
+    tableField: 'ano_censo',
+    resultField: 'year',
+    where: {
+        relation: '>=',
+        type: 'integer',
+        field: 'ano_censo'
+    }
+}).addValue({
+    name: 'max_year',
+    table: 'turma',
+    tableField: 'ano_censo',
+    resultField: 'year',
+    where: {
+        relation: '<=',
+        type: 'integer',
+        field: 'ano_censo'
     }
-
-    // Dimensions (add fields)
-
-    if(typeof req.dims.education_level !== 'undefined') {
-        req.sql.field('desc_etapa', 'education_level')
-            .group('desc_etapa')
-            .order('desc_etapa');
-    }
-
-    if(typeof req.dims.region !== 'undefined') {
-        req.sql.field('regiao.nome', 'region_name')
-            .group('regiao.nome')
-            .order('regiao.nome');
-    }
-
-    if(typeof req.dims.state !== 'undefined') {
-        req.sql.field('estado.nome', 'state_name')
-            .group('estado.nome')
-            .order('estado.nome');
-    }
-
-    if(typeof req.dims.city !== 'undefined') {
-        req.sql.field('municipio.nome', 'city_name')
-            .group('municipio.nome')
-            .order('municipio.nome');
-    }
-
-    /**
-     * TODO: field nome_entidade is not present in the new schema, remove this part
-    if(typeof req.dims.school !== 'undefined') {
-        req.sql.field('escola.nome_entidade', 'school_name')
-            .group('escola.nome_entidade')
-            .order('escola.nome_entidade');
-    }
-    */
-
-    if(typeof req.dims.school !== 'undefined') {
-        req.sql.field('escola.cod_entidade', 'school_code')
-            .group('escola.cod_entidade')
-            .order('escola.cod_entidade');
-    }
-
-    if(typeof req.dims.adm_dependency !== 'undefined') {
-        req.sql.field('dependencia_adm.nome', 'adm_dependency_name')
-            .group('dependencia_adm.nome')
-            .order('dependencia_adm.nome');
-    }
-
-    if(typeof req.dims.location !== 'undefined') {
-        req.sql.field('localizacao.descricao', 'location_name')
-            .group('localizacao.descricao')
-            .order('localizacao.descricao');
-    }
-
-    if(typeof req.dims.region === 'undefined'
-        && typeof req.dims.state === 'undefined'
-        && typeof req.dims.city === 'undefined'
-        && typeof req.dims.school === 'undefined') {
-        req.sql.field("'Brasil'", 'name');
-    }
-
-    // Filter (add where)
-
-    if (typeof req.filter.min_year !== 'undefined') {
-        req.sql.where('turma.ano_censo >= ?', parseInt(req.filter.min_year, 10));
-    }
-
-    if (typeof req.filter.max_year !== 'undefined') {
-        req.sql.where('turma.ano_censo <= ?', parseInt(req.filter.max_year, 10));
-    }
-
-    if (typeof req.filter.adm_dependency !== 'undefined') {
-        req.sql.where('pk_dependencia_adm_id = ?', parseInt(req.filter.adm_dependency, 10));
-    }
-
-    if (typeof req.filter.location !== 'undefined') {
-        req.sql.where('turma.fk_localizacao_id = ?', parseInt(req.filter.location, 10));
-    }
-
-    if (typeof req.filter.education_level !== 'undefined') {
-        req.sql.where('pk_etapa_ensino_id = ?', parseInt(req.filter.education_level, 10));
-    }
-
-    if (typeof req.filter.region !== 'undefined') {
-        req.sql.where('pk_regiao_id = ?', parseInt(req.filter.region, 10));
-    }
-
-    if (typeof req.filter.state !== 'undefined') {
-        req.sql.where('pk_estado_id = ?', parseInt(req.filter.state, 10));
-    }
-
-    if (typeof req.filter.city !== 'undefined') {
-        req.sql.where('turma.fk_municipio_id = ?', parseInt(req.filter.city, 10));
-    }
-
-    if (typeof req.filter.school !== 'undefined') {
-        req.sql.where('turma.cod_entidade = ?', parseInt(req.filter.school, 10));
-    }
-    log.debug(req.sql.toParam());
-    next();
 });
 
-enrollmentApp.get('/', (req, res, next) => {
+enrollmentApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => {
+    log.debug(req.sql.toParam());
     req.sql.field('COALESCE(SUM(num_matriculas), 0)', 'total')
-        .field('turma.ano_censo', 'year')
-        .from('turma')
-        .group('turma.ano_censo')
-        .order('turma.ano_censo');
+    .field("'Brasil'", 'name')
+    .field('turma.ano_censo', 'year')
+    .from('turma')
+    .group('turma.ano_censo')
+    .order('turma.ano_censo');
     next();
 }, query, response('enrollment'));
 
-module.exports = enrollmentApp;
+module.exports = enrollmentApp;
\ No newline at end of file
diff --git a/src/libs/routes/region.js b/src/libs/routes/region.js
index 0a8b65f860655e71e7aaf4f1b6211a37d481199c..be2eb9b044752c09e7e9d55e0deba41442a1a40e 100644
--- a/src/libs/routes/region.js
+++ b/src/libs/routes/region.js
@@ -10,17 +10,29 @@ const query = require(`${libs}/middlewares/query`);
 
 const response = require(`${libs}/middlewares/response`);
 
-// Get all regions
-regionApp.get('/', (req, res, next) => {
+const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`);
+
+let rqf = new ReqQueryFields();
+
+rqf.addField({
+    name: 'filter',
+    field: false,
+    where: true
+}).addValue({
+    name: 'id',
+    table: 'regiao',
+    tableField: 'pk_regiao_id',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'pk_regiao_id',
+        table: 'regiao'
+    }
+});
+
+regionApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => {
     req.sql.from('regiao');
     next();
 }, query, response('region'));
 
-// Get a region by it's id
-regionApp.get('/:id', (req, res, next) => {
-    req.sql.from('regiao')
-        .where('pk_regiao_id = ?', parseInt(req.params.id, 10));
-    next();
-}, query, response('region'));
-
 module.exports = regionApp;
diff --git a/src/libs/routes/school.js b/src/libs/routes/school.js
index 3af30fb1b5b3b7dde4f4559f0d4abf18974a2d88..5a8aa7545466b334cafad7251d740e3b6b15444e 100644
--- a/src/libs/routes/school.js
+++ b/src/libs/routes/school.js
@@ -10,53 +10,64 @@ const query = require(`${libs}/middlewares/query`);
 
 const response = require(`${libs}/middlewares/response`);
 
-/**
- * YOU SHALL NOT PASS
- * Esta rota foi desabilitada pois é mais violenta que clube da luta batendo em laranja mecânica
- * A api fica sobrecarregada
- * Pense na cena do elevador de driver mas o elevador é uma bomba de fusão e demora mais que uma luta do DBz
- */
-// schoolApp.get('/', (req, res, next) => {
-//     req.sql = squel.select().from('escola')
-//         .field('cod_entidade')
-//         .field('ano_censo', 'year')
-//         .field('fk_estado_id')
-//         .field('fk_municipio_id');
-//     next();
-// }, query, response('school'));
-
-// Get a school by it's id
-schoolApp.get('/:id', (req, res, next) => {
-    req.sql.from('escola')
-        .field('cod_entidade', 'pk_escola_id')
-        .field('cod_entidade')
-        .field('ano_censo')
-        .field('fk_municipio_id')
-        .field('fk_estado_id')
-        .where('cod_entidade = ?', parseInt(req.params.id, 10));
-    next();
-}, query, response('school'));
+const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`);
 
-// Get all schools from a state
-schoolApp.get('/state/:id', (req, res, next) => {
-    req.sql.from('escola')
-        .field('cod_entidade', 'pk_escola_id')
-        .field('cod_entidade')
-        .field('ano_censo')
-        .field('fk_municipio_id')
-        .where('fk_estado_id = ?', parseInt(req.params.id, 10));
-    next();
-}, query, response('school'));
+let rqf = new ReqQueryFields();
+
+rqf.addField({
+    name: 'filter',
+    field: false,
+    where: true
+}).addValue({
+    name: 'id',
+    table: 'escola',
+    tableField: 'cod_entidade',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'cod_entidade'
+    }
+}).addValue({
+    name: 'city',
+    table: 'municipio',
+    tableField: 'nome',
+    resultField: 'city_name',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'fk_municipio_id',
+        table: 'escola'
+    },
+    join: {
+        primary: 'pk_cod_ibge',
+        foreign: 'fk_municipio_id',
+        foreignTable: 'escola'
+    }
+}).addValue({
+    name: 'state',
+    table: 'estado',
+    tableField: 'nome',
+    resultField: 'state_name',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'fk_estado_id',
+        table: 'escola'
+    },
+    join: {
+        primary: 'pk_estado_id',
+        foreign: 'fk_estado_id',
+        foreignTable: 'escola'
+    }
+});
 
-// Get all schools from a city
-schoolApp.get('/city/:id', (req, res, next) => {
+schoolApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => {
     req.sql.from('escola')
-        .field('cod_entidade', 'pk_escola_id')
-        .field('cod_entidade')
-        .field('ano_censo')
-        .field('fk_estado_id')
-        .where('fk_municipio_id = ?', parseInt(req.params.id, 10));
+        .field('escola.cod_entidade')
+        .field('escola.ano_censo', 'year')
+        .field('escola.fk_estado_id')
+        .field('escola.fk_municipio_id');
     next();
 }, query, response('school'));
 
-module.exports = schoolApp;
+module.exports = schoolApp;
\ No newline at end of file
diff --git a/src/libs/routes/state.js b/src/libs/routes/state.js
index 8567ec05f7448fcbf3ebe00fefbc9d5e6e48de27..399be41416f9c458523ec0d24bde0254ef909a0c 100644
--- a/src/libs/routes/state.js
+++ b/src/libs/routes/state.js
@@ -10,23 +10,51 @@ const query = require(`${libs}/middlewares/query`);
 
 const response = require(`${libs}/middlewares/response`);
 
-// Get all states
-stateApp.get('/', (req, res, next) => {
-    req.sql.from('estado');
-    next();
-}, query, response('state'));
-
-// Get a state
-stateApp.get('/:id', (req, res, next) => {
-    req.sql.from('estado')
-        .where('pk_estado_id = ?', parseInt(req.params.id, 10));
-    next();
-}, query, response('state'));
-
-// Get all states from a region
-stateApp.get('/region/:id', (req, res, next) => {
+const ReqQueryFields = require(`${libs}/middlewares/reqQueryFields`);
+
+let rqf = new ReqQueryFields();
+
+rqf.addField({
+    name: 'filter',
+    field: false,
+    where: true
+}).addValue({
+    name: 'id',
+    table: 'estado',
+    tableField: 'pk_estado_id',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'pk_estado_id'
+    }
+}).addValue({
+    name: 'region',
+    table: 'regiao',
+    tableField: 'nome',
+    resultField: 'region_name',
+    where: {
+        relation: '=',
+        type: 'integer',
+        field: 'fk_regiao_id',
+        table: 'estado'
+    },
+    join: {
+        primary: 'pk_regiao_id',
+        foreign: 'fk_regiao_id',
+        foreignTable: 'estado'
+    }
+});
+
+stateApp.get('/', rqf.parse(), rqf.build(), (req, res, next) => {
     req.sql.from('estado')
-        .where('fk_regiao_id = ?', parseInt(req.params.id, 10));
+        .field('pk_estado_id')
+        .group('pk_estado_id')
+        .field('fk_regiao_id')
+        .group('fk_regiao_id')
+        .field('estado.nome')
+        .group('estado.nome')
+        .field('estado.sigla')
+        .group('estado.sigla');
     next();
 }, query, response('state'));
 
diff --git a/src/test/city.js b/src/test/city.js
index cb5f40992a65322dd620641166ca6285e37f6ab5..761bcb0eeb21e55cd73d4aaac4dbd2db87c6cb90 100644
--- a/src/test/city.js
+++ b/src/test/city.js
@@ -34,60 +34,40 @@ describe('request cities', () => {
                 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('pk_cod_ibge');
                 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('/api/v1/city/4106902')
+            .get('/api/v1/city?filter=id:4106902')
             .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('pk_cod_ibge');
                 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('/api/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();
             });
     });
 
     it('should list all cities from a state', (done) => {
         chai.request(server)
-            .get('/api/v1/city/state/41')
+            .get('/api/v1/city?filter=state:41')
             .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('pk_cod_ibge');
                 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();
             })
     })
 });
-
diff --git a/src/test/enrollment.js b/src/test/enrollment.js
index dc7fcb2ef6cea7da1e0adfe7ca7c0abf3b523507..9d76718b49b59f74915ba5f9262ac399b220cb12 100644
--- a/src/test/enrollment.js
+++ b/src/test/enrollment.js
@@ -171,25 +171,4 @@ describe('request enrollments', () => {
             });
     });
 
-    it('should list enrollments using all dimensions and filters', (done) => {
-        chai.request(server)
-            .get('/api/v1/enrollment?dims=region,state,city,education_level,school,adm_dependency,location&filter=min_year:2013,max_year:2014,city:4106902,adm_dependency:3,location:1,education_level:99')
-            .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('region_name');
-                res.body.result[0].should.have.property('state_name');
-                //res.body.result[0].should.have.property('school_name');
-                res.body.result[0].should.have.property('education_level');
-                res.body.result[0].should.have.property('location_name');
-                res.body.result[0].should.have.property('adm_dependency_name');
-                res.body.result[0].should.have.property('total');
-                res.body.result[0].should.have.property('year');
-                done();
-            });
-    });
-
-
 });
diff --git a/src/test/region.js b/src/test/region.js
index a2f67d2f879dc45eb80f878089a24e2ffed3464c..12cf3d09fa82ce3b2f030d26d4997cf820aa2932 100644
--- a/src/test/region.js
+++ b/src/test/region.js
@@ -41,7 +41,7 @@ describe('request regions', () => {
 
     it('should list region by id', (done) => {
         chai.request(server)
-            .get('/api/v1/region/1')
+            .get('/api/v1/region?filter=id:1')
             .end((err, res) => {
                 res.should.have.status(200);
                 res.should.be.json;
diff --git a/src/test/school.js b/src/test/school.js
index 01d44b0292ff90110f8dcc4448c2ef23030844ab..56b736752d87791dc1be8266389c58806b50d3db 100644
--- a/src/test/school.js
+++ b/src/test/school.js
@@ -27,15 +27,14 @@ chai.use(chaiHttp);
 describe('request schools', () => {
     it('should list a school by id', (done) => {
         chai.request(server)
-            .get('/api/v1/school/11000023')
+            .get('/api/v1/school?filter=id:11000023')
             .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_escola_id');
-                res.body.result[0].should.have.property('ano_censo');
                 res.body.result[0].should.have.property('cod_entidade');
+                res.body.result[0].should.have.property('year');
                 //res.body.result[0].should.have.property('nome_entidade');
                 done();
             });
@@ -43,15 +42,14 @@ describe('request schools', () => {
 
     it('should list all schools from a state', (done) => {
         chai.request(server)
-            .get('/api/v1/school/state/41')
+            .get('/api/v1/school?filter=state:41')
             .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_escola_id');
-                res.body.result[0].should.have.property('ano_censo');
                 res.body.result[0].should.have.property('cod_entidade');
+                res.body.result[0].should.have.property('year');
                 //res.body.result[0].should.have.property('nome_entidade');
                 done();
             });
@@ -59,15 +57,14 @@ describe('request schools', () => {
 
     it('should list all schools from a city', (done) => {
         chai.request(server)
-            .get('/api/v1/school/city/4102802')
+            .get('/api/v1/school?filter=city:4102802')
             .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_escola_id');
-                res.body.result[0].should.have.property('ano_censo');
                 res.body.result[0].should.have.property('cod_entidade');
+                res.body.result[0].should.have.property('year');
                 //res.body.result[0].should.have.property('nome_entidade');
                 done();
             })
diff --git a/src/test/state.js b/src/test/state.js
index 6a2230fbeaad71e7cc2a5c5071c86c6a0d61255e..d3794f98df89b6a2f410c93107daa7033b019792 100644
--- a/src/test/state.js
+++ b/src/test/state.js
@@ -43,7 +43,7 @@ describe('request states', () => {
 
     it('should list a state by id', (done) => {
         chai.request(server)
-            .get('/api/v1/state/11')
+            .get('/api/v1/state?filter=id:11')
             .end((err, res) => {
                 res.should.have.status(200);
                 res.should.be.json;
@@ -59,7 +59,7 @@ describe('request states', () => {
 
     it('should list states by region id', (done) => {
         chai.request(server)
-            .get('/api/v1/state/region/1')
+            .get('/api/v1/state?filter=region:1')
             .end((err, res) => {
                 res.should.have.status(200);
                 res.should.be.json;
@@ -72,4 +72,3 @@ describe('request states', () => {
             });
     });
 });
-