World Bank API in C#

by Cyrus Hartwin Gomes

See the World Bank API documentation

These recipe examples were tested on July 25, 2023

Setup#

First, install the CURL and jq package by typing the following command in the terminal:

!sudo apt install curl jq libcurl4-openssl-dev

Then, we set a directory where we want the WorldBank directory for our projects to be created:

!mkdir World_Bank

Finally, we change the directory to the folder we created:

%cd World_Bank

1. Get list of country iso2Codes and names#

For obtaining data from the World Bank API, it is helpful to first obtain a list of country codes and names.

We initialize a folder for the current project that we are working on. And then change to that directory

!mkdir iso2Codes_names
%cd iso2Codes_names

Then we utilize the %%file command to create the following makefile which will compile our program and create an executable.

%%file makefile

# Set the variable CC to gcc, which is used to build the program
CC=gcc

# Enable debugging information and enable all compiler warnings
CFLAGS=-g -Wall

# Set the bin variable as the name of the binary file we are creating
BIN=iso2Codes

# Create the binary file with the name we put
all: $(BIN)

# Map any file ending in .c to a binary executable. 
# "$<" represents the .c file and "$@" represents the target binary executable
%: %.c

	# Compile the .c file using the gcc compiler with the CFLAGS and links 
	# resulting binary with the CURL library
	$(CC) $(CFLAGS) $< -o $@ -lcurl

# Clean target which removes specific files
clean:

	# Remove the binary file and an ".dSYM" (debug symbols for debugging) directories
	# the RM command used -r to remove directories and -f to force delete
	$(RM) -rf $(BIN) *.dSYM

The command is used again to create our .c file which contains the code for the program

%%file iso2Codes.c

#include <curl/curl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* CURL program that retrieves JSON data from the World Bank API */

int main (int argc, char* argv[]) {
    
    // If arguments are invalid then return
    if (argc > 1) {                                                                                      
        printf("Error. Please try again correctly.\n");
        return -1;
    }

    // Initialize the CURL HTTP connection
    CURL *curl = curl_easy_init();

    // Bits of the url that are joined together later                                                                      
    char api[] = "https://api.worldbank.org/v2/";                            
    char url[1000];
    char label[] = "country/?format=json&per_page=500";

    // Check if CURL initialization is a success or not
    if (!curl) {                                                                                         
        fprintf(stderr, "init failed\n");
        return EXIT_FAILURE;
    }
        
    // Combine all the bits to produce a functioning url
    sprintf(url, "%s%s", api, label);                                             
                                          
    // Set the url to which the HTTP request will be sent to
    // First parameter is for the initialized curl HTTP request, second for the option to be set, and third for the value to be set
    curl_easy_setopt(curl, CURLOPT_URL, url);

    // If result is not retrieved then output error
    CURLcode result = curl_easy_perform(curl);

    // If result is not retrieved then output error
    if (result != CURLE_OK) {                                                                            
        fprintf(stderr, "download problem: %s\n", curl_easy_strerror(result));
    }

    // Deallocate memory for the CURL connection
    curl_easy_cleanup(curl);                                                                            
    return EXIT_SUCCESS;
}

The folowing program is run, and an executable is created after using the following command:

!make

To output the data from the WOrld Bank API, we enter the following command:

!./iso2Codes | jq '.[1][0]'
{
  "id": "ABW",
  "iso2Code": "AW",
  "name": "Aruba",
  "region": {
    "id": "LCN",
    "iso2code": "ZJ",
    "value": "Latin America & Caribbean "
  },
  "adminregion": {
    "id": "",
    "iso2code": "",
    "value": ""
  },
  "incomeLevel": {
    "id": "HIC",
    "iso2code": "XD",
    "value": "High income"
  },
  "lendingType": {
    "id": "LNX",
    "iso2code": "XX",
    "value": "Not classified"
  },
  "capitalCity": "Oranjestad",
  "longitude": "-70.0167",
  "latitude": "12.5167"
}
!./iso2Codes | jq '.[1][] | .iso2Code + ": " + .name'

2. Compile a Custom Indicator Dataset#

There are many availabe indicators: https://data.worldbank.org/indicator

We wll select either of the three indicators for this example:

  1. Scientific and Technical Journal Article Data = IP.JRN.ARTC.SC

  2. Patent Applications, residents = IP.PAT.RESD

  3. GDP per capita (current US$) Code = NY.GDP.PCAP.CD

Note that these three selected indictaors have a CC-BY 4.0 license We will compile this indicator data for the United States (US) and United Kingdom (GB)

We change the directory of the World_Bank folder to create a new one for our project

%cd ..

We set a directory where we want the WorldBank directory for the custom indicator project

!mkdir Custom_indicator

Then we change the directory to the folder we created

%cd Custom_indicator

Then we utilize the %%file command to create the following makefile which will compile our program and create an executable.

%%file makefile

# Set the variable CC to gcc, which is used to build the program
CC=gcc

# Enable debugging information and enable all compiler warnings
CFLAGS=-g -Wall

# Set the bin variable as the name of the binary file we are creating
BIN=custom_indicator

# Create the binary file with the name we put
all: $(BIN)

# Map any file ending in .c to a binary executable. 
# "$<" represents the .c file and "$@" represents the target binary executable
%: %.c

	# Compile the .c file using the gcc compiler with the CFLAGS and links 
	# resulting binary with the CURL library
	$(CC) $(CFLAGS) $< -o $@ -lcurl

# Clean target which removes specific files
clean:

	# Removes the binary file and an ".dSYM" (debug symbols for debugging) directories
	# the RM command used -r to remove directories and -f to force delete
	$(RM) -rf $(BIN) *.dSYM

The command is used again to create our .c file which contains the code for the program

%%file custom_indicator.c

#include <curl/curl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*CURL program that retrieves JSON data from the World Bank API
This program allows custom indicator data set to be used along with the country specified*/


/* We are going to be inputting the custom indicator and country like this: ./custom_indicator -c "UK" -i "IP.JRN.ARTC.SC"
If the arguments are missing then we use the default: "US" "IP.JRN.ARTC.SC" */

int main (int argc, char* argv[]) {
    
    // If arguments are invalid then return
    if (argc > 5) {                                                                                      
        printf("Error. Please try again correctly.\n");
        return -1;
    }

    // Default country and indicator codes
    char country[10] = {};
    char indicator[100] = {}; 

    // If there is ./custom_indiactor -c/-i
    if ((argc == 1) || ((argc == 2) && ((strcmp(argv[1], "-c")==0) || (strcmp(argv[1], "-i")==0)))) {
        //these arguments run the default parameters and keeps the codes as they are
        strcat(country,"US");
        strcat(indicator, "IP.JRN.ARTC.SC");
    }

    // If there is ./custom indicator -c "UK"
    else if ((argc == 3) && (strcmp(argv[1], "-c")==0)) {
        // Only the country code is changed
        strcat(country,argv[2]);
        strcat(indicator, "IP.JRN.ARTC.SC");
    }

    // If there is ./custom indicator -c "UK" -i
    else if ((argc == 4) && (strcmp(argv[1], "-c")==0) && (strcmp(argv[3], "-i")==0)) {
        // Only the country code is changed
        strcat(country,argv[2]);
        strcat(indicator, "IP.JRN.ARTC.SC");
    }

    // If there is ./custom indicator -c "UK" -i "IP.JRN.ARTC.SC"
    else if ((argc == 5) && (strcmp(argv[1], "-c")==0) && (strcmp(argv[3], "-i")==0)) {
        // Both the country and indicator codes are changed
        strcat(country,argv[2]);
        strcat(indicator, argv[4]);
    }

    // If there is ./custom indicator -i "IP.JRN.ARTC.SC"
    else if ((argc == 3) && (strcmp(argv[1], "-i")==0)) {
        // Only the indicator code is changed
        strcat(country,"US");
        strcat(indicator, argv[2]);
    }

    // If there is ./custom indicator -i "IP.JRN.ARTC.SC" -c
    else if ((argc == 4) && (strcmp(argv[1], "-i")==0) && (strcmp(argv[3], "-c")==0)) {
        // Only the indicator code is changed
        strcat(country,"US");
        strcat(indicator, argv[2]);
    }

    // If there is ./custom indicator -i "IP.JRN.ARTC.SC" -c "UK" 
    else if ((argc == 5) && (strcmp(argv[1], "-i")==0) && (strcmp(argv[3], "-c")==0)) {
        // Both the indicator and country codes are changed
        strcat(country,argv[4]);
        strcat(indicator, argv[2]);
    }

    else{
        printf("usage: ./custom_indicator [-i] indicator [-c] country\n\n");
        printf("the custom_indicator program is used to retrieve json data from the World Bank API\n\n");
        printf("optional arguments\n");
        printf("\t -i indicator    optional custom indicator code; default is 'IP.JRN.ARTC.SC', see: https://data.worldbank.org/indicator\n");
        printf("\t -c country      optional custom country code; default is 'US'\n");
        return -1;
    }

    // Initialize the CURL HTTP connection
    CURL *curl = curl_easy_init();

    // Bits of the url that are joined together later
    char api[] = "https://api.worldbank.org/v2/";                                                                     
    char type1[] = "country/";
    char type2[] = "/indicator/";                           
    char url[1000];
    char label[] = "/?format=json&per_page=500";

    // Check if CURL initialization is a success or not
    if (!curl) {                                                                                         
        fprintf(stderr, "init failed\n");
        return EXIT_FAILURE;
    }
        
    // Combine all the bits to produce a functioning url
    sprintf(url, "%s%s%s%s%s%s", api, type1 , country, type2, indicator, label);                                             
                                          
    // Set the url to which the HTTP request will be sent to
    // First parameter is for the initialized curl HTTP request, second for the option to be set, and third for the value to be set
    curl_easy_setopt(curl, CURLOPT_URL, url);

    // If result is not retrieved then output error
    CURLcode result = curl_easy_perform(curl);

    // If result is not retrieved then output error
    if (result != CURLE_OK) {                                                                            
        fprintf(stderr, "download problem: %s\n", curl_easy_strerror(result));
    }

    // Deallocate memory for the CURL connection
    curl_easy_cleanup(curl);                                                                            
    return EXIT_SUCCESS;
}
!make

To output the data from the World Bank API with the default indicator and country (IP.JRN.ARTC.SC, US), we enter the following command:

!./custom_indicator | jq '.[1][] | "\(.date)':' \(.value)"' | head -n 10
"2022: null"
"2021: null"
"2020: 455855.57"
"2019: 438020.45"
"2018: 435033.88"
"2017: 430198.17"
"2016: 428476.45"
"2015: 428203.78"
"2014: 428140.59"
"2013: 426596.66"

To output the data from the World Bank API with the custom indicator and country, we enter the following command:

!./custom_indicator -i 'NY.GDP.PCAP.CD' -c 'GB' | jq '.[1][] | "\(.date)':' \(.value)"' | head -n 10
"2022: 45850.4261222629"
"2021: 46585.8975644567"
"2020: 40318.4169225055"
"2019: 42747.080460496"
"2018: 43306.3083049317"
"2017: 40622.6893883232"
"2016: 41146.0773555246"
"2015: 45071.0743234873"
"2014: 47447.5889322667"
"2013: 43449.0917173139"

To compile a custom indicator dataset we need to have parse the data into a single .txt file

We enter the following command, to output first indicator data to the .txt file:

!./custom_indicator -i 'NY.GDP.PCAP.CD' -c 'US' | jq '.[1][] | "\(.date)':' \(.value)"' > output1.txt

We do the same for the 2nd and the 3rd indicator data:

!./custom_indicator -i 'IP.JRN.ARTC.SC' -c 'US' | jq '.[1][] | "\(.date)':' \(.value)"' > output2.txt
!./custom_indicator -i 'IP.PAT.RESD' -c 'US' | jq '.[1][] | "\(.date)':' \(.value)"' > output3.txt

We then join the data together in different columns and output it to the specified .txt file:

!join output1.txt output2.txt > output12.txt

The same is done to create the final combined data set:

!join output12.txt output3.txt > output_combined.txt

We then remove the " and : to create the custom data set

!cat output_combined.txt | tr -d '",:' | head -5
2022 76398.5917422054 null null
2021 70219.472454115 null null
2020 63528.6343027508 455855.57 269586
2019 65120.3946628653 438020.45 285113
2018 62823.309438197 435033.88 285095