Node JS (node-fetch library)

Geoapify lets to send multiple API requests within one call by using Batch service. Learn more about the Batch service on the documentation page.

The Batch service based on asynchronous calls. Here is an implementation of asynchronous calls that can be used for Batch requests from a NodeJS project.

node-fetch library

The code sample uses node-fetch library to provide HTTP calls. Run "npm install node-fetch" to install the node-fetch library.

Create a batch job and monitor results

We need 2 types requests: HTTP Post request to create a job and HTTP Get request to monitor the job execution and getting result

  • As we interested in response status by checking the response, we use getBodyAndStatus() that provides both response status and response body.
  • If when the job is accepted (HTTP 202) we start monitor results with getAsyncResult(). To avoid unnecessary calls we set a timeout to 1000ms (60000ms recommended for bigger jobs) and number of maximal attempts.
  • As soon as results are available, the getAsyncResult() promise is resolved.

Code sample

const fetch = require('node-fetch');

var myRouter = function (req, res) {
  var data = { "api": "/v1/geocode/reverse", "params": { "lang": "de", "limit": "3" }, "inputs": [{ "id": "optional-input-id1", "params": { "lat": "51.156397", "lon": "10.875491" } }] };
  var url = `https://api.geoapify.com/v1/batch?apiKey=YOU_API_KEY`;

  fetch(url, {
    method: 'post',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(data)
  })
    .then(getBodyAndStatus)
    .then((result) => {
      if (result.status !== 202) {
        res.json(result);
      } else {
        return getAsyncResult(`${url}&id=${result.body.id}`, 1000, 100).then(queryResult => {
          res.json(queryResult);
        });
      }
    })
    .catch(err => res.json(err));
}

function getBodyAndStatus(response) {
  return response.json().then(responceBody => {
    return {
      status: response.status,
      body: responceBody
    }
  });
}

function getAsyncResult(url, timeout, maxAttempt) {
  return new Promise((resolve, reject) => {
    // start monitoring after timeout
    setTimeout(() => {
      repeatUntilSuccess(resolve, reject, 0)
    }, timeout);
  });

  function repeatUntilSuccess(resolve, reject, attempt) {
    fetch(url)
      .then(getBodyAndStatus)
      .then(result => {
        if (result.status === 200) {
          resolve(result.body);
        } else if (attempt >= maxAttempt) {
          reject("Max amount of attempt achived");
        } else if (result.status === 202) {
            // Check again after timeout
          setTimeout(() => {
            repeatUntilSuccess(resolve, reject, attempt + 1)
          }, timeout);
        } else {
          // Something went wrong
          reject(result.body)
        }
      })
      .catch(err => reject(err));
  };
}