mirror of https://github.com/pelias/api.git
Harish Krishna
10 years ago
18 changed files with 461 additions and 127 deletions
@ -0,0 +1,65 @@ |
|||||||
|
function deg2rad(degrees) { |
||||||
|
return Math.PI*degrees/180; |
||||||
|
} |
||||||
|
|
||||||
|
function rad2deg(radians) { |
||||||
|
return 180.0*radians/Math.PI; |
||||||
|
} |
||||||
|
|
||||||
|
// Semi-axes of WGS-84 geoidal reference
|
||||||
|
var WGS84_a = 6378137.0; // Major semiaxis [m]
|
||||||
|
var WGS84_b = 6356752.3; // Minor semiaxis [m]
|
||||||
|
|
||||||
|
// Earth radius at a given latitude, according to the WGS-84 ellipsoid [m]
|
||||||
|
function WGS84EarthRadius(lat){ |
||||||
|
// http://en.wikipedia.org/wiki/Earth_radius
|
||||||
|
var An = WGS84_a*WGS84_a * Math.cos(lat); |
||||||
|
var Bn = WGS84_b*WGS84_b * Math.sin(lat); |
||||||
|
var Ad = WGS84_a * Math.cos(lat); |
||||||
|
var Bd = WGS84_b * Math.sin(lat); |
||||||
|
return Math.sqrt( (An*An + Bn*Bn)/(Ad*Ad + Bd*Bd) ); |
||||||
|
} |
||||||
|
|
||||||
|
// Bounding box surrounding the point at given coordinates,
|
||||||
|
// assuming local approximation of Earth surface as a sphere
|
||||||
|
// of radius given by WGS84
|
||||||
|
function boundingBox(latitudeInDegrees, longitudeInDegrees, halfSideInKm) { |
||||||
|
var lat = deg2rad(latitudeInDegrees); |
||||||
|
var lon = deg2rad(longitudeInDegrees); |
||||||
|
var halfSide = 1000000*halfSideInKm; |
||||||
|
|
||||||
|
// Radius of Earth at given latitude
|
||||||
|
var radius = WGS84EarthRadius(lat); |
||||||
|
// Radius of the parallel at given latitude
|
||||||
|
var pradius = radius*Math.cos(lat); |
||||||
|
|
||||||
|
var latMin = lat - halfSide/radius; |
||||||
|
var latMax = lat + halfSide/radius; |
||||||
|
var lonMin = lon - halfSide/pradius; |
||||||
|
var lonMax = lon + halfSide/pradius; |
||||||
|
|
||||||
|
return { |
||||||
|
'top_left': { |
||||||
|
'lat': rad2deg(latMin),
|
||||||
|
'lon': rad2deg(lonMin) |
||||||
|
}, |
||||||
|
'bottom_right': { |
||||||
|
'lat': rad2deg(latMax),
|
||||||
|
'lon': rad2deg(lonMax)
|
||||||
|
}
|
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// middleware
|
||||||
|
function middleware(req, res, next){ |
||||||
|
req.clean = req.clean || {}; |
||||||
|
// ideally, bbox should be part of the req (and not to be calculated)
|
||||||
|
// TBD
|
||||||
|
req.clean.bbox = boundingBox(req.query.lat, req.query.lon, 2000); |
||||||
|
next(); |
||||||
|
} |
||||||
|
|
||||||
|
// middleware
|
||||||
|
module.exports.middleware = middleware |
@ -0,0 +1,31 @@ |
|||||||
|
var logger = require('../src/logger'); |
||||||
|
|
||||||
|
// Build pelias search query
|
||||||
|
function generate( params ){ |
||||||
|
|
||||||
|
var cmd = { |
||||||
|
"query":{ |
||||||
|
"filtered" : { |
||||||
|
"query" : { |
||||||
|
"match_all" : {} |
||||||
|
}, |
||||||
|
"filter" : { |
||||||
|
"geo_distance" : { |
||||||
|
"distance" : "1km", |
||||||
|
"center_point" : { |
||||||
|
"lat": params.lat,
|
||||||
|
"lon": params.lon
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
"size": 1 |
||||||
|
}; |
||||||
|
|
||||||
|
// logger.log( 'cmd', JSON.stringify( cmd, null, 2 ) );
|
||||||
|
return cmd; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
module.exports = generate; |
@ -0,0 +1,26 @@ |
|||||||
|
// validate inputs, convert types and apply defaults
|
||||||
|
function sanitize( req ){ |
||||||
|
|
||||||
|
req.clean = req.clean || {}; |
||||||
|
var params= req.query; |
||||||
|
|
||||||
|
// ensure the input params are a valid object
|
||||||
|
if( Object.prototype.toString.call( params ) !== '[object Object]' ){ |
||||||
|
params = {}; |
||||||
|
} |
||||||
|
|
||||||
|
// input text
|
||||||
|
if('string' !== typeof params.input || !params.input.length){ |
||||||
|
return {
|
||||||
|
'error': true, |
||||||
|
'message': 'invalid param \'input\': text length, must be >0' |
||||||
|
}; |
||||||
|
} |
||||||
|
req.clean.input = params.input; |
||||||
|
|
||||||
|
return { 'error': false }; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
// export function
|
||||||
|
module.exports = sanitize; |
@ -0,0 +1,47 @@ |
|||||||
|
// validate inputs, convert types and apply defaults
|
||||||
|
function sanitize( req ){ |
||||||
|
|
||||||
|
var clean = req.clean || {}; |
||||||
|
var params= req.query; |
||||||
|
|
||||||
|
// ensure the input params are a valid object
|
||||||
|
if( Object.prototype.toString.call( params ) !== '[object Object]' ){ |
||||||
|
params = {}; |
||||||
|
} |
||||||
|
|
||||||
|
// lat
|
||||||
|
var lat = parseFloat( params.lat, 10 ); |
||||||
|
if( isNaN( lat ) || lat < 0 || lat > 90 ){ |
||||||
|
return { |
||||||
|
'error': true, |
||||||
|
'message': 'invalid param \'lat\': must be >0 and <90'
|
||||||
|
} |
||||||
|
} |
||||||
|
clean.lat = lat; |
||||||
|
|
||||||
|
// lon
|
||||||
|
var lon = parseFloat( params.lon, 10 ); |
||||||
|
if( isNaN( lon ) || lon < -180 || lon > 180 ){ |
||||||
|
return { |
||||||
|
'error': true, |
||||||
|
'message': 'invalid param \'lon\': must be >-180 and <180'
|
||||||
|
} |
||||||
|
} |
||||||
|
clean.lon = lon; |
||||||
|
|
||||||
|
// zoom level
|
||||||
|
var zoom = parseInt( params.zoom, 10 ); |
||||||
|
if( !isNaN( zoom ) ){ |
||||||
|
clean.zoom = Math.min( Math.max( zoom, 1 ), 18 ); // max
|
||||||
|
} else { |
||||||
|
clean.zoom = 10; // default
|
||||||
|
} |
||||||
|
|
||||||
|
req.clean = clean; |
||||||
|
|
||||||
|
return { 'error': false }; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
// export function
|
||||||
|
module.exports = sanitize; |
@ -0,0 +1,40 @@ |
|||||||
|
var indeces = require('../query/indeces'); |
||||||
|
|
||||||
|
// validate inputs, convert types and apply defaults
|
||||||
|
function sanitize( req ){ |
||||||
|
|
||||||
|
var clean = req.clean || {}; |
||||||
|
var params= req.query; |
||||||
|
|
||||||
|
// ensure the input params are a valid object
|
||||||
|
if( Object.prototype.toString.call( params ) !== '[object Object]' ){ |
||||||
|
params = {}; |
||||||
|
} |
||||||
|
|
||||||
|
// which layers to query
|
||||||
|
if('string' === typeof params.layers && params.layers.length){ |
||||||
|
var layers = params.layers.split(',').map( function( layer ){ |
||||||
|
return layer.toLowerCase(); // lowercase inputs
|
||||||
|
}); |
||||||
|
for( var x=0; x<layers.length; x++ ){ |
||||||
|
if( -1 === indeces.indexOf( layers[x] ) ){ |
||||||
|
return { |
||||||
|
'error': true, |
||||||
|
'message': 'invalid param \'layer\': must be one or more of ' + indeces.join(',')
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
clean.layers = layers; |
||||||
|
} |
||||||
|
else { |
||||||
|
clean.layers = indeces; // default (all layers)
|
||||||
|
} |
||||||
|
|
||||||
|
req.clean = clean; |
||||||
|
|
||||||
|
return { 'error': false }; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
// export function
|
||||||
|
module.exports = sanitize; |
@ -0,0 +1,17 @@ |
|||||||
|
function sanitize( req, sanitiser, cb ){ |
||||||
|
|
||||||
|
req.clean = req.clean || {}; |
||||||
|
|
||||||
|
for (var s in sanitiser) {
|
||||||
|
var sanity = sanitiser[s](req); |
||||||
|
if (sanity.error) { |
||||||
|
return cb(sanity.message); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return cb( undefined, req.clean ); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
// export function
|
||||||
|
module.exports = sanitize; |
@ -0,0 +1,27 @@ |
|||||||
|
// validate inputs, convert types and apply defaults
|
||||||
|
function sanitize( req ){ |
||||||
|
|
||||||
|
var clean = req.clean || {}; |
||||||
|
var params= req.query; |
||||||
|
|
||||||
|
// ensure the input params are a valid object
|
||||||
|
if( Object.prototype.toString.call( params ) !== '[object Object]' ){ |
||||||
|
params = {}; |
||||||
|
} |
||||||
|
|
||||||
|
// total results
|
||||||
|
var size = parseInt( params.size, 10 ); |
||||||
|
if( !isNaN( size ) ){ |
||||||
|
clean.size = Math.min( Math.max( size, 1 ), 40 ); // max
|
||||||
|
} else { |
||||||
|
clean.size = 10; // default
|
||||||
|
} |
||||||
|
|
||||||
|
req.clean = clean; |
||||||
|
|
||||||
|
return {'error':false}; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
// export function
|
||||||
|
module.exports = sanitize; |
@ -0,0 +1,23 @@ |
|||||||
|
|
||||||
|
var logger = require('../src/logger'), |
||||||
|
_sanitize = require('../sanitiser/_sanitize'), |
||||||
|
sanitiser = { |
||||||
|
latlonzoom: require('../sanitiser/_latlonzoom') |
||||||
|
}; |
||||||
|
|
||||||
|
var sanitize = function(req, cb) { _sanitize(req, sanitiser, cb); } |
||||||
|
|
||||||
|
// export sanitize for testing
|
||||||
|
module.exports.sanitize = sanitize; |
||||||
|
|
||||||
|
// middleware
|
||||||
|
module.exports.middleware = function( req, res, next ){ |
||||||
|
sanitize( req, function( err, clean ){ |
||||||
|
if( err ){ |
||||||
|
res.status(400); // 400 Bad Request
|
||||||
|
return next(err); |
||||||
|
} |
||||||
|
req.clean = clean; |
||||||
|
next(); |
||||||
|
}); |
||||||
|
}; |
@ -1,84 +0,0 @@ |
|||||||
|
|
||||||
var logger = require('../src/logger'), |
|
||||||
indeces = require('../query/indeces'); |
|
||||||
|
|
||||||
// validate inputs, convert types and apply defaults
|
|
||||||
function sanitize( params, cb ){ |
|
||||||
|
|
||||||
var clean = {}; |
|
||||||
|
|
||||||
// ensure the input params are a valid object
|
|
||||||
if( Object.prototype.toString.call( params ) !== '[object Object]' ){ |
|
||||||
params = {}; |
|
||||||
} |
|
||||||
|
|
||||||
// input text
|
|
||||||
if('string' !== typeof params.input || !params.input.length){ |
|
||||||
return cb( 'invalid param \'input\': text length, must be >0' ); |
|
||||||
} |
|
||||||
clean.input = params.input; |
|
||||||
|
|
||||||
// total results
|
|
||||||
var size = parseInt( params.size, 10 ); |
|
||||||
if( !isNaN( size ) ){ |
|
||||||
clean.size = Math.min( Math.max( size, 1 ), 40 ); // max
|
|
||||||
} else { |
|
||||||
clean.size = 10; // default
|
|
||||||
} |
|
||||||
|
|
||||||
// which layers to query
|
|
||||||
if('string' === typeof params.layers && params.layers.length){ |
|
||||||
var layers = params.layers.split(',').map( function( layer ){ |
|
||||||
return layer.toLowerCase(); // lowercase inputs
|
|
||||||
}); |
|
||||||
for( var x=0; x<layers.length; x++ ){ |
|
||||||
if( -1 === indeces.indexOf( layers[x] ) ){ |
|
||||||
return cb( 'invalid param \'layer\': must be one or more of ' + indeces.join(',') ); |
|
||||||
} |
|
||||||
} |
|
||||||
clean.layers = layers; |
|
||||||
} |
|
||||||
else { |
|
||||||
clean.layers = indeces; // default (all layers)
|
|
||||||
} |
|
||||||
|
|
||||||
// lat
|
|
||||||
var lat = parseFloat( params.lat, 10 ); |
|
||||||
if( isNaN( lat ) || lat < 0 || lat > 90 ){ |
|
||||||
return cb( 'invalid param \'lat\': must be >0 and <90' ); |
|
||||||
} |
|
||||||
clean.lat = lat; |
|
||||||
|
|
||||||
// lon
|
|
||||||
var lon = parseFloat( params.lon, 10 ); |
|
||||||
if( isNaN( lon ) || lon < -180 || lon > 180 ){ |
|
||||||
return cb( 'invalid param \'lon\': must be >-180 and <180' ); |
|
||||||
} |
|
||||||
clean.lon = lon; |
|
||||||
|
|
||||||
// zoom level
|
|
||||||
var zoom = parseInt( params.zoom, 10 ); |
|
||||||
if( !isNaN( zoom ) ){ |
|
||||||
clean.zoom = Math.min( Math.max( zoom, 1 ), 18 ); // max
|
|
||||||
} else { |
|
||||||
clean.zoom = 10; // default
|
|
||||||
} |
|
||||||
|
|
||||||
return cb( undefined, clean ); |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
// export function
|
|
||||||
module.exports = sanitize; |
|
||||||
|
|
||||||
// middleware
|
|
||||||
module.exports.middleware = function( req, res, next ){ |
|
||||||
sanitize( req.query, function( err, clean ){ |
|
||||||
if( err ){ |
|
||||||
res.status(400); // 400 Bad Request
|
|
||||||
return next(err); |
|
||||||
} |
|
||||||
req.clean = clean; |
|
||||||
next(); |
|
||||||
}); |
|
||||||
}; |
|
@ -0,0 +1,26 @@ |
|||||||
|
|
||||||
|
var logger = require('../src/logger'), |
||||||
|
_sanitize = require('../sanitiser/_sanitize'), |
||||||
|
sanitizers = { |
||||||
|
input: require('../sanitiser/_input'), |
||||||
|
size: require('../sanitiser/_size'), |
||||||
|
layers: require('../sanitiser/_layers'), |
||||||
|
latlonzoom: require('../sanitiser/_latlonzoom') |
||||||
|
}; |
||||||
|
|
||||||
|
var sanitize = function(req, cb) { _sanitize(req, sanitizers, cb); } |
||||||
|
|
||||||
|
// export sanitize for testing
|
||||||
|
module.exports.sanitize = sanitize; |
||||||
|
|
||||||
|
// middleware
|
||||||
|
module.exports.middleware = function( req, res, next ){ |
||||||
|
sanitize( req, function( err, clean ){ |
||||||
|
if( err ){ |
||||||
|
res.status(400); // 400 Bad Request
|
||||||
|
return next(err); |
||||||
|
} |
||||||
|
req.clean = clean; |
||||||
|
next(); |
||||||
|
}); |
||||||
|
}; |
@ -0,0 +1,14 @@ |
|||||||
|
#> valid reverse query |
||||||
|
path: '/reverse?lat=29.49136&lon=-82.50622' |
||||||
|
|
||||||
|
#? 200 ok |
||||||
|
response.statusCode.should.equal 200 |
||||||
|
|
||||||
|
#? valid response |
||||||
|
now = new Date().getTime() |
||||||
|
should.exist json |
||||||
|
should.not.exist json.error |
||||||
|
should.exist json.date |
||||||
|
json.date.should.be.within now-2000, now+2000 |
||||||
|
should.exist json.body |
||||||
|
json.body.should.be.instanceof Array |
@ -0,0 +1,52 @@ |
|||||||
|
|
||||||
|
var generate = require('../../../query/reverse'); |
||||||
|
|
||||||
|
module.exports.tests = {}; |
||||||
|
|
||||||
|
module.exports.tests.interface = function(test, common) { |
||||||
|
test('valid interface', function(t) { |
||||||
|
t.equal(typeof generate, 'function', 'valid function'); |
||||||
|
t.end(); |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
module.exports.tests.query = function(test, common) { |
||||||
|
test('valid query', function(t) { |
||||||
|
var query = generate({ |
||||||
|
lat: 29.49136, lon: -82.50622 |
||||||
|
}); |
||||||
|
var expected = { |
||||||
|
query:{ |
||||||
|
filtered : { |
||||||
|
query : { |
||||||
|
match_all : {} |
||||||
|
}, |
||||||
|
filter : { |
||||||
|
geo_distance : { |
||||||
|
distance : '1km', |
||||||
|
center_point : { |
||||||
|
lat: 29.49136,
|
||||||
|
lon: -82.50622 |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
size: 1 |
||||||
|
}; |
||||||
|
|
||||||
|
t.deepEqual(query, expected, 'valid reverse query'); |
||||||
|
t.end(); |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
module.exports.all = function (tape, common) { |
||||||
|
|
||||||
|
function test(name, testFunction) { |
||||||
|
return tape('reverse query ' + name, testFunction); |
||||||
|
} |
||||||
|
|
||||||
|
for( var testCase in module.exports.tests ){ |
||||||
|
module.exports.tests[testCase](test, common); |
||||||
|
} |
||||||
|
}; |
Loading…
Reference in new issue