ETHan
ETHan

Reputation: 207

Can not make XMLHttpRequest to 3 separate API urls

Before I start, here is the API. Super simple: https://www.cryptonator.com/api

To note, I have worked with api before, but i used a await async function, but for some reason I couldn't get that to work....but I found a tutorial for doing this with XML http request, so I decided to just move forwards doing it in XML because I was able to make a simple Bitcoin ticker.

I am building a simple widget to display the prices of Bitcoin, Litecoin, and Ethereum using the cryptonator API. Like I said above, I made a bitcoin ticker with the first function ( see code below ), and it works great. However, I am having issues trying to get 3 different currencies.

Here is what I am trying to do.

var url = "https://api.cryptonator.com/api/ticker/btc-usd";

xmlhttp.onreadystatechange = function() {
  if (this.readyState == 4 && this.status == 200) {
    var json = JSON.parse(this.responseText);
    parseJson(json);
  }
};

xmlhttp.open("GET", url, true);
xmlhttp.send();

function parseJson(json) {

  var usdValue = json["ticker"]["price"];
  document.getElementById("data").innerHTML = usdValue;

  var usdValue = usdValue.replace(/[^\d.\-]/g, "");
  var usd = parseFloat(usdValue);
  document.getElementById("data").innerHTML = "$ " + usd.toFixed(2);
}



// 
// 

var xmlhttp2 = new XMLHttpRequest();
var url2 = "https://api.cryptonator.com/api/ticker/ltc-usd";

xmlhttp2.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      var json = JSON.parse(this.responseText);
      parseJson(json);
    }
  };

  xmlhttp2.open("GET", url2, true);
  xmlhttp2.send();

  function parseJson(json) {

    var LTCusdValue = json["ticker"]["price"];
    // document.getElementById("data2").innerHTML = LTCusdValue;

    var LTCusdValue = LTCusdValue.replace(/[^\d.\-]/g, "");
    var LTCusd = parseFloat(LTCusdValue);
    document.getElementById("data2").innerHTML = "$ " + LTCusd.toFixed(2);
  }


//   
// 
// 

var xmlhttp3 = new XMLHttpRequest();
var url3 = "https://api.cryptonator.com/api/ticker/eth-usd";

xmlhttp3.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      var json = JSON.parse(this.responseText);
      parseJson(json);
    }
  };

  xmlhttp3.open("GET", url3, true);
  xmlhttp3.send();

  function parseJson(json) {

    var ETHusdValue = json["ticker"]["price"];
    // document.getElementById("data3").innerHTML = ETHusdValue;

    var ETHusdValue = ETHusdValue.replace(/[^\d.\-]/g, "");
    var ETHusd = parseFloat(ETHusdValue);
    document.getElementById("data3").innerHTML = "$ " + ETHusd.toFixed(2);
  }

As you can see, I am trying to make 3 request to 3 different APis, but it isn't working. If I comment out all but one of these functions, it works fine. My issues comes when i try to use all 3 at once. If i use Bitcoin and Litecoin only, it will actually work, but will just break again once I try to use the 3rd function ( to get ethereum price ).

Upvotes: 1

Views: 154

Answers (3)

Matt Oestreich
Matt Oestreich

Reputation: 8538

You should be able to write an async wrapper function for this using a Promise.. This will allow you to use async/await with XHR..

To make using XHR a lot easier, you can use the built in fetch API.. According to this, most browsers support fetch.. All in all, I prefer using fetch over axios, XHR, etc.. but since you specifically asked about XHR, that is how I answered.

If you did not want to await each response, you can do something like this:

// basic XHR wrapper function for 'get'
function getXHR(url) {
  return new Promise(function(resolve, reject) {
    const xhr = new XMLHttpRequest();
    xhr.open("get", url, true);
    xhr.onreadystatechange = function() {
      if (this.readyState == 4 && this.status == 200) {
        this.status == 200
          ? resolve(this.responseText)
          : reject(this.status);
      }
    };
    xhr.send();
  });
}

const ethElement = document.getElementById("eth");
const bcElement = document.getElementById("bc");
const lcElement = document.getElementById("lc");

// etherium
getXHR("https://api.cryptonator.com/api/ticker/eth-usd")
  .then(eth => {
    // Can turn into JSON like this:
    //const ethJson = JSON.parse(eth);
    ethElement.innerHTML = eth;
  })

// bitcoin
getXHR("https://api.cryptonator.com/api/ticker/btc-usd")
  .then(bc => {
    // Can turn into JSON like this:
    //const bcJson = JSON.parse(bc);
    bcElement.innerHTML = bc; 
  })

// litecoin
getXHR("https://api.cryptonator.com/api/ticker/ltc-usd")
  .then(lc => {
    // Can turn into JSON like this:
    //const lcJson = JSON.parse(lc);
    lcElement.innerHTML = lc;  
  })
<h1>eth:</h1>
<pre id="eth"></pre>
<h1>bc:</h1>
<pre id="bc"></pre>
<h1>litecoin:</h1>
<pre id="lc"></pre>

I have created the following demo to show you how to accomplish this using async/await:

Init(); // call 'main' function

// basic XHR wrapper function for 'get'
function getXHR(url) {
  return new Promise(function(resolve, reject) {
    const xhr = new XMLHttpRequest();
    xhr.open("get", url, true);
    xhr.onreadystatechange = function() {
      if (this.readyState == 4 && this.status == 200) {
        this.status == 200
          ? resolve(this.responseText)
          : reject(this.status);
      }
    };
    xhr.send();
  });
}

// "Main" function
async function Init() {
  const ethElement = document.getElementById("eth");
  const bcElement = document.getElementById("bc");
  const lcElement = document.getElementById("lc");

  // etherium
  const eth = await getXHR("https://api.cryptonator.com/api/ticker/eth-usd");
  const ethJson = JSON.parse(eth);
  ethElement.innerHTML = ethJson.ticker.price + " " + ethJson.ticker.target;
  
  // bitcoin
  const bc = await getXHR("https://api.cryptonator.com/api/ticker/btc-usd");
  const bcJson = JSON.parse(bc);
  bcElement.innerHTML = bcJson.ticker.price + " " + bcJson.ticker.target;
  
  // litecoin
  const lc = await getXHR("https://api.cryptonator.com/api/ticker/ltc-usd");
  const lcJson = JSON.parse(lc);
  lcElement.innerHTML = lcJson.ticker.price + " " + lcJson.ticker.target;
}
div h1,
div p {
    display: inline;
    vertical-align: top;
    font-family: 'Open Sans', sans-serif;
    line-height: 38px;
}
<div>
  <h1>eth:</h1>
  <p id="eth"></p>
</div>
<div>
  <h1>btc:</h1>
  <p id="bc"></p>
</div>
<div>
  <h1>ltc:</h1>
  <p id="lc"></p>
</div>

Upvotes: 1

Emiel Zuurbier
Emiel Zuurbier

Reputation: 20954

The parseJson function is defined three times. This means that every time you write the function it will overwrite the previous definition. So in your case only the last parseJson function will be used for all three requests. You could do a couple of things.

Write three different variations. (Bad practice)

Though this would be the less favorable of the options. It will require you to have repeated code copied multiple times. This can be done more efficiently.

function parseJson1(json) {
  ...
}

function parseJson2(json) {
  ...
}

function parseJson3(json) {
  ...
}

Add an argument to the function. (Good practice)

Give the parseJson function a second argument that selects the element to output the value. This should be the id of the element you'll want to select.
This is the better solution because it only requires you to write a function once and call it multiple times accounting for the variations.

function parseJson(json, id) {
  var output = document.getElementById(id); // Select the element based on the id.
  if (output === null) { // If element is not found, stop the function.
    return;
  }
  var price = json["ticker"]["price"];
  var usdValue = price.replace(/[^\d.\-]/g, "");
  var usd = parseFloat(usdValue);
  output.innerHTML = "$ " + usd.toFixed(2);
}

The last technique is applicable to the rest of your code. Be aware of repeating yourself. You'll write much cleaner and better code when you only have to write something once.

Upvotes: 1

Chumpocomon
Chumpocomon

Reputation: 733

If I understood you well you can create a method for all cryptos and avoid repeting the same code. If you run the example below you will be able to see all cryptos and also it's easy to add new ones:

const URL = 'https://api.cryptonator.com/api/ticker/'
const cryptos = ['btc', 'ltc', 'eth']

cryptos.map(crypto => {
  fetch(`${URL}${crypto}-usd`)
    .then(data => data.json())
    .then(({ ticker: { base, price } }) => console.log(`${base}: ${(+price).toFixed(2)}`))
})

We are using fetch that is modern XHR. Hope this help.

Upvotes: 1

Related Questions