'Problem using IMF data API for a large number of countries

I am trying to download national account data from the API of the International Financial Statistics from the International Monetary Fund.

I don't have any trouble with downloading a few selected countries. As you can check in the following code, I am able to turn some json from the API into a pandas dataframe.

import requests
import pandas as pd

# Nominal domestic variables
dcn_sa = [
    'NINV_SA_XDC',
    'NGDP_D_SA_IX', 
    'NGDP_SA_XDC', 
    'NCPHI_SA_XDC',
    'NCPHN_SA_XDC',
    'NCGG_SA_XDC',
    'NFI_SA_XDC',
    'NX_SA_XDC',
    'NM_SA_XDC'
]
# A bunch of countries
countries = [
    'MX',
    'FR',
    'US',
    'GB'
]

# API calling
base = 'http://dataservices.imf.org/REST/SDMX_JSON.svc/CompactData/IFS/'

period = 'Q'
#countries = codes['Alpha2'].values
time = '?startPeriod=1960&endPeriod=2021'

# Get data from the above URL using the requests package
url = f"{base}{period}.{'+'.join(countries)}.{'+'.join(dcn_sa)}.{time}"
rq = requests.get(url)

response = rq.json()

series = response['CompactData']['DataSet']['Series']

N = len(series)

temp_imf = pd.DataFrame()
dum_df = pd.DataFrame()
for n in range(0, N-1):
    temp_dic = series[n].get('Obs')
    temp_df = pd.DataFrame.from_dict(
        temp_dic
        ).rename(
            columns = {
            '@OBS_VALUE':'Value',
            }
        )
    temp_df['Code'] = series[n].get('@REF_AREA')
    temp_df['Variable'] = series[n].get('@INDICATOR')
    temp_df['Period'] = pd.to_datetime(
            [row.replace('-', '') for row in temp_df['@TIME_PERIOD']]
        )
    temp_imf = temp_imf.append(temp_df)
    
imf = pd.pivot(
    temp_imf,
    values='Value', 
    index=['Code', 'Period'],
    columns='Variable'
)

Nevertheless, as I increase de selection of countries to, for example:

countries = [
    'AF', 'AX', 'AL', 'DZ', 'AS', 'AD', 'AO',
    'AI', 'AQ', 'AG', 'AR', 'AM', 'AW', 'AU',
    'AT', 'AZ', 'BS', 'BH', 'BD', 'BB', 'BY',
    'BE', 'BZ', 'BJ', 'BM', 'BT', 'BO', 'BQ',
    'BA', 'BW', 'BV', 'BR', 'IO', 'BN', 'BG',
    'BF', 'BI', 'CV', 'KH', 'CM', 'CA', 'KY',
    'CF', 'TD', 'CL', 'CN', 'CX', 'CC', 'CO',
    'KM', 'CD', 'CG', 'CK', 'CR', 'CI', 'HR',
    'CU', 'CW', 'CY', 'CZ', 'DK', 'DJ', 'DM',
    'DO', 'EC', 'EG', 'SV', 'GQ', 'ER', 'EE',
    'SZ', 'ET', 'FK', 'FO', 'FJ', 'FI', 'FR',
    'GF', 'PF', 'TF', 'GA', 'GM', 'GE', 'DE', 
    'GH', 'GI', 'GR', 'GL', 'GD', 'GP', 'GU',
    'GT', 'GG', 'GN', 'GW', 'GY', 'HT', 'HM',
    'VA', 'HN', 'HK', 'HU', 'IS', 'IN', 'ID'
]

I get the following error

JSONDecodeError: Expecting value: line 1 column 1 (char 0)

I thought that, perhaps empty elements of the json files could be causing trouble so I re-wrote previous code, but iterating country by country

base = 'http://dataservices.imf.org/REST/SDMX_JSON.svc/CompactData/IFS/'
period = 'Q'
time = '?startPeriod=1960&endPeriod=2021'
countries = codes['Alpha2']
temp_imf = pd.DataFrame()
for cont in countries:
    url = f"{base}{period}.{cont}.{'+'.join(dcn_sa)}.{time}"
    rq = requests.get(url)
    if rq == 200:
        response = rq.json()
        series = response['CompactData']['DataSet']['Series']
        N = len(series)
        for n in range(0, N-1):
            temp_dic = series[n].get('Obs')
            temp_df = pd.DataFrame.from_dict(
                temp_dic
            ).rename(
                columns = {
                '@OBS_VALUE':'Value',
            }
            )
            temp_df['Code'] = series[n].get('@REF_AREA')
            temp_df['Variable'] = series[n].get('@INDICATOR')
            temp_df['Period'] = pd.to_datetime(
                [row.replace('-', '') for row in temp_df['@TIME_PERIOD']]
            )
            temp_imf = temp_imf.append(temp_df)
        print(response)
   # print([cont, rq])
        
imf = pd.pivot(
    temp_imf,
    values='Value', 
    index=['Code', 'Period'],
    columns='Variable'
)

but no dataframe is created as when I select only a few countries.

My question is how to avoid these errors and write some code that can handle all the countries.

I hope you can help.

Thanks



Solution 1:[1]

I have also seen issues with this API. In that you give the same inputs , but it will error out sometimes , you can handle the request code. But have also seen it work , but there be no data , so you need to resolve if the series is there. On the documentation is says there are limits on how many requests can be made in given time. So introducing a pause might also help

makeRequest = requests.get(url)
if makeRequest.status_code == 200:
     Data = makeRequest.json()
     # Call was a success
     # Look to see if you have a series
     if 'Series' in Data['CompactData']['DataSet']:
           #### You Got Some Data 
     import time
     time.sleep(1)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1