Skip to content

Commit

Permalink
added provider types: http and pg
Browse files Browse the repository at this point in the history
  • Loading branch information
marshallford committed Jun 14, 2016
1 parent f4d5b5c commit 89760b1
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 20 deletions.
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -47,6 +47,7 @@
"express": "^4.13.4",
"limiter": "^1.1.0",
"lodash": "^4.13.1",
"pg": "^5.1.0",
"redis": "^2.6.1"
}
}
24 changes: 18 additions & 6 deletions src/api.js
Expand Up @@ -6,11 +6,23 @@ import { latlng, truncate } from '~/utils'
import config from '~/config'
import client from '~/redis'

// define rate limiter based on provider's config
const limiter = new RateLimiter(
config.providers.google.limit.number,
config.providers.google.limit.period,
true
// get list of providers to use
const providers = Object.keys(config.providers)
.filter(provider => config.providers[provider].priority !== 0)
.sort((x, y) => config.providers[x].priority - config.providers[y].priority)
.map(provider => provider)

// define rate limiters based on provider's config
const limiters = {}
providers
.filter(provider => config.providers[provider].limit)
.forEach(provider => {
limiters[provider] = new RateLimiter(
config.providers.google.limit.number,
config.providers.google.limit.period,
true
)
}
)

const api = () => {
Expand All @@ -35,7 +47,7 @@ const api = () => {
// if latlng key exists in redis, return cached result to client
if (reply !== null) return res.set('redis', 'HIT').json({ 'input': input, 'output': reply })

limiter.removeTokens(1, (error, remainingRequests) => {
limiters['google'].removeTokens(1, (error, remainingRequests) => {
// check if provider's defined rate limit has been reached
if (error || remainingRequests < 0) {
return res.status(500).json({ message: 'provider rate limit reached' })
Expand Down
40 changes: 28 additions & 12 deletions src/config.js
Expand Up @@ -2,32 +2,48 @@ const config = {
truncate: 5,
providers: {
google: {
key: process.env['REVERSE_GEOCODER_GOOGLE_API_KEY'],
url: (lat, lng, key) => `https://maps.googleapis.com/maps/api/geocode/json?latlng=${lat},${lng}&key=${key}`,
path: 'data.results[0].formatted_address',
type: 'http',
priority: 2,
limit: {
'number': 2500,
'period': 'day'
}
},
key: process.env['REVERSE_GEOCODER_GOOGLE_API_KEY'],
url: (lat, lng, key) => `https://maps.googleapis.com/maps/api/geocode/json?latlng=${lat},${lng}&key=${key}`,
path: 'data.results[0].formatted_address'
},
openstreetmap: {
key: ' ',
url: (lat, lng, key) => `http://nominatim.openstreetmap.org/reverse?format=json&lat=${lat}&lon=${lng}&addressdetails=0`,
path: 'data.display_name',
type: 'http',
limit: {
'number': 1,
'period': 'second'
}
},
priority: 3,
key: 'N/A',
url: (lat, lng, key) => `http://nominatim.openstreetmap.org/reverse?format=json&lat=${lat}&lon=${lng}&addressdetails=0`,
path: 'data.display_name'
},
// for testing
status400: {
key: ' ',
url: () => 'http://httpstat.us/400',
path: 'data',
type: 'http',
priority: 0,
limit: {
'number': 100,
'period': 'minute'
}
},
key: ' ',
url: () => 'http://httpstat.us/400',
path: 'data'
},
postgis: {
type: 'pg',
limit: null,
priority: 1,
host: 'localhost',
port: '5432',
db: 'gisdb',
username: process.env['REVERSE_GEOCODER_POSTGIS_USERNAME'],
password: process.env['REVERSE_GEOCODER_POSTGIS_PASSWORD']
}
}
}
Expand Down
16 changes: 14 additions & 2 deletions src/server.js
Expand Up @@ -16,11 +16,23 @@ app.use((err, req, res, next) => {
})

// validate config
const requiredProviderInfo = ['key', 'url', 'path', 'limit']
const requiredProviderInfo = ['type', 'priority', 'limit']
const requiredHttpProviderInfo = ['key', 'url', 'path']
const requiredPgProviderInfo = ['host', 'port', 'db', 'username', 'password']

Object.keys(config.providers).forEach(provider => {
requiredProviderInfo.forEach(info => {
if (!config.providers[provider][info]) {
if (config.providers[provider][info] === undefined) {
throw new Error(`Provider ${provider} is missing ${info} information`)
}
})
requiredHttpProviderInfo.forEach(info => {
if (config.providers[provider][info] === undefined && config.providers[provider].type === 'http') {
throw new Error(`Provider ${provider} is missing ${info} information`)
}
})
requiredPgProviderInfo.forEach(info => {
if (config.providers[provider][info] === undefined && config.providers[provider].type === 'pg') {
throw new Error(`Provider ${provider} is missing ${info} information`)
}
})
Expand Down

0 comments on commit 89760b1

Please sign in to comment.