1

I am trying to use the Javascript fetch API to access the RouteXL Trip API.

I have the request working in Postman, it's very simple and it works:

Workingin Postman

Now I am trying to replicate that request using the Javascript fetch API but I just can't get it to work. The API is not seeing the 'locations' data. I've tried the same thing in a Node.js server using the Got library and am facing the same problem.

This is what my browser code looks like (I have tried MANY variations):

const url = `https://api.routexl.nl/tour`;
const locations = this.makeLocations(tasks,trip);
const params = {
  skipOptimisation: true,
  locations:locations
}
const request = new Request(url, {
  method: 'POST',
  headers: {
    'Authorization': 'Basic authToken',
    'Content-Type': 'application/x-www-form-urlencoded'
  },
  body: JSON.stringify(params)
})
const response = await fetch(request)
console.info("Response:", response)

The locations data that is being returned from

this.makeLocations(tasks,trip);

is the same data that I have pasted into Postman.

Here is another attempt using FormData:

const form = new FormData();    
const locations = [
      { "address": "Start", "lng": -1.81, "postcode": "B33 8QE", "lat": 52.48, "servicetime": 0 }, 
      { "address": "24631000021902777", "lng": -2.440442, "postcode": "HR8 1PS", "lat": 52.088603, "servicetime": 22 }, 
      { "address": "End", "lng": -1.81, "postcode": "B33 8QE", "lat": 52.48, "servicetime": 0 }
    ]
    form.append("locations", JSON.stringify(locations));
    const request = new Request(url, {
      method: 'POST',
      headers: {
        'Authorization': 'Basic myToken'
      },
      body:form
    })

I have also tried using qs stringify on the locations but still get the same result.

Another attempt (same result) based on Post a x-www-form-urlencoded request from React Native:

const locations = JSON.stringify([
  { "address": "Start", "lng": -1.81, "postcode": "B33 8QE", "lat": 52.48, "servicetime": 0 }, 
  { "address": "24631000021902777", "lng": -2.440442, "postcode": "HR8 1PS", "lat": 52.088603, "servicetime": 22 }, 
  { "address": "End", "lng": -1.81, "postcode": "B33 8QE", "lat": 52.48, "servicetime": 0 }
])
let formBody = [];
formBody.push(encodeURIComponent("locations") + "=" + encodeURIComponent(locations));
formBody.push(encodeURIComponent("skipOptimisation") + "=" + encodeURIComponent(true));
const request = new Request(url, {
  method: 'POST',
  headers: {
    'Authorization': 'Basic myToken'
  },
  body:formBody.join("&")
})
const response = await fetch(request)
kpg
  • 7,644
  • 6
  • 34
  • 67
  • Not tested this, but be aware only the **value** of locations needs to be json. You're making json of all params keys and values in the given example. Also, check the Javascript examples on Github: https://github.com/routexl/RouteXL-API-Connector – RouteXL Jul 01 '20 at 04:01
  • I have to pass a string to 'body', that is why I have to use JSON.stringify. The example on Github uses JQuery, I don't. I would appreciate it if you would test it and post an example in modern Javascript. There is a post in your support forum on the same topic which has not been answered. – kpg Jul 01 '20 at 04:29
  • Correction, I could also pass FormData as the body, so I have tried doing that with a JSON string as the locations parameter but I get the same result. – kpg Jul 01 '20 at 06:28
  • From the duplicate, see [this answer](https://stackoverflow.com/a/53189376/283366). You don't need to set a content-type header if using `URLSearchParams` – Phil Jul 01 '20 at 06:41
  • @kpg We've updated our example on Github to plain Javascript. – RouteXL Jul 01 '20 at 08:47
  • Your content-type header is still wrong. Look closer at the examples in the linked duplicate. – Phil Jul 02 '20 at 21:46

1 Answers1

0

I never had luck using FormData with x-www-form-urlencoded so I used the qs library instead.

Your code would look something like this.

const qs = require('qs')
const url = `https://api.routexl.nl/tour`;
const locations = this.makeLocations(tasks,trip);
const params = qs.stringify({
  skipOptimisation: true,
  locations:locations
})
const request = new Request(url, {
  method: 'POST',
  headers: {
    'Authorization': 'Basic authToken',
    'Content-Type': 'application/x-www-form-urlencoded'
  },
  body: params
})
const response = await fetch(request)
console.info("Response:", response)

Hope this helps.

kpg
  • 7,644
  • 6
  • 34
  • 67
Michael
  • 1,454
  • 3
  • 19
  • 45
  • Thanks.The qs library is one of the many other things I've tried :(. The problem seems to be something to do with the escape characters. The poorly documented RouteXL API seems to be expecting a JSON string for 'locations', but when I stringify the 'body' parameter to the 'fetch' request, the escape characters are duplicated. Strangely enough, I did (eventually) succeed in using this same API a couple of years ago from another language (Zoho's Deluge) by assembling a kind of string representation of an array. The code is so hideous that I'm having difficulty translating it into Javascript. – kpg Jul 01 '20 at 04:39
  • `'Content-type': 'application/x-www-form-urlencoded'` – Phil Jul 01 '20 at 06:39
  • @Phil I don't think this is really a duplicate of the question you referenced, although I did find the answer in that question. There are three issues: the other post is related to React which I'm not using; the other post has twelve answers, the reason I found the answer there is because you led me to the specific answe, I had already seen the post but didn't find the answer on my own; this post specifically relates to RouteXL which I have done battle with twice at great cost. I would like to add my actual working solution here, so have voted to reopen the question. – kpg Jul 03 '20 at 06:38