UNPKG

dc-mar

Version:

Node module for DC Master Address Repository API

91 lines (80 loc) 3.13 kB
const axios = require('axios'); const Address = require('./address'); const clientDefaultOptions = { request: axios, baseUrl: 'https://citizenatlas.dc.gov/newwebservices/locationverifier.asmx/', minInterval: 3000, // 3 sec, as requested by DC OCTO: https://octo.dc.gov/node/1166991 }; let previousRequestTime = 0; class Client { constructor(options = {}) { for (const name of Object.keys(options)) { if (!clientDefaultOptions.hasOwnProperty(name)) { throw new Error(`Invalid client option "${name}"`); } } this.options = Object.assign({}, clientDefaultOptions, options); } // Wait long enough between requests (not useful except privately) pause(result) { const now = Date.now(); const delay = Math.max(this.options.minInterval - now + previousRequestTime, 0); previousRequestTime = now; return new Promise(function (resolve) { setTimeout(() => resolve(result), delay); }); } request(operation, parameters) { if (operation.substr(-1) !== '2') { operation += '2'; // the REST versions of the operations all end in '2' } const requestOptions = { url: this.options.baseUrl + operation, params: Object.assign({}, parameters, {f: 'json'}), // avoid modifying argument }; return this.pause() .then(() => this.options.request(requestOptions)) .then(response => response.data); } findLocation(searchString, raw = false) { return this.request('findLocation', {str: searchString}) .then(function (body) { if (raw) { return body; } return extractAddresses(body); }); } findLocationBatch(searchStrings, raw) { const separator = '|'; const separatorRe = new RegExp('\\' + separator, 'g'); const parameters = { addr_base64: Buffer.from(searchStrings.map(s => s.replace(separatorRe, ' ')).join(separator)) .toString('base64'), addr_separator: separator, chunkSequnce_separator: '\x7F', // don't know what this is supposed to do }; return this.request('findLocationBatch', parameters) .then(function (body) { if (raw) { return body; } return body.filter(o => typeof o === 'object').map(extractAddresses); }); } reverseLatLngGeocoding(lat, lng, raw) { const parameters = {lat, lng}; return this.request('reverseLatLngGeocoding', parameters) .then(function (body) { if (raw) { return body; } return body && body.Table1 ? body.Table1.map(properties => new Address(properties)) : []; }); } } function extractAddresses(obj) { const r = obj.returnDataset; return r && r.Table1 ? r.Table1.map(properties => new Address(properties)) : []; } module.exports = Client;