-
-
Notifications
You must be signed in to change notification settings - Fork 18
/
app.js
103 lines (84 loc) · 2.58 KB
/
app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
const app = require('express')();
const _ = require('lodash');
const Router = require('express').Router;
const adminLookup = require('pelias-wof-admin-lookup');
const fs = require('fs');
const path = require('path');
const morgan = require( 'morgan' );
const logger = require('pelias-logger').get('pip');
const through = require( 'through2' );
function isFiniteNumber(value) {
return !_.isEmpty(_.trim(value)) && _.isFinite(_.toNumber(value));
}
const validate = (req, res, next) => {
if (_.at(req.params, ['lat', 'lon']).every(isFiniteNumber)) {
// both lat and lon are non-blank finite numbers, so validation step passes
req.query.centroid = {
lat: _.toNumber(req.params.lat),
lon: _.toNumber(req.params.lon)
};
next();
} else {
res.status(400).send('Cannot parse input');
next('route'); // skip lookup middleware and output, still logs
}
};
// middleware that cleans up layers parameters, eg:
// 'layers=layer1,layer2' => ['layer1', 'layer2']
// 'layers= layer1 , , layer2 ' => ['layer1', 'layer2']
// 'layers= , , ' => undefined
// 'layers=' => undefined
// no layers parameter => undefined
const parseLayers = (req, res, next) => {
const layers = _.split(req.query.layers, ',').reduce((layers, layer) => {
// only add to the valid layers list if it's not reduceable to an empty string
if (!_.isEmpty(_.trim(layer))) {
layers.push(_.trim(layer));
}
return layers;
}, []);
// if there are no layers, remove the parameter
if (_.isEmpty(layers)) {
delete req.query.layers;
} else {
req.query.layers = layers;
}
next();
};
function lookup(pointInPoly) {
return (req, res, next) => {
pointInPoly.lookup(req.query.centroid, req.query.layers, (err, result) => {
req.query.resolved = result;
next();
});
};
}
const output = (req, res, next) => {
res.status(200).send(req.query.resolved);
next();
};
function log() {
morgan.token('url', (req, res) => {
// if there's a DNT header, just return '/' as the URL
if (['DNT', 'dnt', 'do_not_track'].some((header) => {
return req.headers.hasOwnProperty(header);
})) {
return '/[removed]/[removed]';
} else {
return req.originalUrl;
}
});
return morgan('combined', {
stream: through( function write( ln, _, next ){
logger.info( ln.toString().trim() );
next();
})
});
}
module.exports = () => {
const pointInPoly = adminLookup.localResolver();
const router = new Router();
router.get('/:lon/:lat', validate, parseLayers, lookup(pointInPoly), output);
app.use(log(), router);
return app;
};