Get YouTube Channel Details API: Testing Connection
Tags: python, programming, api, programmers
Published: 2023-12-27 16:10:21

Hi,

In our previous post [here](https://dev.to/apiharbor/building-python-package-api-client-for-youtube-channel-details-rapidapi-75g), we built the framework for a Python package that communicates with the API at [The Better YouTube Channel Details](https://rapidapi.com/dataocean/api/the-better-youtube-channel-details) to retrieve YouTube channel details. If you haven't read the previous part, I highly recommend it!

Let's look at the roadmap to see where we are now:

1. [creating the package structure and coding for API communication](https://dev.to/apiharbor/building-python-package-api-client-for-youtube-channel-details-rapidapi-75g).
2. 👉 **we are currently here: testing our solution**
3. [next, we'll publish our work on pypi](https://dev.to/apiharbor/how-to-publish-a-python-package-best-practices-a-youtube-channel-api-example-fin)

Today, we're going to:
- create a function that will connect to the API endpoint 
- test the implementation

Let's get started!

Everyone ready? Camera! ACTION! 🎬

## 📡 Get Youtube Channel details by using `__get_request`

Previously, we implemented the `__get_request` function, which connects to the API and returns data in JSON format. We'll use it to fetch the details of a YouTube channel from the API. 

In the [API documentation](https://rapidapi.com/dataocean/api/the-better-youtube-channel-details), we see that the endpoint is located at:
`https://the-better-youtube-channel-details.p.rapidapi.com/GetChannelDetails`
and it accepts a query parameter `UrlOrUsername`. The endpoint only supports the `GET` method.

With this knowledge of the API, let's write a function:

```python
   async def get_channel_details(self, urlOrUsername) -> any:
        response = await self.__get_request("/GetChannelDetails", urlencode({'urlOrUsername': urlOrUsername}))
        print(response)
```
In the previous post, when we were implementing `__get_request`, we explained why this function would take a `query: dict` parameter. Briefly, it's because `urlencode`, which is used for encoding special characters, returns them in the form of a `dict`.

## 👨‍💻 Let's test the code!

Phew, now we need to check if everything works correctly. We'll use tests for this task. Yes, I know, "test-first". But in such a project, let's be realistic - we write tests (like a BOSS) AFTER coding 😊 We write them only to check if we haven't made any mistakes and if the code works as it should.

We open a file `tests/tests.py`. At the very beginning of the file, we add an import line:

```python
from src.youtube_channel_details_api_client_apiharbor.api_client import YouTubeChannelDetailsApiClient

print("it works!")
```

It's very important! Pay attention to how the `from` construct looks, and then look at the structure of our project:

![Running the tests](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kfi2djmnoajr3f2vmqom.png)

We open `cmd` and navigate to the directory `\libs\youtube_channel_details_api`, then write the command to run the test: `python -m tests.tests`
And we should see the message: "it works!"

When everything works we can move on. Let's write a simple test to check if data fetching from the API works.

```python
api = YouTubeChannelDetailsApiClient("YOUR_RAPID_API_KEY")

async def test_get_channel_details():
  await api.get_channel_details('@MrBeast')

async def main():
  await test_get_channel_details()
  return None

asyncio.run(main())
```

We run it using the previously mentioned command:
`python -m tests.tests` 
in the directory `\libs\youtube_channel_details_api` and here is the result:

```json
{'description': 'OK', 'status': 200, 'data': {'channel_url': 'https://www.youtube.com/channel/UCX6OQ3DkcsbYNE6H8uQQuVA', 'channel_name': 'MrBeast', 'channel_id': 'UCX6OQ3DkcsbYNE6H8uQQuVA', 'joined_date_text': 'Joined Feb 20, 2012', 'channel_country': 'United States', 'rss_url': …
```
🦾 We're the best! Everything works as it should, but we want to make our work easier in other projects. Therefore, we will do mapping from JSON to OBJECT.

## 🔄 Mapping plain JSON to python OBJECT

Let's go back to our `get_channel_details` function.

```json
async def get_channel_details(self, urlOrUsername) -> any:
        response = await self.__get_request("/GetChannelDetails", urlencode({'urlOrUsername': urlOrUsername}))
        print(response)
```

Everything is going well, but we still need to map JSON. We'll use the `pydantic` package for this task. Let's install it by running the command: `pip install pydantic`.

Now let's start coding the mapping. We add a directory `src/schemas`, where we'll put: `base.py`, which will be the main model from which every class in the schema will inherit.

```python
from pydantic import BaseModel

class BaseModelORM(BaseModel):
    class Config:
        from_attributes = True
```

We create a new schema `schemas/channel_details.py`.

```python
from .base import BaseModelORM

class ChannelDetails(BaseModelORM):
    status: int
    description: str
```
So far, we will only map these two fields: `status` and `description`. We need to make sure that everything works. Only then will we map all the fields.

Let's go back to `api_client.py` and import the `ChannelDetails` schema.

```python
from .schemas.channel_details import ChannelDetails
```

and modify the `get_channel_details` function so that it returns a `ChannelDetails` object created from the JSON received from the API.

```python
async def get_channel_details(self, urlOrUsername) -> any:
 response = await self.__get_request("/GetChannelDetails", urlencode({'urlOrUsername': urlOrUsername}))
        return ChannelDetails.model_validate(response)

```

The final step is to modify the `test_get_channel_details` test.

```python
async def test_get_channel_details():
    r = await api.get_channel_details('@MrBeast')
    assert r.status == 200
```

Run `python -m tests.tests` and... nothing appears. That means everything is working! Otherwise, we would have received an error. To confirm this theory, let's change the `assert` in the test to

```python
    assert r.status != 200
```

After running the test, we are greeted with a beautiful error:

```python
assert r.status != 200
AssertionError
```

All that's left for us to do is to complete the mapping for `ChannelDetails`.

![One Eternity Later](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sh033kajl6y8hzv5muq4.png)

Just kidding. We won't be doing this mapping manually; instead, we'll use a tool available at [https://jsontopydantic.com/](https://jsontopydantic.com/). You just need to input your JSON, and the tool will generate the schema for you.

## Recap
Let's summarize what we managed to do today:
- We wrote the `get_channel_details` function, which calls `__get_request` to fetch YouTube channel details.
- We also wrote a test for it to check if everything works OK.
- We implemented mapping from JSON to a Python object.

What will we do next time? Actually, the whole package is ready, and all that's left is to publish it on [Packagist](https://packagist.org/).

Thanks for your time and see you next time!

p.s. I hope you enjoyed the style and examples. If possible, please give a thumbs up, comment, or any kind of reaction! It fuels me for future posts. Follow me to make sure you don't miss anything 🚀