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