Hi,
In our previous post here, we built the framework for a Python package that communicates with the API at 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:
- creating the package structure and coding for API communication.
- 👉 we are currently here: testing our solution
- next, we'll publish our work on pypi
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, 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:
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:
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:
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.
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:
{'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.
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.
from pydantic import BaseModel
class BaseModelORM(BaseModel):
class Config:
from_attributes = True
We create a new schema schemas/channel_details.py
.
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.
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.
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.
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
assert r.status != 200
After running the test, we are greeted with a beautiful error:
assert r.status != 200
AssertionError
All that's left for us to do is to complete the mapping for ChannelDetails
.
Just kidding. We won't be doing this mapping manually; instead, we'll use a tool available at 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.
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 🚀
Top comments (0)