Home Manual Reference Source Repository

Mapcreator Javascript API npm version

The Mapcreator API is a powerful mapping service built for our front-end applications. This library is released to provide a painless way of talking to the api using Javascript. See the LICENSE file for licensing information. Api tokens can be granted through support requests.

Documentation

The documentation can be found here. Please refer to the api documentation for resource information. Job structure documentation will be released soon.

Installation

Please refer to the installation docs here.

Download

The library is built to be ran in either the browser or using nodejs.

The source code can be found on the GitLab repo.

Building

Please refer to the build docs here

Authenticating

Authentication can be done using OAuth. Examples of how to use authentication can be found in the documentation. The following authentication methods are supported:

Examples

Examples can be found in the documentation under the "Manual" section.

License

See the LICENSE file for license information. This project is licensed under a BSD-3-Clause license.

Basics

These examples assume that an instance of the api exists and is authenticated. See the node and web authentication examples for more information on authenticating.

Getting a resource

Resources are bound to the base api class by default. Resources can be fetched in two ways; by selecting them (.select) or by fetching them (.get). Selecting them will only set the object's id to it's properties. Fetching a resource

Fetch resource and all it's properties:

api.colors.get(1).then(function(color) {
    console.log(color.id + " " + color.name + ": " + color.hex);
})

Select the current user to quickly obtain related mapstyle sets:

api.users.select('me').mapstyleSets().then(function(sets) {
    for(var i = 0; i < sets.data.length; i++) {
        console.log(sets.data[i].name);
    }
});

Selection is only usefull as a stepping stone to related resources that can be easily obtained using the id of the parent. Please refer to the api documentation for further reference.

Create a new resource

Create a new color and dump the new resource to the console after saving

var data = {name: 'Smurf', hex: '88CCFF'};
api.colors.new(data).save().then(console.dir);

Modify a resource

Change profession of the current user and save it.

api.users.get('me').then(me => {
  me.profession = 'Developer';
  me.save(); // Optional chaining to get the updated resource
});

Clone a resource

Setting the id to null forces the creation of a new object upon saving.

api.colors.get(1).then(color => {
  color.id = null;
  color.save();
});

Pagination

Listing resources with pagination. First page with 5 items per page

api.colors.list(1, 5).then(page => {
  console.log('Got resources:');

  for (var i = 0; i < page.data.length; i++) {
    console.log(page.data[i].toString());
  }
});

Loop over every page and print the result to the console.

function parsePages(page) {
  for (var i = 0; i < page.data.length; i++) {
    console.log(page.data[i].toString());
  }

  if (page.hasNext) {
    console.log('Grabbing page ' + (page.page + 1));
    page.next().then(parsePage);
  }
}

api.colors
   .list(1, 50)
   .then(parsePages);

Loop over all pages and return the data in a promise

function parsePages(page) {
  var data = [];

  function parse(page) {
      data = data.concat(page.data);

      if(page.hasNext) {
          return page.next().then(parse);
      } else {
          return data;
      }
  }

  return parse(page);
}

api.colors
   .list(1, 50)
   .then(parsePages)
   .then(d => console.log('Total rows: ' + d.length));

Select current user but do not fetch any info to make fetching resources easier.

api.users.select('me').colors.list().then(page => {
  console.dir(page.data);
});

Searching

Resource lists can be queried to search for specific records as follows:

var query = {
  name: '^:test',
  scale_min: ['>:1', '<:10'],
}
api.layers.search(query).then(console.dir);

The search method is an extension of list. This means that .search({}) is the same as list(). More information about search query formatting can be found in the api documentation.

Canceling a requests

Most methods that return a promise will have a method called cancel. This method can be called to cancel the request. If the request is running or about to be ran the promise will throw an error once canceled. If the request has been completed before the promise has been canceled it will not throw an error and instead complete successfully.

// Fetch a preview
const promise = api.jobs.select(123456).downloadPreview();

// Turns out we don't need it anyways
promise.cancel();

Authentication

Authentication is done through OAuth. This library provides multiple OAuth flow implementations for authentication. A client id can be obtained through a support ticket but this is planned to change in the near future. The client will first check if any tokens can be found in the cache before requiring authentication. If one can be found the api.authenticate() method will instantly resolve without any side-effects. The variable api.authenticated will be set to true if a token has been found and is still valid.

Tokens are stored in HTTPS cookies if possible and using localStorage when the browser is not using a HTTPS connection. Nodejs uses a file named .m4n_token to store the token.

Web

Multiple flows are supported for web browsers. All the web examples assume the web build of the library has been included in the target page.

Implicit Flow

A client id is required to use the implicit flow. The redirect url must be the same as the one linked to the client id. The callback url is automatically guessed if none is provided.

// Obtained client id
var clientId = 1;

// Callback url is set to the current url by default
var auth = new ImplicitFlow(clientId);
var api = new Mapcreator(auth);

// This will hijack the page if no authentication cache can
// be found. Smartest thing to do is to just let it happen
// and initialize any other code afterwards.
api.authenticate().then(function() {
  // Save the token
  api.saveToken();

  // Get the current user and dump the result to the console.
  api.users.get('me').then(console.dir);
});

Implicit flow pop-up

Just like the Implicit Flow a client id is required.

// Obtained client id
var clientId = 1;

// Callback url is set to the current url by default. The
// script is smart enough close the page if it detects that
// it's a child after authentication. This means that either
// the current page can be set as the callback (default) or
// a custom page that just contains `api.authenticate()`
// that uses ImplicitFlowPopup as the auth parameter.
var auth = new ImplicitFlowPopup(clientId);
var api = new Mapcreator(auth);

// This will create a pop-up window containing the log in
// page. Once the pop-up redirects back to the callback it
// will resolve the promise. The callback page should contain
api.authenticate().then(function() {
  // Save the token
  api.saveToken();

  // Get the current user and dump the result to the console.
  api.users.get('me').then(console.dir);
});

Implicit flow pop-up (advanced)

Due to the nature of the implicit flow pop-up (referred to as IFP from now on) method the callback page can be set to a blank page that just grabs the token and then closes. This can be done in the following way.

index.html:

var clientId = 1;
var callbackUrl = 'https://example.com/callback.html';

var auth = new ImplicitFlowPopup(clientId);
var api = new Mapcreator(auth);

// This will resolve once the callback page has been loaded
api.authenticate().then(function() {
  // Save the token
  api.saveToken();

  // Get the current user and dump the result to the console.
  api.users.get('me').then(console.dir);
});

callback.html:

var clientId = 1;

// This will instantly detect the token and close the page
new ImplicitFlowPopup(clientId);

Password flow (dangerous)

The password flow is NOT intended to be used in the browser. If you do decide to use the password flow then it is recommended to make sure that the site is NOT public facing and using HTTPS. Leaking the secret is a very bad idea.

var clientId = 1; // client id
var secret = ''; // secret
var username = 'user@example.com'; // email is used for authentication
var password = 'Password1!'; // password

// Secret will be leaked if this is used on a webpage. Please only use
// this for non-web applications.
var auth = new PasswordFlow(clientId, secret, username, password);
var api = new Mapcreator(auth);

// This will resolve once the authentication has completed
api.authenticate().then(function() {
  // Get the current user and dump the result to the console.
  api.users.get('me').then(console.dir);
});

Dummy flow

The dummy flow can be used when a token should be present in the cache.

var auth = new DummyFlow();
var api = new Mapcreator(auth);

// Manually check if we're logged in
if (api.authenticated) {
    console.log('Found authentication token in cache!');
}

api.authenticate().then(function() {
    // Will only resolve if a token was found
    console.log("We're authenticated");
}).catch(function(err) {
    // This will be called if `api.authenticated` is false
    console.log(err.toString());
});

Nodejs

The library currently only supports the password flow and the dummy flow for nodejs. Other flows might be added in the future.

Password Flow

Make sure to store your secret somewhere safe and to only store the token and never the unencrypted user password.

var clientId = 1; // client id
var secret = ''; // secret
var username = 'user@example.com'; // email is used for authentication
var password = 'Password1!'; // password

var auth = new PasswordFlow(clientId, secret, username, password);
var api = new Mapcreator(auth);

// This will resolve once the authentication has completed
api.authenticate().then(function() {
  // Get the current user and dump the result to the console.
  api.users.get('me').then(console.dir);
});

Dummy flow

The dummy flow can also be used when a token is known.

var auth = new DummyFlow();
var api = new Mapcreator(auth);

var token = {
  token: "eyJ0eXAiOiJKV1...",
  type: "Bearer",
  expires: "Thu, 18 May 2017 14:14:38 GMT"
};

// Set the token
api.auth.token = OAuthToken.fromResponseObject(token);

// Manually check if we're logged in
if (api.authenticated) {
    console.log('Found authentication token in cache!');
}

api.authenticate().then(function() {
    // Will only resolve if a token was found
    console.log("We're authenticated");
}).catch(function(err) {
    // This will be called if `api.authenticated` is false
    console.log(err.toString());
});

Building

Building the api can be done using [yarn] and [webpack]. The result will be placed in the /dist folder. Both the web and nodejs releases are built this way.

yarn install
yarn run build

Building docs

The docs can be built using [esdoc] after which they can be found in the /docs folder.

yarn install
yarn run docs

Development docs can be built by adding "private" to the esdoc.access variable in package.json before building the docs.

Installation

Installation can be done through either npm or yarn.

// Using npm
npm install --save @mapcreator/api

// Using yarn
yarn add @mapcreator/api

After installation the package can be imported as follows:

var m4n = require('@mapcreator/api');

// Do stuff
var auth = new m4n.ImplicitFlow(1);
var api = new m4n.Mapcreator(auth);

or using ES6 import statements:

import {Mapcreator, DummyFlow} from '@mapcreator/api';

// Do stuff
var auth = new DummyFlow();
var api = new Mapcreator(auth);