Skip to content

Commit

Permalink
Merge pull request #16 from mapbox/refactor
Browse files Browse the repository at this point in the history
Begin service-split refactor
  • Loading branch information
tmcw committed Jul 18, 2015
2 parents 3a94349 + 0e579d9 commit c0515b9
Show file tree
Hide file tree
Showing 8 changed files with 552 additions and 433 deletions.
443 changes: 11 additions & 432 deletions lib/client.js

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions lib/format_points.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
'use strict';

var invariant = require('invariant');

function formatPoints(waypoints) {
return waypoints.map(function(location) {
invariant(typeof location.latitude === 'number' &&
typeof location.longitude === 'number',
'location must be an object with numeric latitude & longitude properties');
return location.longitude + ',' + location.latitude;
}).join(';');
}

module.exports = formatPoints;
10 changes: 10 additions & 0 deletions lib/make_query.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
'use strict';

var qs = require('querystring');

function makeQuery(accessToken, options) {
options.access_token = accessToken;
return '?' + qs.stringify(options);
}

module.exports = makeQuery;
127 changes: 127 additions & 0 deletions lib/services/directions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
'use strict';

var invariant = require('invariant'),
request = require('superagent'),
resolveToString = require('es6-template-strings/resolve-to-string'),
formatPoints = require('../format_points'),
makeQuery = require('../make_query'),
constants = require('../constants');

/**
* The JavaScript API to Mapbox services
*
* @class
* @throws {Error} if accessToken is not provided
* @param {string} accessToken a private or public access token
* @example
* var client = new MapboxClient('ACCESSTOKEN');
*/
function MapboxDirections(accessToken) {
invariant(typeof accessToken === 'string',
'accessToken required to instantiate MapboxDirections');
this.accessToken = accessToken;
}

/**
* Find directions from A to B, or between any number of locations.
* Consult the [Mapbox Directions API](https://www.mapbox.com/developers/api/directions/)
* for more documentation.
*
* @param {Array<Object>} waypoints an array of objects with `latitude`
* and `longitude` properties that represent waypoints in order. Up to
* 25 waypoints can be specified.
* @param {Object} [options={}] additional options meant to tune
* the request
* @param {string} [options.profile=mapbox.driving] the directions
* profile, which determines how to prioritize different routes.
* Options are `'mapbox.driving'`, which assumes transportation via an
* automobile and will use highways, `'mapbox.walking'`, which avoids
* streets without sidewalks, and `'mapbox.cycling'`, which prefers streets
* with bicycle lanes and lower speed limits for transportation via
* bicycle.
* @param {string} [options.alternatives=true] whether to generate
* alternative routes along with the preferred route.
* @param {string} [options.instructions=text] format for turn-by-turn
* instructions along the route.
* @param {string} [options.geometry=geojson] format for the returned
* route. Options are `'geojson'`, `'polyline'`, or `false`: `polyline`
* yields more compact responses which can be decoded on the client side.
* [GeoJSON](http://geojson.org/), the default, is compatible with libraries
* like [Mapbox GL](https://www.mapbox.com/mapbox-gl/),
* Leaflet and [Mapbox.js](https://www.mapbox.com/mapbox.js/). `false`
* omits the geometry entirely and only returns instructions.
* @param {Function} callback called with (err, results)
* @returns {undefined} nothing, calls callback
* @example
* var mapboxClient = new MapboxDirections('ACCESSTOKEN');
* mapboxClient.directions(
* [
* { latitude: 33.6, longitude: -95.4431 },
* { latitude: 33.2, longitude: -95.4431 } ],
* function(err, res) {
* // res is a document with directions
* });
*
* // With options
* mapboxClient.getDirections([
* { latitude: 33.6875431, longitude: -95.4431142 },
* { latitude: 33.6875431, longitude: -95.4831142 }
* ], {
* profile: 'mapbox.walking',
* instructions: 'html',
* alternatives: false,
* geometry: 'polyline'
* }, function(err, results) {
* console.log(results.origin);
* });
*/
MapboxDirections.prototype.getDirections = function(waypoints, options, callback) {

// permit the options argument to be omitted
if (callback === undefined && typeof options === 'function') {
callback = options;
options = {};
}

// typecheck arguments
invariant(Array.isArray(waypoints), 'waypoints must be an array');
invariant(typeof options === 'object', 'options must be an object');
invariant(typeof callback === 'function', 'callback must be a function');

var encodedWaypoints = formatPoints(waypoints);

var profile = 'mapbox.driving',
alternatives = true,
geometry = 'geojson',
instructions = 'text';

if (options.profile) {
invariant(typeof options.profile === 'string', 'profile option must be string');
profile = options.profile;
}

if (options.instructions) {
invariant(typeof options.instructions === 'string', 'instructions option must be string');
instructions = options.instructions;
}

if (options.geometry) {
invariant(typeof options.geometry === 'string', 'geometry option must be string');
geometry = options.geometry;
}

var url = resolveToString(constants.API_DIRECTIONS, {
encodedWaypoints: encodedWaypoints,
profile: profile
}) + makeQuery(this.accessToken, {
instructions: instructions,
geometry: geometry,
alternatives: alternatives
});

request(url, function(err, res) {
callback(err, res.body);
});
};

module.exports = MapboxDirections;
147 changes: 147 additions & 0 deletions lib/services/geocoder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
'use strict';

var invariant = require('invariant'),
request = require('superagent'),
resolveToString = require('es6-template-strings/resolve-to-string'),
makeQuery = require('../make_query'),
constants = require('../constants');

/**
* The JavaScript API to Mapbox services
*
* @class
* @throws {Error} if accessToken is not provided
* @param {string} accessToken a private or public access token
* @example
* var client = new MapboxClient('ACCESSTOKEN');
*/
function MapboxGeocoder(accessToken) {
invariant(typeof accessToken === 'string',
'accessToken required to instantiate MapboxGeocoder');
console.log('geocoder constructed');
this.accessToken = accessToken;
}

/**
* Search for a location with a string, using the
* [Mapbox Geocoding API](https://www.mapbox.com/developers/api/geocoding/).
*
* @param {string} query desired location
* @param {Object} [options={}] additional options meant to tune
* the request
* @param {Object} options.proximity a proximity argument: this is
* a geographical point given as an object with latitude and longitude
* properties. Search results closer to this point will be given
* higher priority.
* @param {string} [options.dataset=mapbox.places] the desired data to be
* geocoded against. The default, mapbox.places, does not permit unlimited
* caching. `mapbox.places-permanent` is available on request and does
* permit permanent caching.
* @param {Function} callback called with (err, results)
* @returns {undefined} nothing, calls callback
* @example
* var mapboxClient = new MapboxGeocoder('ACCESSTOKEN');
* mapboxClient.geocodeForward('Paris, France', function(err, res) {
* // res is a GeoJSON document with geocoding matches
* });
* // using the proximity option to weight results closer to texas
* mapboxClient.geocodeForward('Paris, France', {
* proximity: { latitude: 33.6875431, longitude: -95.4431142 }
* }, function(err, res) {
* // res is a GeoJSON document with geocoding matches
* });
*/
MapboxGeocoder.prototype.geocodeForward = function(query, options, callback) {

// permit the options argument to be omitted
if (callback === undefined && typeof options === 'function') {
callback = options;
options = {};
}

// typecheck arguments
invariant(typeof query === 'string', 'query must be a string');
invariant(typeof options === 'object', 'options must be an object');
invariant(typeof callback === 'function', 'callback must be a function');

var queryOptions = {};
if (options.proximity) {
invariant(typeof options.proximity.latitude === 'number' &&
typeof options.proximity.longitude === 'number',
'proximity must be an object with numeric latitude & longitude properties');
queryOptions.proximity = options.proximity.longitude + ',' + options.proximity.latitude;
}

var dataset = 'mapbox.places';
if (options.dataset) {
invariant(typeof options.dataset === 'string', 'dataset option must be string');
dataset = options.dataset;
}

var url = resolveToString(constants.API_GEOCODER_FORWARD, {
query: query,
dataset: dataset
}) + makeQuery(this.accessToken, queryOptions);

request(url, function(err, res) {
callback(err, res.body);
});
};

/**
* Given a location, determine what geographical features are located
* there. This uses the [Mapbox Geocoding API](https://www.mapbox.com/developers/api/geocoding/).
*
* @param {Object} location the geographical point to search
* @param {number} location.latitude decimal degrees latitude, in range -90 to 90
* @param {number} location.longitude decimal degrees longitude, in range -180 to 180
* @param {Object} [options={}] additional options meant to tune
* the request
* @param {string} [options.dataset=mapbox.places] the desired data to be
* geocoded against. The default, mapbox.places, does not permit unlimited
* caching. `mapbox.places-permanent` is available on request and does
* permit permanent caching.
* @param {Function} callback called with (err, results)
* @returns {undefined} nothing, calls callback
* @example
* var mapboxClient = new MapboxGeocoder('ACCESSTOKEN');
* mapboxClient.geocodeReverse(
* { latitude: 33.6875431, longitude: -95.4431142 },
* function(err, res) {
* // res is a GeoJSON document with geocoding matches
* });
*/
MapboxGeocoder.prototype.geocodeReverse = function(location, options, callback) {

// permit the options argument to be omitted
if (callback === undefined && typeof options === 'function') {
callback = options;
options = {};
}

// typecheck arguments
invariant(typeof location === 'object', 'location must be an object');
invariant(typeof options === 'object', 'options must be an object');
invariant(typeof callback === 'function', 'callback must be a function');

invariant(typeof location.latitude === 'number' &&
typeof location.longitude === 'number',
'location must be an object with numeric latitude & longitude properties');

var dataset = 'mapbox.places';
if (options.dataset) {
invariant(typeof options.dataset === 'string', 'dataset option must be string');
dataset = options.dataset;
}

var url = resolveToString(constants.API_GEOCODER_REVERSE, {
location: location,
dataset: dataset
}) + makeQuery(this.accessToken, {});

request(url, function(err, res) {
callback(err, res.body);
});
};

module.exports = MapboxGeocoder;

0 comments on commit c0515b9

Please sign in to comment.