Coding exercise - 5 coins

Welcome to the place to discuss the coding exercise with the top 5 altcoins.

Retrieve the top 5 coins, their tickers and their prices from Coinpaprika. Batch the requests using Promise.all.

Bad solution, wanted to loop the coins:

const node = document.querySelector(".coins");
let list =[];

Promise.all([
axios.get(‘https://api.coinpaprika.com/v1/tickers/btc-bitcoin’),
axios.get(‘https://api.coinpaprika.com/v1/tickers/eth-ethereum’),
axios.get(‘https://api.coinpaprika.com/v1/tickers/usdt-tether’),
axios.get(‘https://api.coinpaprika.com/v1/tickers/xrp-xrp’),
axios.get(‘https://api.coinpaprika.com/v1/tickers/bch-bitcoin-cash’)
]).then(
(coinResponses) => {
const coins = coinResponses
.map(response => `

${response.data.name} (${response.data.symbol}): $${response.data.quotes['USD'].price}

`) .join(''); node.innerHTML = `

    ${coins}
`; });
1 Like

Took longer than expected but that was I forgot Promise.all() takes an array so I was attempting to use spread and it was producing an error.

1 Like

There will be quite a lot of new Coinpaprika users triggered by this course. :slight_smile:

@mayjer, don’t forget to clean up unnecessary console logs.

@andersbraath1, no worries about looping or mapping, both works. No need to go pure functional when the objective of our code is a side-effect in the form of a DOM insertion.

I could not get the loop to work, but you showed it in the solution. This API setup is golden, thank you have been looking for something like this!

Is there a way to increase the number of tickers to more than 10? I get this error: createError.js:16 Uncaught (in promise) Error: Request failed with status code 429.

Too many requests!? If I do:
const COIN_COUNT = 10;
It works.

1 Like

You will get blocked due to querying too many endpoints. This is why it seems Coinpaprika encourages retrieving all coins and filtering in your application.

1 Like

Stoked!

I made the parseInt update work. I must be learning!

handleRefresh = async (event) => {

    // Prevent default action of submitting the form

    event.preventDefault();
    const updatePrice = await this.props.handleRefresh(this.props.ticker);
};

render() {

    return (
            <tr>

                <Td>{this.props.name}</Td>

                <Td>{this.props.ticker}</Td>

                <Td>${parseFloat(Number(this.props.price).toFixed(4))}</Td>

                {this.props.showBalance ? <Td>${this.props.balance}</Td> : null}
2 Likes

I reused the table of the previous exercise and tried to gather axios calls in an array.

I begin to better understand the use of codePen and its render :sweat_smile:

1 Like

I tried to get cute with assigning a variable equal to the id of the top five coins in api.coinpaprika.com/v1/coins and retrieve the name, symbol, and price quotes within api.coinpaprika.com/v1/tickers using the id, but I finally settled on the easier way. Looking forward to getting better and providing a more scaleable solution. Loving the course thus far! Anyway, here’s my code:
https://codepen.io/kapitanon/pen/PoZMpJr

1 Like

1 Like

I separated some concerns. componentDidMount() seemed overloaded with tasks its name does not imply.

class App extends React.Component {
  state = {
      apName: 'Coin Exchange',
      balance: 10000,
      showBalance: true,
      coinData: [],
  };

  getIDs = async () => {
    // Fetch the IDs of first COIN_COUNT items.
    const repsonse = await axios.get('https://api.coinpaprika.com/v1/coins')
    return repsonse.data.slice(0,COIN_COUNT).map(coin => coin.id);
  }

  getCoinData = async(coinIds) => {
    // Retrieve coin data array for given coin id's.
    const tickerUrl = 'https://api.coinpaprika.com/v1/tickers/';
    const promises = coinIds.map(key => axios.get(tickerUrl + key));
    return await Promise.all(promises);
  }

  extractPrices = (coinData) => {
    // Extract prices from given coinData array
    return coinData.map(function(response) {
      const coin = response.data;
      return {
        key:    coin.id,
        name:   coin.name,
        ticker: coin.symbol, 
        balance: 0,
        price:  parseFloat(Number(coin.quotes.USD.price).toFixed(2)),
      };
    });
  }

  loadAllAPIData = async () => {
    // Load API data for all items.
    const coinIds = await this.getIDs();
    const coinData = await this.getCoinData(coinIds);
    const coinPriceData = this.extractPrices(coinData);
    this.setState({ coinData: coinPriceData});
  }

  componentDidMount = async () => {
    // hook for timing.  Do this:
    this.loadAllAPIData();
  };   
1 Like

2 Likes

1 Like

import React from ‘react’;

import ‘./App.css’;
import ExchangeHeader from ‘./components/ExchangeHeader/ExchangeHeader’;
import CoinList from ‘./components/CoinList/CoinList’;
import AccountBalance from ‘./components/AccountBalance/AccountBalance’;
import axios from ‘axios’;

//import {v4 as uuidv4} from ‘uuid’;

const COIN_COUNT = 5;
export default class App extends React.Component {
state = {
balance: 10001,
showBalance : true,
coinData: [
]
}

/**

  • This runs after the component is loaded. it will rerieve the top
  • COIN_COUNT coins from coinpaprika.com (listed by order of ranking).
  • this function makes an REST call to coinpaprika and retrieves the coins.
  • updates the state. It takes a little time to run.
  • change the function to a async function si I could use the await
  • option on axios.get() This way I program syncronously. it does not mater
  • because this code is already blocking in the background and running on
  • a seperate thread.
    */
    componentDidMount = async () => {
    let response = await axios.get(‘https://api.coinpaprika.com/v1/coins’);
    let coinData1 = response.data.slice(0,COIN_COUNT).map(function(coin) {
    return {
    key: coin.id,
    name: coin.name,
    ticker: coin.symbol,
    balance: 0,
    price: 0,
    };
    });
// Notes on how this all works:
// calling promise.all() will execute all the promises in the array passed
// after all that is done you get an array in this case ( coinResponses ) and this
// is passed to the then() part. this is only called once at the end of the promises.
// if there is an error the .then() is not called. 
//

let coinData = [];
Promise.all(  [
  axios.get('https://api.coinpaprika.com/v1/tickers/' + coinData1[0].key),
  axios.get('https://api.coinpaprika.com/v1/tickers/' + coinData1[1].key),
  axios.get('https://api.coinpaprika.com/v1/tickers/' + coinData1[2].key),
  axios.get('https://api.coinpaprika.com/v1/tickers/' + coinData1[3].key),
  axios.get('https://api.coinpaprika.com/v1/tickers/' + coinData1[4].key)
  ]
).then(
  (coinResponses) => {
    console.log( "promis called ", coinResponses);
    // move the responses into coinData array where we can set the state later.
    for( let i = 0; i< coinResponses.length; i++) {
      coinData.push( 
        {  
          key: coinResponses[i].data.id,
          name: coinResponses[i].data.name,
          ticker: coinResponses[i].data.symbol,
          balance: 0,
          price: coinResponses[i].data.quotes.USD.price
      })
    }; //endfor
    this.setState({ coinData});
  } // endThen
); //endPromisAll

}

// update the price, leave all the other things the same
handleRefresh = (valueChangedTicker) => {
const newCoinData = this.state.coinData.map(
function( values) {
let newValues = { …values }; //clone the old values (shallow copy)
if ( valueChangedTicker === newValues.ticker ) {
const randomPercentage = 0.995 + Math.random() * 0.01;
newValues.price *= randomPercentage;
}
return newValues;
});
this.setState({coinData: newCoinData});
}

// handle the clicking of the show balance button.
// we toggle it from true to false or false to true.
handleBalanceShowHide = () => {
let newShowBalance = !this.state.showBalance;
this.setState({showBalance: newShowBalance});
}

render() {
return (


    <div>
    <AccountBalance amount={this.state.balance} showBalance={this.state.showBalance} 
        handleBalanceShowHide= {this.handleBalanceShowHide} />
    </div>
    <CoinList  coinData={this.state.coinData} 
               showBalance={this.state.showBalance}
               handleRefresh={this.handleRefresh} />
  </div>
);

}
}

1 Like
1 Like

https://codepen.io/scrummaciousd/pen/ZEOdNmx

I need to ask, how do you embed the codepen in a forum message?

2 Likes

Hey @Ciaran, hope you are well.

Is quite easy, right bottom corner on codepen editor, you have an “Embed” option, click on it.


Then on the “Copy & Paste Code” box, you have different tabs, select “iframe” then copy the code and paste it here.

If you have any more questions, please let us know so we can help you! :slight_smile:

Carlos Z.

1 Like

https://codepen.io/catalystjesal/pen/YzGPOxy

1 Like

Took longer because i hadn´t axios defined in the beggining

https://codepen.io/traderramos/pen/oNzjbgQ

3 Likes

HTML

<h1>Top 5 Crypto Coins</h1>
<div class = "js-container"> </div>

JS

var node = document.querySelection('.js-container');
var text  = [];
Promise.all([
axios.get('https://api.coinpaprika.com/v1/tickers/btc-bitcoin'),
axios.get('https://api.coinpaprika.com/v1/tickers/eth-ethereum'),
axios.get('https://api.coinpaprika.com/v1/tickers/xrp-xrp'),
axios.get('https://api.coinpaprika.com/v1/tickers/usdt-tether'),
axios.get('https://api.coinpaprika.com/v1/tickers/ltc-litecoin')
]).then((coinResponses)=> {
const coins = coinResponses
.map(response=> '<li>$ {response.data.name} (${response.data.sympol});
${response.data.quotes ['USD'].price} </li>')
.join(' ');
node.innerHTML ='<ol> $ {coins} </ol>';
}
);
2 Likes