Giter Club home page Giter Club logo

mapbox-sdk-js's Introduction

@mapbox/mapbox-sdk

Build Status

A JS SDK for working with Mapbox APIs.

Works in Node, the browser, and React Native.

As of 6/11/18, the codebase has been rewritten and a new npm package released. The mapbox package is deprecated in favor of the new @mapbox/mapbox-sdk package. Please read the documentation and open issues with questions or problems.

Table of contents

Installation

npm install @mapbox/mapbox-sdk

If you are supporting older browsers, you will need a Promise polyfill. es6-promise is a good one, if you're uncertain.

The documentation below assumes you're using a JS module system. If you aren't, read "Pre-bundled files on unpkg.com".

Usage

There are 3 basic steps to getting an API response:

  1. Create a client.
  2. Create a request.
  3. Send the request.

Creating clients

To create a service client, import the service's factory function from '@mapbox/mapbox-sdk/services/{service}' and provide it with your access token.

The service client exposes methods that create requests.

const mbxStyles = require('@mapbox/mapbox-sdk/services/styles');
const stylesService = mbxStyles({ accessToken: MY_ACCESS_TOKEN });
// stylesService exposes listStyles(), createStyle(), getStyle(), etc.

You can also share one configuration between multiple services. To do that, initialize a base client and then pass that into service factory functions.

const mbxClient = require('@mapbox/mapbox-sdk');
const mbxStyles = require('@mapbox/mapbox-sdk/services/styles');
const mbxTilesets = require('@mapbox/mapbox-sdk/services/tilesets');

const baseClient = mbxClient({ accessToken: MY_ACCESS_TOKEN });
const stylesService = mbxStyles(baseClient);
const tilesetsService = mbxTilesets(baseClient);

Creating and sending requests

To create a request, invoke a method on a service client.

Once you've created a request, send the request with its send method. It will return a Promise that resolves with a MapiResponse.

const mbxClient = require('@mapbox/mapbox-sdk');
const mbxStyles = require('@mapbox/mapbox-sdk/services/styles');
const mbxTilesets = require('@mapbox/mapbox-sdk/services/tilesets');

const baseClient = mbxClient({ accessToken: MY_ACCESS_TOKEN });
const stylesService = mbxStyles(baseClient);
const tilesetsService = mbxTilesets(baseClient);

// Create a style.
stylesService.createStyle({..})
  .send()
  .then(response => {..}, error => {..});

// List tilesets.
tilesetsService.listTilesets()
  .send()
  .then(response => {..}, error => {..})

Overview of requests, responses, and errors

For more details, please read the full classes documentation.

MapiRequest

Service methods return MapiRequest objects.

Typically, you'll create a MapiRequest then send it. send returns a Promise that resolves with a MapiResponse or rejects with a MapiError.

MapiRequests also expose other properties and methods that you might use from time to time. For example:

  • MapiRequest#abort aborts the request.
  • MapiRequest#eachPage executes a callback for each page of a paginated API response.
  • MapiRequest.emitter exposes an event emitter that fires events like downloadProgress and uploadProgress.

For more details, please read the full MapiRequest documentation.

// Create a request and send it.
stylesService.createStyle({..})
  .send()
  .then(response => {..}, error => {..});

// Abort a request.
const req = tilesetsService.listTilesets();
req.send().then(response => {..}, error => {
  // Because the request is aborted, an error will be thrown that we can
  // catch and handle.
});
req.abort();

// Paginate through a response.
tilesetsService.listTilesets().eachPage((error, response, next) => {
  // Do something with the page, then call next() to send the request
  // for the next page.

  // You can check whether there will be a next page using
  // MapiResponse#hasNextPage, if you want to do something
  // different on the last page.
  if (!response.hasNextPage()) {..}
});

// Listen for uploadProgress events.
const req = stylesService.createStyleIcon({..});
req.on('uploadProgress', event => {
  // Do something with the progress event information.
});
req.send().then(response => {..}, error => {..});

MapiResponse

When you send a MapiRequest, the returned Promise resolves with a MapiResponse.

Typically, you'll use MapiResponse.body to access the parsed API response.

MapiResponses also expose other properties and methods. For example:

  • MapiResponse#hasNextPage indicates if there is another page of results.
  • If there is another page, MapiResponse#nextPage creates a MapiRequest that you can send to get that next page.
  • MapiResponse.headers exposes the parsed HTTP headers from the API response.

For more details, please read the full MapiResponse documentation.

// Read a response body.
stylesService.getStyle({..})
  .send()
  .then(resp => {
    const style = resp.body;
    // Do something with the style.
  }, err => {..});

// Get the next page of results.
tilesetsService.listTilesets()
  .send()
  .then(resp => {
    if (resp.hasNextPage()) {
      const nextPageReq = resp.nextPage();
      nextPageReq.send().then(..);
    }
  }, err => {..});

// Check the headers.
tilesetsService.listTilesets()
  .send()
  .then(resp => {
    console.log(resp.headers);
  }, err => {..});

MapiError

If the server responds to your MapiRequest with an error, or if you abort the request, the Promise returned by send will reject with a MapiError.

MapiErrors expose the information you'll need to handle and respond to the error. For example:

  • MapiError.type exposes the type of error, so you'll know if it was an HTTP error from the server or the request was aborted.
  • MapiError.statusCode exposes the status code of HTTP errors.
  • MapiError.body exposes the body of the HTTP response, parsed as JSON if possible.
  • MapiError.message tells you what went wrong.

For more details, please read the full MapiError documentation.

// Check the error.
stylesService.getStyle({..})
  .send()
  .then(response => {..}, error => {
    if (err.type === 'RequestAbortedError') {
      return;
    }
    console.error(error.message);
  });

Services

Please read the full documentation for services.

Pre-bundled files on unpkg.com

If you aren't using a JS module system, you can use a <script> tag referencing pre-bundled files on the CDN unpkg.com.

<script src="https://unpkg.com/@mapbox/mapbox-sdk/umd/mapbox-sdk.js"></script>
<script src="https://unpkg.com/@mapbox/mapbox-sdk/umd/mapbox-sdk.min.js"></script>

These files are a UMD build of the package, exposing a global mapboxSdk function that creates a client, initializes all the services, and attaches those services to the client. Here's how you might use it.

<script src="https://unpkg.com/@mapbox/mapbox-sdk/umd/mapbox-sdk.min.js"></script>
<script>
  var mapboxClient = mapboxSdk({ accessToken: MY_ACCESS_TOKEN });
  mapboxClient.styles.getStyle(..)
    .send()
    .then(..);
  mapboxClient.tilesets.listTilesets(..)
    .send()
    .then(..);
</script>

Development

Please read ./docs/development.md.

mapbox-sdk-js's People

Contributors

andrewharvey avatar apendleton avatar chriswhong avatar cmtoomey avatar danpat avatar danswick avatar davidtheclark avatar dependabot[bot] avatar elifitch avatar geografa avatar grigorydobrov avatar heystenson avatar jingsam avatar kasi1999999 avatar kepta avatar lshig avatar mapsam avatar mcwhittemore avatar millzpaugh avatar mollymerp avatar mpothier avatar peterqliu avatar rclark avatar scothis avatar shabnomnom avatar tmcw avatar tristen avatar vikneshwar avatar vladislavmedved avatar willwhite avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mapbox-sdk-js's Issues

Geocoder taking access token as query

The response leads me to believe that somehow the code is taking the access token as the query to the geocoder.

Code:

var mapboxLib = require('mapbox');

var accessToken = 'pk.eyJ1IjoibHl6aWRpYW1vbmQiLCJhIjoiNjRiZmQ5YjhiYjM4YTc5NDViMDE5YTVlNDcxNjM0MDMifQ.A7h7zjV7EQjL4Juoop3J2g';

var client = new mapboxLib(accessToken);

function geocode(location){
  client.geocodeForward(location, {}, function(err, res){
    if(err) throw err;
    console.log(res);
  });
}

geocode('Chester, NJ');

Response:

{ type: 'FeatureCollection',
  query: 
   [ 'access',
      'token',
   'pkeyj1ijoibhl6awrpyw1vbmqilcjhijoinjrizmq5yjhiyjm4ytc5ndvimde5ytvlndcxnjm0mdmifqa7h7zjv7eqjl4juoop3j2g' ],
  features: [],
  attribution: 'NOTICE: You may cache this data for up to 30 days. © 2015 Mapbox and its suppliers. All rights reserved. Use of this data is subject to the Mapbox Terms of Service. (https://www.mapbox.com/about/maps/)’ }

Any thoughts as to why this might be happening? @tmcw

xhr library

request is extremely robust and common for node, but I believe it's simply too large for browsers: it's an 844kb bump even after code compression.

Current plan is to use got for node and xhr for browsers.

better uri encoding for geocodes

I was doing a bit of forward geocoding and ended up running a string with a line break in it, looked sort of like 100 6th St\nSan Francisco. It failed with this error message:

Potentially unhandled rejection [7] Error: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<TITLE>ERROR: The request could not be satisfied</TITLE>
</HEAD><BODY>
<H1>ERROR</H1>
<H2>The request could not be satisfied.</H2>
<HR noshade size="1px">
Bad request.
<BR clear="all">
<HR noshade size="1px">
<PRE>
Generated by cloudfront (CloudFront)
Request ID: 0C0WjIdiUNxnFnej1T_D3zhMfAQMXe49QKjAXEdziNroPxHra7E3Zg==
</PRE>
<ADDRESS>
</ADDRESS>
</BODY></HTML>

https://github.com/mapbox/mapbox-sdk-js/blob/master/lib/services/geocoder.js#L56

invariant -> assert

This way we don't need a module dep: it's built for node and works with browserify

Promise support

We should support promises. This means making callbacks optional for all methods.

I'll post a sketch of this in a sec to get thoughts on the approach.

Adding a Static Service

I'm looking into adding a static service to this library for generating URLs to static map images.

Here's a rough API sketch:

var MapboxClient = require('mapbox');
var client = new MapboxClient('YOUR_ACCESS_TOKEN');
var url = client.static('mapbox.pencil', ({lon: 123, lat: 456});

Is the above feature appropriate for this library?

I can't seem to find a service method that doesn't take a callback. Are there any, or do all the methods hit the network?

Error handling and documentation

The various client methods should handle errors in a regular, predictable fashion, and there should be a well-defined way to document the possible error outcomes from each method.

Geocode batch support

The geocode... code should be smart enough to obey Mapbox's special headers in order to geocode big collections of input.

Browser example

This code works great in browsers. This is not immediately obvious. Make it so.

CLI utilities

I don't particularly care if these are in this package or not. For development and everything else, we need cli utilities.

HTML documentation

This repo should have HTML documentation generated with documentation.js and pushed to its mb-pages branch.

Geocoder proximity doesn't do anything

The forward geocoder endpoint passes a proximity flag into the rest client, but it doesn't make it into the final URL, so it doesn't end up affecting the results. The issue seems to be this rest interceptor, which, per the rest docs, does this:

Params defined by the template that are missing as well as additional params are ignored. After the template interceptor, the request.params are removed from the request object, as the URI is fully defined.

So the object is gone by the time GET parameters are added.

Assigning to myself, but not sure yet how to fix it.

cc @tmcw

Feature pagination on list endpoints

We have provisional pagination in place for feature listing API endpoints. We should support these are additional options when running .listFeatures(). I would suggest implementing this by changing the function so that it can accept an optional options object that may provide the following arguments to the API call:

Argument Description
sortby The property to use for sorting. created and modified are currently supported.
reverse Set to true to reverse the default sort order of the listing.
limit The maximum number of objects to return. This value must be between 1 and 100. The API will attempt to return the requested number of objects, but receiving fewer objects does not necessarily signal the end of the collection. Receiving an empty page of results is the only way to determine when you are at the end of a collection.
start The object id that acts as the cursor for pagination and defines your location in the collection. This argument is exclusive so the object associated with the id provided to the start argument will not be included in the response.
Datasets.prototype.listFeatures = function(dataset, options, callback) {
  if (typeof options === 'function') {
    callback = options;
    options = {};
  }

  // ... etc
};

cc @isiyu @peterqliu @willwhite

Modularity while expanding to other services

As we attempt to bring support for more services into this lib, we'll probably feel the need to break from a single class that defines every one of the methods. Further, there may be advantages to being able to import parts of the library, e.g.

var MapboxDirections = require('mapbox/directions');

@tmcw I'm curious what your architectural thoughts are here? It seems to me that constants.js and the MapboxClient class are basically utilities for any of the services to have access to. Perhaps each service should be a module that instantiates these utilities and then goes on to define the methods pertinent to that service.

reverseGeocode location object not working

First, I think the longitude & latitude are in the wrong order in the constant:
module.exports.API_GEOCODER_REVERSE = '/v4/geocode/{dataset}/{location.longitude},{location.latitude}.json';

Second, when sending in an object {latitude: lat, longitude: long}, the query string isn't properly set due to an issue in template.js in rest/interceptor. The uri is set using param[value] but this doesn't work then the value is "location.longitude", etc.

I'm fixing this right now by explicitly setting long & lat params in geocoder.js like so:

params: { latitude: location.latitude, longitude: location.longitude, dataset: dataset }

and rewriting the constant to:

module.exports.API_GEOCODER_REVERSE = '/v4/geocode/{dataset}/{latitude},{longitude}.json';

Stop using `assert`

Our use of the assert module breaks compatibility with react-native and other bundlers that don't polyfill node modules.

Drop geojsonhint dependency

This is a nice perk but I think it should be out of scope. At worst it's a big perf hit not everyone wants to pay all the time.

Clean up after tests

Right now we create datasets and other resources and don't delete them. We should have tests clean up after themselves, deleting the resources they create.

Dist version is too old

Hi,

can someone publish a new "dist" version of the SDK? It's a bit painful (impossible?) trying to merge in latest changes file by file into a big "dist" .js file manually (we are using Bower in our Cordova app).

Thanks for the great work!

Start from scratch

Remove everything in this repo, start with a new module with the usual shiz

  • CI
  • eslint
  • docs
  • jsdocs

Callback failed to be called for insertFeature

Yesterday I moved my 24,000 instagram photo points from a local GeoJSON file to a dataset. As the batch request function hadn't been deployed yet I did a serial push via insertFeature. Most of the time it worked fine. There were a few times though when the callback was never called. One time I let it got for a very longtime (at least an hour) so I'm pretty sure the problem is internal to the SDK, but it could be some weird hang up in the api.

/cc @rclark @tmcw

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.