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