[Qt/C++] WORKING WITH REST API
Published: 2021-07-13 20:51:27

## WHAT ARE APIs?
 API is short for Application Programming Interface. You can think of it as an intermediary between computers or software systems, It provides an environment for those systems to interact with each other, Usually you have a client(your application) which requests information from the server(service) and the API determines how that entire environment will function.

## How is Data passed through APIs?
 The predominant form in which data is passed in an environment leveraging APIs is through **JSON** which stands for **J**avaScript Object Notation which is a light-weight text-based format used for representing structured data based on JavaScript object syntax.

Data in JSON is represented in key - value pairs

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1625826663010/C2mkUMwhn.png)

Those data can be encapsulated in an **array** or **object** form. Data encapsulated in "curly braces" `{}` denote **object-form** while Data encapsulated in "square brackets" `[]` denote **array-form.**

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1625827159782/GfOoQXVb_.png)

`NB : As you can see JSON objects can be nested into one another, the same goes for JSON arrays`

## REST APIs
 If you've been in the software development ecosystem for even a little while, you've most likely heard of REST APIs. REST is short for `Representational State Transfer` which is a software architectural style. A `REST` API an API that follows the **REST** design principles. Unlike some other API models, REST APIs are flexible, user-friendly and easy to work with across multiple programming languages and it has non-strict design principles which is why it's easy to work with.You can read on REST design principles [here](www.ibm.com/cloud/learn/rest-apis).

## Working with REST APIs
 So I've chosen the Qt application framework as the tool which I will use to demonstrate how to work with REST APIs.

## Qt ?
   Qt at it's base is an application framework written in C++ which can be used to develop wide range of cross-platform applications and graphical user interfaces.

I've decided to use the [GitHub](https://docs.github.com/en/rest) REST API for the demonstration on working with REST APIs

First I will create a Project called `GitHub_API` in Qt Creator(the IDE for Qt framework) which inherits the `QMainWindow` base class and add the `network` module in our project file because we will be working with networks in this project.


![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1625830919511/bv7uqDY-D.png)

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1625830832407/QPNwQKK3n.png)

I have designed a simple GUI to use with our API program using Qt Designer

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1625831201694/w5FwgCkts.png)

`NB : The goal of this article is to show how to work with REST APIs in Qt which already assumes you have basic knowledge on how Qt works`
### Important Qt Objects Used
 * `QNetworkAccessManager` - allows our application to send and receive network replies
 * `QNetworkRequest` - contains a request to be sent to a `QNetworkAccessManager` object
 * `QNetworkReply` - embodies a `reply`which is gotten when a request is carried out by `QNetworkAccessManager`

We define a few variables that we will be using in our program:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1625833125705/F5olC0HYZ.png)

* `netManager` - will manage our network requests and replies
* `netReply` - will handle most of the replies we get from the API
* `repoReply` - will handle the replies we get concerning repositories from GitHub
* `dataBuffer` - will contain the data we receive from the API
* `img` - will contain the an image (profile pic)

`We want this program to collect a 'GitHub Username' from the user and then it will request information on the GitHub user(if it exists) through the GitHub API, the API will return the information in form of JSON and the program will make use of that data to display some information through the GUI`


![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1625836487630/5Ziz5H-X-.png)

When the user clicks on the `USERNAME` Button, it should bring up a simple dialog window in which the user would input the username of the GitHub Account

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1625836784237/YJ1Rl64tM.png)

And then when the user inputs the username and clicks on the `ok` button, we first store that username into a variable then we call the `clearValues()` function which resets all the information displayed i.e It resets the program to its default state which is when no information is being displayed.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1625837116120/nmoxUwISm.png)

Those variables that are being cleared are the GUI elements that you see visually in the program when information on a GitHub User is being showed, we want to make sure they're empty before we display info

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1625837276786/fCRdB2tbh.png)

After they're cleared, we create two `QNetworkRequest` variables (req, repoReq) which we will use to request for information on the user and the repositories of the user

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1625837468883/6-vBsqPLo.png)

### How do we request information from the GitHub API
 Open your browser and type in `api.github.com/users/YOUR_USERNAME` and you'll see that it will return information on the GitHub username you put in place of `YOUR_USERNAME` in form of a JSON document. In my case: 

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1625838137952/0KNOo9xcG.png)

So we put in `api.github.com/users/%1` as the `URL` for `req` and `api.github.com/users/%1/repos` for `repoReq`.

`NB : %1 is a placeholder text, it will be replaced by what is passed into the arg method, In this case it will be replaced with the username variable..It's similar to how C's printf() function works`

We then call the `get` method for the `QNetworkAccesManager` object and pass in `req` as the argument. It basically gets the content of what the `req`requests (which in this case is the information of the user in JSON format) and returns it in form of a `QNetworkReply` object.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1625839018799/pTZ3MrBOX.png)
 
Then we store what is returned into the `netReply` variable and then we connect its signals(`readyRead` and `finished`) to our custom slots `readData` and `finishedReading`

 * `readyRead` signal is emitted when there is data to be read from the `netReply` object
 * `finished` signal is emitted when the `netReply` object has finished processing the data it got from the request

So basically `readData` and `finishedReading` is called when the `readyRead` and `finished` signal **for the netReply object is emitted**

```C++
//READ DATA CUSTOM SLOT

void MainWindow::readData()
{
    dataBuffer.append(netReply->readAll());
}

//FINISHED READING CUSTOM SLOT
void MainWindow::finishReading()
{
    if(netReply->error() != QNetworkReply::NoError){
        qDebug() << "Error : " << netReply->errorString();
        QMessageBox::warning(this,"Error",QString("Request[Error] : %1").arg(netReply->errorString()));
    }else{

        //CONVERT THE DATA FROM A JSON DOC TO A JSON OBJECT
        QJsonObject userJsonInfo = QJsonDocument::fromJson(dataBuffer).object();

        //SET USERNAME
        QString login = userJsonInfo.value("login").toString();
        ui->usernameLabel->setText(login);

        // SET DISPLAY NAME
        QString name = userJsonInfo.value("name").toString();
        ui->nameLabel->setText(name);

        //SET BIO
        auto bio = userJsonInfo.value("bio").toString();
        ui->bioEdit->setText(bio);

        //SET FOLLOWER AND FOLLOWING COUNT
        auto follower = userJsonInfo.value("followers").toInt();
        auto following = userJsonInfo.value("following").toInt();
        ui->followerBox->setValue(follower);
        ui->followingBox->setValue(following);

        //SET ACCOUNT TYPE
        QString type = userJsonInfo.value("type").toString();
        ui->typeLabel->setText(type);

        //SET PICTURE
        auto picLink = userJsonInfo.value("avatar_url").toString();
        QNetworkRequest link{QUrl(picLink)};
        netReply = netManager->get(link);
        connect(netReply,&QNetworkReply::finished,this,&MainWindow::setUserImage);
        dataBuffer.clear();
    }
}

void MainWindow::setUserImage()
{
    img->loadFromData(netReply->readAll());
    QPixmap temp = img->scaled(ui->picLabel->size());
    ui->picLabel->setPixmap(temp);
}

```
 * readData - appends the data(JSON document) received from the executed request into the data buffer(`QByteArray` object)

`NB : A QByteArray is used to store raw bytes`

* finishedReading - first checks to see if an error occurred during the request, if there was an error it will display a simple dialog window notifying the user of the error. If there was no error it does the following steps :
   * Convert the bytes of data in the `dataBuffer` to a `JSON` Document and then convert that document to a JSON object named `userJsonInfo`, we can do this because remember when i said JSON objects are denoted using curly-braces `{}`, If you go to the site on your browser you will see that all the data is in fact enclosed in a curly brace which means that we can convert that document straight-away into a JSON object.
   * We then retrieve the username of the GitHub user by calling the `value` method on the `userJsonInfo` variable which expects a "key", it will return the value associated with the key (it will return a `QJsonValue` object which we convert to a `string` by calling it's `toString()` method), We pass in the "login" key and we expect that it would return the `username` value associated with it. Then we pass the value in to the `usernameLabel` Label object which is in our GUI.
  * We repeat the same action multiple times and get the display name, bio, number of followers and followings and the account type
 * We then request for the display picture of the user and connect the `finished` signal to a custom slot `setUserImage` then we clear our buffer because we dont need to store any more data.

 * `setUserImage` - gets the image from the buffer then it scales it down to the size of the `picLabel` object so it can fit in it and then sets the `picLabel` object to show the image by calling `setPixmap()`

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1625841902799/2p1H_izgW.png)

`NB : The dataBuffer object gets cleared after the setUserImage function is completed`

So that's how the user info is retrieved from the API...Then we retrieve the repository info of that user because we haven't done that.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1625842186919/lzq-aCQrS.png)

All the things we explained above happened in those two lines, then the next line of code executes which executes the request for repository info on the user. We connect some more custom slots to the `repoReply` object which will contain the JSON document that has information on the repositories of the GitHub Account.

```C++
void MainWindow::readDataForRepo()
{
    dataBuffer.append(repoReply->readAll());
}

void MainWindow::finishedGettingRepos()
{
    if(repoReply->error() != QNetworkReply::NoError){
        qDebug() << "Error Getting List of Repo: " << netReply->errorString();
        QMessageBox::warning(this,"Error",QString("Request[Error] : %1").arg(netReply->errorString()));
    }else{
        QJsonArray repoInfo = QJsonDocument::fromJson(dataBuffer).array();
        ui->repoBox->setValue(repoInfo.size());
        for(int i{0}; i < ui->repoBox->value(); ++i){
            auto repo = repoInfo.at(i).toObject();
            QString repoName = repo.value("name").toString();
            ui->repoList->addItem(repoName);
        }
    }
}
```
![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1625842900421/G0_WThaaW.png)

* `readDataForRepo` - appends the data(JSON document) into the dataBuffer
* `finishedGettingRepos` - first checks if there was an error with the request and displays the error to the user, if there was no error it creates a JSON document out of the data stored in our dataBuffer and then it converts it into an array because the information in the document is enclosed in square braces which means it's a json array. Then it sets the value of the `repoBox` GUI element to the size of the array(the size of the array would be the number of public repos that user has)

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1625843023080/82Ek3I57g.png)

We then use a `loop`(that is constricted to the length of the array) to go through each item(repo) in the array and get its name and then add it to our `list widget` which is another of our GUI component

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1625853750129/-5Jotuxbe.png)
 
`NB : A QListWidget is used to display items in a .........list form`

And that's all, if we build and run the application we get the GUI i had designed and pass in my GitHub username, we get this:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1625855683855/30k6Cmup_.png)

Aside from the Trash UI, the program works as intended, It successfully interacts with the GitHub API!!

`PS : Here is the `[REPO](https://github.com/TruePadawan/GitHub_API) `which contains this entire program in case you want to view the entire source code`