C++ Json parsing issue throws Unhandled Exception

413 views Asked by At

`` I am trying to order a vector of coins to be traded in order of their market cap rank. it compiles perfectly and runs but throws an error 3 at runtime. code found below.

debugging: json.hpp Throws unhandled exception Unhandled exception at 0x0000500000000000 in MyProgram.exe: Microsoft C++ exception: nlohmann::json_abi_v3_11_2::detail::type_error at memory location 0x000000E000000000.

JSON_THROW(type_error::create(302, concat("type must be number, but is ", j.type_name()), &j));

Desired Outcome: orders my vector of coins from highest market cap to lowest after requesting market cap rank from api. and lists vector to terminal.

trading.h

#ifndef TRADING_H
#define TRADING_H

#include <string>
#include <iostream>
#include <vector>

using namespace std;

class trading{
    private:
        vector<string> coins;

    public:
        trading();
        void order();
        void listOrder();

};

trading.cpp

#include <string>
#include <iostream>
#include <vector>
#include <cpr/cpr.h>
#include <nlohmann/json.hpp>
#include "trading.h"

// for convenience
using json = nlohmann::json;

using namespace cpr;
using namespace std;


//orders the coins from 1-20 ascending order
void trading::order(){
    //variables
    vector<string> coinsCopy;
    int rankOrder = 0;

    //order coing by market cap
    string base = "https://api.coingecko.com/api/v3/search?query=";
    string id;

    //makes a copy of coins
    for (int k = 0; k < coins.size(); k++) {
        coinsCopy.push_back(coins[k]);
    }


    for (int i = 0; i < coins.size(); i++) {
        //loop variables
        string id = coins[i];
        auto search = Get(Url{ base + id });
        json data = json::parse(search.text);

        //collects rank 
        for (json& item : data["coins"]) {
            rankOrder = item["market_cap_rank"];
            if (rankOrder > coins.size()) {
                rankOrder = coins.size();
            }
            break;
        }

        //updates coins to correct order in coins copy
        coinsCopy.at(rankOrder) = coins[i];
    }

    //updates main coin vector with correct rank order
    for (int ii = 0; ii < coins.size(); ii++) {
        coins.at(rankOrder) = coinsCopy[ii];
    }
}

void trading::listOrder() {
    for (int j = 0; j < coins.size(); j++) {
        cout << "Coin Ranked # " << j << ": " << coins[j] << endl;
    }
}

Main.cpp

#include <cpr/cpr.h>
#include <iostream>
#include <nlohmann/json.hpp>
#include <string>
#include <vector>
#include "trading.h"

// for convenience
using json = nlohmann::json;

using namespace cpr;
using namespace std;


int main() {
    
    trading trade;

    
    trade.order();
    trade.listOrder();
    
}

sample of JSON FILE

{"coins":[{"id":"bitcoin","name":"Bitcoin","api_symbol":"bitcoin","symbol":"BTC","market_cap_rank":1,"thumb":"https://assets.coingecko.com/coins/images/1/thumb/bitcoin.png","large":"https://assets.coingecko.com/coins/images/1/large/bitcoin.png"},

Coins Vector

Coin Ranked # 0: bitcoin
Coin Ranked # 1: ethereum
Coin Ranked # 2: tether
Coin Ranked # 3: binancecoin
Coin Ranked # 4: usd-coin
Coin Ranked # 5: binance-usd
Coin Ranked # 6: ripple
Coin Ranked # 7: dogecoin
Coin Ranked # 8: cardano
Coin Ranked # 9: matic-network
Coin Ranked # 10: polkadot
Coin Ranked # 11: staked-ether
Coin Ranked # 12: shiba-inu
Coin Ranked # 13: okb
Coin Ranked # 14: litecoin
Coin Ranked # 15: dai
Coin Ranked # 16: tron
Coin Ranked # 17: solana
Coin Ranked # 18: uniswap
Coin Ranked # 19: avalanche-2
1

There are 1 answers

4
panik On

There are numerous tokens having null "market_cap_rank", e.g. "xi-token" at the moment. The library fails to convert null rank to an integer value. The problem is caused by the lack of data validation.

Also note that the code

vector<string> coinsCopy;
//...
for (int k = 0; k < coins.size(); k++) {
    coinsCopy.push_back(coins[k]);
}
//...
if (rankOrder > coins.size()) {
    rankOrder = coins.size();
}    
//...
coinsCopy.at(rankOrder) = coins[i];

throws depending on the actual rankOrder value.

Edits

I feel the need to make my answer more elaborate by adding missing details.

By means of the following Python3 script, we obtain the top 20 coins sorted in the ascending order by "market_cap_rank".

import requests
import json
import operator

def receive_coins():
    resp = requests.get(r'https://api.coingecko.com/api/v3/search')
    with open("response", 'w', encoding = 'utf-8') as response:
        response.write(resp.text)
        
def get_top20():    
    with open('response', 'r', encoding = 'utf-8') as response:
        jresp = json.load(response)
        coinlist = [
            (coin['id'], coin['market_cap_rank']) for coin in jresp['coins'] if coin['market_cap_rank']
        ]        
        return sorted(coinlist, key=operator.itemgetter(1))[:20]
    return []

print(get_top20())

They are

[('bitcoin', 1), ('ethereum', 2), ('tether', 3), ('binancecoin', 4), ('usd-coin', 5), ('binance-usd', 6), ('ripple', 7), ('dogecoin', 8), ('cardano', 9), ('matic-network', 10), ('polkadot', 11), ('staked-ether', 12), ('litecoin', 13), ('shiba-inu', 14), ('okb', 15), ('dai', 16), ('solana', 17), ('tron', 18), ('uniswap', 19), ('avalanche-2', 20)]

The "market_cap_rank" values span from 1 to 20, not from 0 to 19. From the question statement, we infer that there are precisely 20 elements in the coinsCopy array, which proves my second point that the line coinsCopy.at(rankOrder) = coins[i]; throws an exception.

Another issue stems from the lack of data validation. The line auto search = Get(Url{ base + id }); repeats 20 times with negligible intervals. This may cause a site protection triggered, which results with receiving a site-specific unexpected response. The response contents are not validated in any case.