<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: apiharbor</title>
    <description>The latest articles on DEV Community by apiharbor (@apiharbor).</description>
    <link>https://dev.to/apiharbor</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1210773%2Ffa2ba684-f9af-40fb-b4be-ae8724f5d07e.png</url>
      <title>DEV Community: apiharbor</title>
      <link>https://dev.to/apiharbor</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/apiharbor"/>
    <language>en</language>
    <item>
      <title>Analyzing Likes Using Instagram API with python - part 3</title>
      <dc:creator>apiharbor</dc:creator>
      <pubDate>Sun, 30 Jun 2024 16:08:07 +0000</pubDate>
      <link>https://dev.to/apiharbor/analyzing-likes-using-instagram-api-with-python-part-3-4ggp</link>
      <guid>https://dev.to/apiharbor/analyzing-likes-using-instagram-api-with-python-part-3-4ggp</guid>
      <description>&lt;h1&gt;
  
  
  Analyzing likes using Instagram API with python - part 3
&lt;/h1&gt;

&lt;p&gt;Some time ago, we started working on an app to &lt;a href="https://usemyapi.com/articles/how-to-analyze-instagram-likes-a-simple-python-app/"&gt;analyze likes on Instagram posts&lt;/a&gt;. We want to answer the question: &lt;strong&gt;What percentage of followers like Instagram posts?&lt;/strong&gt; This will tell us whether the account should focus on gaining new followers or improving content since its current followers might not be interested. The result will be a bar chart for each post showing the ratio of all likes to likes from followers.&lt;/p&gt;

&lt;p&gt;In our previous post &lt;a href="https://dev.to/apiharbor/how-to-create-an-instagram-api-client-in-python-a-step-by-step-tutorial-2l1h"&gt;How to analyze Instagram likes – part 2&lt;/a&gt;, we created an API client in Python. We decided to use the &lt;a href="https://usemyapi.com/articles/instagram-scraper-api-comprehensive-guide-and-best-practices/"&gt;Instagram Scraper 2023 API&lt;/a&gt;. We wrote a client to fetch the data needed for our task. Today, it’s time to finish our app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Save requests to Instagram API by adding file caching
&lt;/h2&gt;

&lt;p&gt;Let’s revisit our &lt;code&gt;rapidapi_client&lt;/code&gt;. We want to cache every call to the endpoint. We don’t want to waste requests while working, so it’s worth returning previously fetched data.&lt;/p&gt;

&lt;p&gt;Currently, we have three functions that we will add caching to. Let’s write the caching method first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__get_cache_file_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end_cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Generate a file path for caching based on the endpoint, identifier, count, and end_cursor.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;identifier&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;__get_end_cursor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;end_cursor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.pkl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cache_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__get_or_set_cache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end_cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Retrieve data from the cache if it exists; otherwise, fetch data from the URL, cache it, and return the data.

    :param endpoint: The API endpoint being queried.
    :param identifier: The identifier for the request (e.g., user ID or post shortcode).
    :param count: The number of items requested.
    :param end_cursor: The pagination cursor for the request.
    :param url: The URL to fetch data from if not cached.
    :return: The data retrieved from the cache or fetched from the URL.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;cache_file_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;__get_cache_file_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end_cursor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Check if the cache file exists
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cache_file_path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Load and return data from cache
&lt;/span&gt;        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cache_file_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;cache_file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pickle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cache_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Make the API request if cache does not exist
&lt;/span&gt;    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# Save the fetched data to the cache
&lt;/span&gt;    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cache_file_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;wb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;cache_file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;pickle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cache_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also need to change the constructor to create a folder for caching files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cache_dir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;cache&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;x-rapidapi-key&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RAPIDAPI_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;x-rapidapi-host&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RAPIDAPI_HOST&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cache_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cache_dir&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cache_dir&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makedirs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cache_dir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything looks fantastic! Now, we need to change the methods that communicate with the API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_user_posts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;userid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end_cursor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;__get_api_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/userposts/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;userid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;__get_end_cursor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;end_cursor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;__get_or_set_cache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;userposts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;userid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end_cursor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_post_likes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shortcode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end_cursor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;__get_api_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/postlikes/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;shortcode&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;__get_end_cursor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;end_cursor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;__get_or_set_cache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;postlikes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shortcode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end_cursor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_user_followers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;userid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end_cursor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;__get_api_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/userfollowers/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;userid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;__get_end_cursor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;end_cursor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;__get_or_set_cache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;userfollowers&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;userid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end_cursor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing extraordinary here, we just use &lt;code&gt;__get_or_set_cache&lt;/code&gt; and return the cached content if found instead of querying the Instagram API.&lt;/p&gt;

&lt;p&gt;We are now protected against wasting requests, let’s move on!&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating plain old python objects (POPO)
&lt;/h2&gt;

&lt;p&gt;POPO are simple Python objects without additional methods or attributes other than those explicitly defined. We need them to pass data between classes.&lt;/p&gt;

&lt;p&gt;Let’s think about the POPO we need. We must gather data from the API and merge it into one object to pass it further. So, we need a simple &lt;code&gt;PostData&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PostData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;post_likers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;followers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;post_id&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post_likers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;post_likers&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;followers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;followers&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another POPO will be the analysis result, let’s name this class &lt;code&gt;PostResult&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PostResult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;all_likes_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;likers_likes_count&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all_likes_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;all_likes_count&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;likers_likes_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;likers_likes_count&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;post_id&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s create a list of &lt;code&gt;PostData&lt;/code&gt; built from Instagram API data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Create an instance of the RapidApiClient
&lt;/span&gt;&lt;span class="n"&gt;api_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RapidApiClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;end_cursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

&lt;span class="c1"&gt;# Replace with your actual Instagram account ID
&lt;/span&gt;&lt;span class="n"&gt;ACCOUNT_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;__PASTE_ACCOUNT_ID__&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;# Retrieve followers for the account (maximum 50 followers for testing purposes)
&lt;/span&gt;&lt;span class="n"&gt;followers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;api_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_user_followers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ACCOUNT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Extract usernames of the followers
&lt;/span&gt;&lt;span class="n"&gt;followers_usernames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;username&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;followers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;

&lt;span class="c1"&gt;# Initialize an empty list to store post data
&lt;/span&gt;&lt;span class="n"&gt;posts_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;PostData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="n"&gt;PAGE_LIMIT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;  &lt;span class="c1"&gt;# Limit the number of pages to retrieve for testing purposes
&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PAGE_LIMIT&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Retrieve user posts (maximum 5 posts per page for testing purposes)
&lt;/span&gt;    &lt;span class="n"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;api_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_user_posts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ACCOUNT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end_cursor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Check if there is no next page, break the loop if not
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;next_page&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;

    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;end_cursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;end_cursor&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# Update the end_cursor for the next page
&lt;/span&gt;    &lt;span class="n"&gt;edges&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;edges&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# Extract the posts data
&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;edge&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;node&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;post_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# Extract the post ID
&lt;/span&gt;
        &lt;span class="c1"&gt;# Retrieve likes for the post (maximum 50 likes for testing purposes)
&lt;/span&gt;        &lt;span class="n"&gt;post_likes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;api_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_post_likes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shortcode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# Extract usernames of the users who liked the post
&lt;/span&gt;        &lt;span class="n"&gt;post_likers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;like&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;username&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;like&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;post_likes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;likes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;

        &lt;span class="c1"&gt;# Create a PostData object and add it to the posts_data list
&lt;/span&gt;        &lt;span class="n"&gt;posts_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PostData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;post_likers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;followers_usernames&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, &lt;code&gt;posts_data&lt;/code&gt; contains a list of &lt;code&gt;PostData&lt;/code&gt; objects composed of post IDs, lists of likers, and lists of followers. Great! We have the data ready; it’s time to feed it to the analyzer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Analyzing data from the Instagram API
&lt;/h2&gt;

&lt;p&gt;Let’s think about what such an analyzer should do. Essentially, it should count, just count 😉 But what exactly?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The total number of likes on a given post&lt;/li&gt;
&lt;li&gt;The number of likes from followers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is achieved by the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LikesAnalyzer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;posts_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;PostData&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
        Initialize the LikesAnalyzer with a list of PostData objects.

        :param posts_data: List of PostData objects containing data for each post.
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;posts_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;posts_data&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_analysis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;PostResult&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
        Analyze the likes data to determine the total likes and the likes from followers for each post.

        :return: A list of PostResult objects containing the analysis results for each post.
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;PostResult&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;  &lt;span class="c1"&gt;# Initialize an empty list to store the analysis results
&lt;/span&gt;
        &lt;span class="c1"&gt;# Iterate through each PostData object in the posts_data list
&lt;/span&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;posts_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;all_likes_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post_likers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Count the total number of likes for the post
&lt;/span&gt;            &lt;span class="n"&gt;likers_likes_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;  &lt;span class="c1"&gt;# Initialize the count for likes from followers
&lt;/span&gt;
            &lt;span class="c1"&gt;# Iterate through each liker of the post
&lt;/span&gt;            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;liker&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post_likers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="c1"&gt;# Check if the liker is also a follower
&lt;/span&gt;                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;liker&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;followers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;likers_likes_count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;  &lt;span class="c1"&gt;# Increment the count if the liker is a follower
&lt;/span&gt;
            &lt;span class="c1"&gt;# Create a PostResult object with the post ID, total likes, and likes from followers
&lt;/span&gt;            &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PostResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;all_likes_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;likers_likes_count&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;  &lt;span class="c1"&gt;# Return the list of PostResult objects
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;get_analysis&lt;/code&gt; function returns a list of &lt;code&gt;PostResult&lt;/code&gt;. Yes, these are the results of our analysis. Such dry results don’t tell us much. Let’s make a chart out of them!&lt;/p&gt;

&lt;h2&gt;
  
  
  Displaying the chart based on
&lt;/h2&gt;

&lt;p&gt;Data from the Instagram API&lt;/p&gt;

&lt;p&gt;I propose the class name &lt;code&gt;PostLikesPlotter&lt;/code&gt; to keep it simple. The best representation for the results will be a bar chart. It will immediately show on one bar how many followers liked a given post.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;matplotlib.pyplot&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;

&lt;span class="c1"&gt;# Constants for the bar chart
&lt;/span&gt;&lt;span class="n"&gt;BAR_WIDTH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;  &lt;span class="c1"&gt;# Width of the bars in the chart
&lt;/span&gt;&lt;span class="n"&gt;ALL_LIKES_COLOR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;blue&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;  &lt;span class="c1"&gt;# Color of the bars representing all likes
&lt;/span&gt;&lt;span class="n"&gt;LIKERS_LIKES_COLOR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;green&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;  &lt;span class="c1"&gt;# Color of the bars representing likes from followers
&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PostLikesPlotter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;plot_analysis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;PostResult&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
        Plot the analysis of post likes, showing total likes and likes from followers for each post.

        :param results: A list of PostResult objects containing analysis results for each post.
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="c1"&gt;# Extract post IDs, total likes counts, and likers likes counts from the results
&lt;/span&gt;        &lt;span class="n"&gt;post_ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;all_likes_counts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all_likes_count&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;likers_likes_counts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;likers_likes_count&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="c1"&gt;# Create a figure and axis for the bar chart
&lt;/span&gt;        &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subplots&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="c1"&gt;# Plot the bars for total likes
&lt;/span&gt;        &lt;span class="n"&gt;bars&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;all_likes_counts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BAR_WIDTH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ALL_LIKES_COLOR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;All Likes&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Plot the bars for likes from followers, overlaying them on the total likes bars
&lt;/span&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;all_likes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;liker_likes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bars&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;all_likes_counts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;likers_likes_counts&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
            &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_x&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;liker_likes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BAR_WIDTH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;LIKERS_LIKES_COLOR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Likers Likes&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Set the labels and title of the chart
&lt;/span&gt;        &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_xlabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Post ID&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_ylabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Likes Count&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Likes Analysis per Post&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Move the legend outside the bar chart area
&lt;/span&gt;        &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;legend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;upper left&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bbox_to_anchor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

        &lt;span class="c1"&gt;# Adjust the appearance of the x-axis labels
&lt;/span&gt;        &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_xticklabels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fontsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rotation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ha&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;right&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Display the bar chart
&lt;/span&gt;        &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffypg2f0yr1so7y5qtwu6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffypg2f0yr1so7y5qtwu6.png" alt="Result of analysis" width="800" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;We have a working application written in Python for Instagram data analysis! For those who want to download the source code, visit our website &lt;a href="https://usemyapi.com/articles/instagram-data-analysis-with-python-analyzing-likes-using-instagram-api-part-3/"&gt;UseMyApi.com&lt;/a&gt; where you will find a link to GitHub with the code.&lt;/p&gt;

&lt;p&gt;If you liked the post ❤️ leave a comment or any reaction. If you need any other application or changes to the current code, you can "hire" me for programming work. Feel free to &lt;a href="https://usemyapi.com/services/"&gt;contact me&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;All the best for you all!&lt;/p&gt;

</description>
      <category>python</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to create an Instagram API client in python: a step-by-step tutorial</title>
      <dc:creator>apiharbor</dc:creator>
      <pubDate>Wed, 19 Jun 2024 13:06:18 +0000</pubDate>
      <link>https://dev.to/apiharbor/how-to-create-an-instagram-api-client-in-python-a-step-by-step-tutorial-2l1h</link>
      <guid>https://dev.to/apiharbor/how-to-create-an-instagram-api-client-in-python-a-step-by-step-tutorial-2l1h</guid>
      <description>&lt;h1&gt;
  
  
  How to Create an Instagram API Client in Python: A Step-by-Step Tutorial - part 2
&lt;/h1&gt;

&lt;p&gt;In the &lt;a href="https://dev.to/apiharbor/how-to-analyze-instagram-likes-a-simple-python-app-2fl1"&gt;previous post&lt;/a&gt;, we set up the runtime environment for working with &lt;a href="https://rapidapi.com"&gt;RapidAPI&lt;/a&gt; in Python. We also wrote a simple client that communicates with the &lt;strong&gt;Instagram Scraper 2023 API&lt;/strong&gt; hosted on RapidAPI. The tests went well, so today we will be finishing the client.&lt;/p&gt;

&lt;h2&gt;
  
  
  Our Goal
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;To remind you of our goal:&lt;/strong&gt; We want to create a full-fledged Python application using Instagram data that will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tell us who is liking the posts&lt;/li&gt;
&lt;li&gt;Calculate the percentage of followers who like the posts&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What value will this application provide?
&lt;/h3&gt;

&lt;p&gt;It will help determine whether the account owner should focus more on encouraging users to follow the profile, getting more likes, or improving the content.&lt;/p&gt;

&lt;p&gt;Let's get to work!&lt;/p&gt;

&lt;h2&gt;
  
  
  Necessary Endpoints
&lt;/h2&gt;

&lt;p&gt;To achieve our goal, we need to know exactly what data we need to conduct our analysis. Therefore, we need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To get a listing of posts by user ID&lt;/li&gt;
&lt;li&gt;To get a list of people liking a particular post&lt;/li&gt;
&lt;li&gt;To get a list of people following a user&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In our application, we use the &lt;strong&gt;Instagram Scraper 2023 API&lt;/strong&gt;, which provides the necessary data without any issues. We will use the following endpoints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;User Posts&lt;/strong&gt; - returns a listing of posts by user ID&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Post Likes&lt;/strong&gt; - returns a listing of people liking a particular post&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User Followers&lt;/strong&gt; - returns a listing of people following a user&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since we have everything selected, it's time to implement these endpoints in our &lt;code&gt;RapidApiClient&lt;/code&gt; class.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation in RapidApiClient Class
&lt;/h2&gt;

&lt;p&gt;Currently, this class in Python looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;RAPIDAPI_HOST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RAPIDAPI_KEY&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RapidApiClient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;x-rapidapi-key&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RAPIDAPI_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;x-rapidapi-host&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RAPIDAPI_HOST&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_user_posts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;userid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;__get_api_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/userposts/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;userid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/%7Bend_cursor%7D&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__get_api_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path_and_query&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;RAPIDAPI_HOST&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="n"&gt;path_and_query&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, there's nothing complicated here. To fetch more posts, we need to add &lt;strong&gt;end_cursor&lt;/strong&gt; support. The operation of &lt;strong&gt;end_cursor&lt;/strong&gt; is very simple. When we fetch the first batch of posts, the response will include an &lt;strong&gt;end_cursor&lt;/strong&gt; value. To get the next batch of posts, we simply pass this cursor in the next request.&lt;/p&gt;

&lt;h3&gt;
  
  
  Modify the get_user_posts Function
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_user_posts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;userid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end_cursor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;__get_api_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/userposts/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;userid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;__get_end_cursor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;end_cursor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We set the &lt;strong&gt;end_cursor&lt;/strong&gt; parameter as default (None) and wrote a simple function &lt;code&gt;__get_end_cursor&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__get_end_cursor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ec&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ec&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%7Bend_cursor%7D&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ec&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function returns the default value if the cursor is None.&lt;/p&gt;

&lt;p&gt;Let's modify &lt;code&gt;main.py&lt;/code&gt; to fetch more than 50 posts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Initialize the end_cursor to None
&lt;/span&gt;&lt;span class="n"&gt;end_cursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

&lt;span class="c1"&gt;# Loop to fetch posts, iterating up to 2 times
&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Fetch user posts using the API client, specifying user ID, number of posts to fetch, and end cursor for pagination
&lt;/span&gt;    &lt;span class="n"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;api_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_user_posts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;11579415180&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end_cursor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Check if there is no next page of posts
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;next_page&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="c1"&gt;# Break the loop if there are no more pages
&lt;/span&gt;        &lt;span class="k"&gt;break&lt;/span&gt;

    &lt;span class="c1"&gt;# Update the end_cursor to the end cursor from the current batch of posts for the next iteration
&lt;/span&gt;    &lt;span class="n"&gt;end_cursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;end_cursor&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# Print the fetched posts
&lt;/span&gt;    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code fetches 100 posts. The first time, when &lt;code&gt;cursor_end = None&lt;/code&gt;, it fetches the 50 latest posts. Then, in the second loop iteration, it captures &lt;code&gt;cursor_end&lt;/code&gt; from the API response and uses it to fetch 50 more posts.&lt;/p&gt;

&lt;p&gt;We're doing quite well!&lt;/p&gt;

&lt;h3&gt;
  
  
  Write the Function to Return People Liking the Post
&lt;/h3&gt;

&lt;p&gt;Let's move to &lt;code&gt;rapidapi_client.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_post_likes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shortcode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end_cursor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;__get_api_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/postlikes/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;shortcode&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;__get_end_cursor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;end_cursor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the operation is identical to &lt;code&gt;get_user_posts&lt;/code&gt;. So, let's write another function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_user_followers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;userid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end_cursor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;__get_api_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/userfollowers/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;userid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;__get_end_cursor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;end_cursor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function will return the followers of a user.&lt;/p&gt;

&lt;h2&gt;
  
  
  RapidApiClient Ready for Action!
&lt;/h2&gt;

&lt;p&gt;At this point, we have a complete client for communicating with the API. We can fetch all the data we need. In the next post, we will write the logic to use this data for analysis. Finally, we will be able to advise the analyzed user on how to develop their profile.&lt;/p&gt;

&lt;p&gt;See you next time! 🚀&lt;/p&gt;

</description>
      <category>python</category>
      <category>tutorial</category>
      <category>programming</category>
      <category>api</category>
    </item>
    <item>
      <title>How to Analyze Instagram Likes: A Simple Python App - part 1</title>
      <dc:creator>apiharbor</dc:creator>
      <pubDate>Sun, 16 Jun 2024 10:41:56 +0000</pubDate>
      <link>https://dev.to/apiharbor/how-to-analyze-instagram-likes-a-simple-python-app-2fl1</link>
      <guid>https://dev.to/apiharbor/how-to-analyze-instagram-likes-a-simple-python-app-2fl1</guid>
      <description>&lt;p&gt;&lt;strong&gt;How to Analyze Instagram Likes: A Simple Python App - part 1&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Do you want to better understand which Instagram posts attract the most attention? In my latest article on &lt;a href="https://usemyapi.com/articles/how-to-analyze-instagram-likes-a-simple-python-app/"&gt;usemyapi.com&lt;/a&gt;, I show you how to build a simple application in Python to analyze Instagram likes.&lt;/p&gt;

&lt;p&gt;You will learn how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gain access to the Instagram API&lt;/li&gt;
&lt;li&gt;Establish a connection with the API&lt;/li&gt;
&lt;li&gt;Write a Python class that communicates with the API&lt;/li&gt;
&lt;li&gt;Create a working example that operates on the retrieved data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don't miss this opportunity to enhance your programming skills and gain valuable insights into Instagram user behavior.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://usemyapi.com/articles/how-to-analyze-instagram-likes-a-simple-python-app/"&gt;Read the full article here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to publish a python package - Best Practices: A YouTube Channel API Example</title>
      <dc:creator>apiharbor</dc:creator>
      <pubDate>Wed, 10 Jan 2024 08:48:06 +0000</pubDate>
      <link>https://dev.to/apiharbor/how-to-publish-a-python-package-best-practices-a-youtube-channel-api-example-fin</link>
      <guid>https://dev.to/apiharbor/how-to-publish-a-python-package-best-practices-a-youtube-channel-api-example-fin</guid>
      <description>&lt;p&gt;Hey everyone! 👋&lt;/p&gt;

&lt;p&gt;We've finally wrapped up our coding journey with &lt;a href="https://rapidapi.com/dataocean/api/the-better-youtube-channel-details"&gt;The Better YouTube Channel Details API&lt;/a&gt;. It's been a real adventure getting all those YouTube channel details like social media links, email addresses, avatars, RSS feeds, and subscriber stats.&lt;/p&gt;

&lt;p&gt;Guess what? It's time to roll out our baby to the world - we're hitting PyPi with our package! It's not just about bragging rights; we're here to lend a hand to fellow coders. We've cooked up this nifty library so you can plug it into your apps without breaking a sweat. Cheers to smoother coding days ahead!&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/apiharbor/building-python-package-api-client-for-youtube-channel-details-rapidapi-75g"&gt;creating the package structure and writing code to communicate with the API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/apiharbor/get-youtube-channel-details-api-connection-testing-1jjg"&gt;testing the solution&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;👉 &lt;strong&gt;we are here: publishing our work on pypi.org&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  setup.py - necessary information about the package
&lt;/h2&gt;

&lt;p&gt;So let’s create the &lt;code&gt;setup.py&lt;/code&gt; file directly in the project directory&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwppjvc9gmtyc4n05uzbr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwppjvc9gmtyc4n05uzbr.png" alt="setup.py" width="439" height="169"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will be using a template like the one below. It contains all the important information, so in my opinion, this example has everything we need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;setuptools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;find_packages&lt;/span&gt;

&lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;example&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0.1.0&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;author&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;author_email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;author@example.com&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;short description&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;long_description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;README.md&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;long_description_content_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;text/markdown&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https://example.com&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;packages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;find_packages&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;install_requires&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="c1"&gt;# Package dependency list, e.g 'requests &amp;gt;= 2.20.0'
&lt;/span&gt;    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;classifiers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Programming Language :: Python :: 3&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;License :: OSI Approved :: MIT License&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Operating System :: OS Independent&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;keywords&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;example&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;python_requires&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;=3.6&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will closely examine the setup and present the best practices for each property!&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Practices
&lt;/h2&gt;

&lt;h3&gt;
  
  
  👉 Name
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Simplicity is Key&lt;/strong&gt;: Pick a name that's easy to remember and reflects your package's functionality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check for Uniqueness&lt;/strong&gt;: Make sure your chosen name isn't already in use on PyPI to avoid naming conflicts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lowercase Preference&lt;/strong&gt;: Typically, Python package names are all lowercase, following a common Python packaging convention.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No Special Characters&lt;/strong&gt;: Use only letters, numbers, and underscores. Avoid characters like hyphens, as they can make importing the package more difficult.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Descriptive and Relevant&lt;/strong&gt;: Choose a name that gives a hint about what your package does. Steer clear of names that are too generic or ambiguous.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Concise and Memorable&lt;/strong&gt;: Aim for a name that's short and sticks in the mind. Long or complex names can be hard to remember.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Avoid Trademark Issues&lt;/strong&gt;: Make sure your package name doesn't infringe upon existing trademarks or brand names.&lt;/p&gt;

&lt;h3&gt;
  
  
  Our choice:
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Following the instructions above, we are leaning towards the name: apiharbor_youtubeapi, because it combines username with "youtube" and "api," clearly indicating its purpose and origin.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  👉 Version
&lt;/h2&gt;

&lt;p&gt;Choosing the right version number for your Python package is important for effective version control and to communicate the nature of changes to users. Here are some best practices for versioning your package:&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Semantic Versioning (SemVer):
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Major Version (X.y.z)&lt;/strong&gt;: Bump this up when you make big changes that aren't backward compatible. Think of it as a 'new era' for your package.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Minor Version (x.Y.z)&lt;/strong&gt;: Increase this when you add cool new features, but everything old still works fine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Patch Version (x.y.Z)&lt;/strong&gt;: This one's for those little bug fixes and tweaks that don't change the features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Starting Point&lt;/strong&gt;: If your package is all grown up and stable, kick off with 1.0.0. If it's still a baby (in early development), start with something like 0.1.0.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pre-Release Fun&lt;/strong&gt;: Got a beta or alpha version? Tag it onto the end like 1.0.0-beta. It's like giving your users a sneak peek.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Post-Release Adjustments&lt;/strong&gt;: Need to tweak a release without a big fuss? Use post-releases like 1.0.0-1 for those minor changes, maybe a typo fix in your documentation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Changelog Is Your Friend&lt;/strong&gt;: Keep a log of what you change or fix. It's super helpful for users and fellow developers to track what's new or different.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stay Consistent&lt;/strong&gt;: Picked SemVer? Great! Stick with it. Consistency is key.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No Wild Jumps&lt;/strong&gt;: Avoid crazy jumps in version numbers. Each increment should make sense.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Define Your Public API&lt;/strong&gt;: Make it clear what's in your public API and how you plan to keep it stable. This guides your versioning strategy.&lt;/p&gt;

&lt;p&gt;Remember, version numbers are like signposts for users – they tell them what to expect with each new update. Keep it clear and sensible!&lt;/p&gt;

&lt;h3&gt;
  
  
  Our choice:
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;We will set version &lt;code&gt;1.0.0&lt;/code&gt; as it is the first production version. Later, we will adhere to the semantics and best practices mentioned above.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  👉 Author
&lt;/h2&gt;

&lt;p&gt;You might be wondering, it's just the &lt;code&gt;author&lt;/code&gt; field, what could be important here? Choosing the right author can actually be a challenge. Here are some best practices to follow when specifying an author:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Go Real with Names&lt;/strong&gt;: Using your real name adds a touch of professionalism and trust. If you're in a team, you might want to list the lead dev or the project boss.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep It Uniform&lt;/strong&gt;: Got a bunch of packages? Stick to the same name across the board. It helps users and contributors spot your work in different places.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shoutout to Co-Authors&lt;/strong&gt;: Working with a cool team? Give them a nod. But remember, the &lt;code&gt;author&lt;/code&gt; field usually has just one name or entity. You can always detail everyone else's contributions in a CONTRIBUTORS file or the docs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Representing an Org&lt;/strong&gt;? Use Its Name: Publishing on behalf of a company, university, or open-source group? Use that name. It's pretty standard for projects developed under an official banner.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Emails: Handle with Care&lt;/strong&gt;: Including an email? Make sure it's one you set up for the project or can handle public emails. Watch out for spam risks!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Privacy Matters&lt;/strong&gt;: If you're worried about privacy or other personal issues, a pseudonym is totally fine. Just keep it professional and consistent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Change of Guard? Update the Name&lt;/strong&gt;: If there's a new sheriff in town (aka a new maintainer), update the author field. Maybe give a shout out to the original author in the docs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stay Professional&lt;/strong&gt;: This field is out there for all to see in package directories and repos. A professional touch can really make a difference in how people view your package's reliability.&lt;/p&gt;

&lt;p&gt;Remember, the way you present the author info can say a lot about your package. Keep it clear, respectful, and professional!&lt;/p&gt;

&lt;h3&gt;
  
  
  Our choice:
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;As we can see, &lt;code&gt;author&lt;/code&gt; is not so obvious, but in our case, we will simply set it to: &lt;code&gt;apiharbor&lt;/code&gt;. However, it's good to be aware of the things mentioned above.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  👉 Description
&lt;/h2&gt;

&lt;p&gt;A very important thing. The description must attract developers and encourage them to install our package. After all, we want to clearly show them that using our library will make their lives easier. What should guide us? Here are our best practices:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Short and Sweet&lt;/strong&gt;: Nail your description in just a few words. It should quickly let users know what your package is all about, in plain language.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keyword Magic&lt;/strong&gt;: Sprinkle in those relevant keywords. They're like beacons for users and search engines, guiding them to what your package offers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Jargon? Just Say No&lt;/strong&gt;: Unless you're talking to a niche crowd, keep the tech talk to a minimum. Clear and simple is your best bet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Showcase the Wow Factor&lt;/strong&gt;: What's special about your package? Does it solve a tricky problem? Add a sparkle to something ordinary? Let that shine through.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Grammar Police&lt;/strong&gt;: Polish your description. No typos, no grammar bloopers. It's like dressing your package for success.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Language Harmony&lt;/strong&gt;: Stick to one language. If your code comments and docs are in English, your description should be too.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tone It Right&lt;/strong&gt;: Keep the vibe professional, tailored to who you're talking to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stay Current&lt;/strong&gt;: Evolved your package? Give your description a makeover too. Keep it in sync with what's new or different.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep It Real&lt;/strong&gt;: Don't oversell. Promise what you can deliver, or you might end up with unhappy users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build Trust&lt;/strong&gt;: Especially for packages aimed at a broad audience, your description should radiate confidence about your package’s stability and usefulness.&lt;/p&gt;

&lt;p&gt;Remember, your description is like the front door to your package. Make it inviting, clear, and true to what's inside!&lt;/p&gt;

&lt;h3&gt;
  
  
  Our choice:
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Following these practices, we will set the description:&lt;/p&gt;

&lt;p&gt;Want to dive deeper into the YouTube scene? Our YouTube Channel Details API is just what you need, especially if you're a marketer, researcher, or content creator. It's not just about getting contact info; it's about discovering those little gems like social media and location details of YouTube channels. Imagine the possibilities - like when one of our users found the perfect collaboration opportunity just by using these insights!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A big advantage of it is that it's short and clear to understand. Right away, you can see who it's intended for and what it does.&lt;/p&gt;

&lt;h2&gt;
  
  
  👉 Long Description
&lt;/h2&gt;

&lt;p&gt;Here are two properties to be filled&lt;/p&gt;

&lt;p&gt;&lt;code&gt;long_description=open('README.md').read()&lt;/code&gt; -  path to the README file&lt;br&gt;
&lt;code&gt;long_description_content_type='text/markdown',&lt;/code&gt; - content format&lt;/p&gt;

&lt;p&gt;Let's take a look at the best practices we use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Snappy Title&lt;/strong&gt;: Kick off with a title that's both clear and catchy. It should give a snapshot of what your project is all about.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Elevator Pitch Description&lt;/strong&gt;: In just a few sentences, highlight what your project does and its coolest features. Think of it as your project's elevator pitch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Easy-Peasy Setup&lt;/strong&gt;: Guide your users through a hassle-free installation. Simple steps, commands to run, or download links will make it a breeze.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How-to-Use Demo&lt;/strong&gt;: Show off how your project works. Include code snippets, command-line examples, or even screenshots for a quick visual guide.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dependencies List&lt;/strong&gt;: Got other tools or libraries your project leans on? List them out clearly along with installation tips.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Config 101&lt;/strong&gt;: If your project needs some setting up, walk your users through it with detailed instructions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test Run&lt;/strong&gt;: If your project has automated tests, explain how to run them. It's like a health check for your project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Join the Club&lt;/strong&gt;: Invite others to contribute and lay out the ground rules in your CONTRIBUTING.md. Collaboration makes the project world go round!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Version Chronicles&lt;/strong&gt;: Talk about your versioning system, if you have one. It's like telling the history of your project's evolution.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cheers to the Team&lt;/strong&gt;: Acknowledge the brains behind the project. List the authors and give a shout-out to contributors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;License Lowdown&lt;/strong&gt;: Include your project's license details – a brief note and a link to the full text should do the trick.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FAQs Corner&lt;/strong&gt;: Tackle those frequently asked questions or common hiccups users might run into.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Got Questions? Get in Touch&lt;/strong&gt;: Provide contact info for support or inquiries. It's always nice to have someone to reach out to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Badge Bonanza&lt;/strong&gt;: (Optional) Flaunt those badges! They're like little trophies showing off your project's health or status.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Show and Tell&lt;/strong&gt;: If it makes sense, add visuals like screenshots, gifs, or videos to showcase your project in action.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Global Reach&lt;/strong&gt;: If your project speaks multiple languages, mention the available translations and how to switch them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What’s Next?&lt;/strong&gt; Got plans for your project? Share your roadmap or future dreams – it's exciting to see where things are headed.&lt;/p&gt;

&lt;p&gt;Remember, your project documentation is your chance to make a great first impression. Make it friendly, informative, and engaging!&lt;/p&gt;
&lt;h3&gt;
  
  
  Our choice:
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;We won't paste the content here because it would be a bit (just a tad ;)) over the top, but I encourage you to check out our &lt;a href="https://github.com/apiharbor/apiharbor-rapidapi-dataocean-python-youtubeapi/blob/main/README.md"&gt;README.md&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  👉 Keywords
&lt;/h2&gt;

&lt;p&gt;Keywords are the last property we'll discuss, as the rest is purely technical and there's nothing groundbreaking there, you just need to set the remaining values correctly 😊 and that's it.&lt;/p&gt;

&lt;p&gt;Our best practices for selecting keywords are:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spot-On Selection&lt;/strong&gt;: Pick keywords that are like a bullseye for what your project is all about. Think of functionality and purpose.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nail the Specifics&lt;/strong&gt;: Choose terms that precisely paint a picture of what your project can do. It's like giving someone a mini-tour through its features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What Would Users Type?&lt;/strong&gt;: Think about the words your future fans might use when they're on the hunt for a project like yours. Those are your golden keywords.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mix It Up&lt;/strong&gt;: Blend both broad and narrow terms. It's like casting a wide net, but with some targeted spots.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quality Over Quantity&lt;/strong&gt;: It’s tempting to throw in a kitchen sink of keywords, but resist the urge. A well-thought-out, concise list is way more effective. Aim for that sweet spot where you've covered the essentials without going overboard.&lt;/p&gt;

&lt;p&gt;Remember, picking the right keywords is like setting up signposts that lead straight to your project. Make them count!&lt;/p&gt;

&lt;p&gt;Our choice:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;keywords&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;youtube&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;youtube-api&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;channel-details&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;youtube-data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;youtube-analytics&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;contact-information&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;social-media-analysis&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;youtube-marketing&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content-creation&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;influencer-research&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;video-analytics&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;youtube-content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;media-analysis&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;digital-marketing&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That will be perfect 🙂&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's put everything together
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;setuptools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;find_packages&lt;/span&gt;

&lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;example&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0.1.0&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;author&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;author_email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;author@example.com&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;short description&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;long_description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;README.md&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;long_description_content_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;text/markdown&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https://example.com&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;packages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;find_packages&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;install_requires&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
           &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;classifiers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Programming Language :: Python :: 3&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;License :: OSI Approved :: MIT License&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Operating System :: OS Independent&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;keywords&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;example&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;python_requires&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;=3.6&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Publishing the Package!
&lt;/h2&gt;

&lt;p&gt;The first thing we need to do is register at &lt;a href="https://pypi.org/"&gt;PyPi&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, we launch the command line and navigate to the directory where we have &lt;code&gt;setup.py&lt;/code&gt;. Next, we run a command to ensure we have the latest installation package installed:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;\ApiHarbor\libs\youtube_channel_details_api&amp;gt;python -m pip install --upgrade build&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now, we need to generate the distribution archives that we will publish. We do this using the command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;python -m build&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7fmooynbjy20viv9fmmi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7fmooynbjy20viv9fmmi.png" alt="result" width="756" height="79"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft2h1aexm86tamjwc48jr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft2h1aexm86tamjwc48jr.png" alt="project" width="424" height="323"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The build has finished. Let's check if everything was generated correctly by entering the command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;twine check dist/*&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnrk3wxyiawqh6s3e9hjj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnrk3wxyiawqh6s3e9hjj.png" alt="result" width="759" height="46"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Everything looks great!&lt;/p&gt;

&lt;p&gt;Now that we have the distribution files, we need to install &lt;code&gt;twine&lt;/code&gt; as it's needed to upload the distribution package. We enter the installation command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;python -m pip install --upgrade twine&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ✋ Token needed!
&lt;/h3&gt;

&lt;p&gt;PyPi has changed its authentication system. Now, we won't publish by providing our username and password for the account, but we need to do it through API tokens.&lt;/p&gt;

&lt;p&gt;First, we need to create the token by entering here:&lt;br&gt;
&lt;a href="https://pypi.org/manage/account/token/"&gt;https://pypi.org/manage/account/token/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdg2b90ahmf12babhf8ge.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdg2b90ahmf12babhf8ge.png" alt="creating a token" width="729" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, let's save it somewhere on the side so we don't lose it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzttan9f5oc3gmhfoaqdh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzttan9f5oc3gmhfoaqdh.png" alt="token" width="725" height="253"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, the most important part, the command to publish our package:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;python -m twine upload --repository pypi dist/*&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After entering the command, you will be prompted to enter the username. There, you should type: &lt;code&gt;__token__&lt;/code&gt;&lt;br&gt;
yes, &lt;code&gt;__token__&lt;/code&gt;, always enter &lt;code&gt;__token__&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and the password, which is the previously saved token, including the prefix: &lt;code&gt;pypi-&lt;/code&gt;&lt;br&gt;
This is very important&lt;/p&gt;

&lt;p&gt;Note! If we want to publish on &lt;code&gt;testpypi&lt;/code&gt;, we need to create an account (register) at &lt;a href="https://test.pypi.org/"&gt;https://test.pypi.org/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pypi&lt;/code&gt; (production) and &lt;code&gt;testpypi&lt;/code&gt; (test) are separate from each other, so the generated tokens will not work in both places. This needs to be kept in mind, because during the upload, we might encounter a situation where we provide the correct auth data but still receive the response:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;HTTPError: 403 Forbidden from …&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;That's all from our series of posts about creating and publishing your own Python package. We went through the journey from setting up the project structure, writing the code, and its tests, to publishing the package. Now, programmers around the world can breathe a little easier thanks to us.&lt;/p&gt;

&lt;p&gt;You can see our work here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pypi.org/project/apiharbor-youtubeapi/1.0.0/"&gt;Published package on PyPi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/apiharbor/apiharbor-rapidapi-dataocean-python-youtubeapi"&gt;Package source code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apiharbor.com/"&gt;Our Website with interesting articles about APIs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;💚 Thanks for your time and see you!&lt;/p&gt;

&lt;p&gt;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 🚀&lt;/p&gt;

</description>
      <category>python</category>
      <category>tutorial</category>
      <category>programming</category>
      <category>api</category>
    </item>
    <item>
      <title>Get YouTube Channel Details API: Testing Connection</title>
      <dc:creator>apiharbor</dc:creator>
      <pubDate>Wed, 27 Dec 2023 16:10:21 +0000</pubDate>
      <link>https://dev.to/apiharbor/get-youtube-channel-details-api-connection-testing-1jjg</link>
      <guid>https://dev.to/apiharbor/get-youtube-channel-details-api-connection-testing-1jjg</guid>
      <description>&lt;p&gt;Hi,&lt;/p&gt;

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

&lt;p&gt;Let's look at the roadmap to see where we are now:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://dev.to/apiharbor/building-python-package-api-client-for-youtube-channel-details-rapidapi-75g"&gt;creating the package structure and coding for API communication&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;👉 &lt;strong&gt;we are currently here: testing our solution&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/apiharbor/how-to-publish-a-python-package-best-practices-a-youtube-channel-api-example-fin"&gt;next, we'll publish our work on pypi&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Today, we're going to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create a function that will connect to the API endpoint &lt;/li&gt;
&lt;li&gt;test the implementation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's get started!&lt;/p&gt;

&lt;p&gt;Everyone ready? Camera! ACTION! 🎬&lt;/p&gt;

&lt;h2&gt;
  
  
  📡 Get Youtube Channel details by using &lt;code&gt;__get_request&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Previously, we implemented the &lt;code&gt;__get_request&lt;/code&gt; 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. &lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://rapidapi.com/dataocean/api/the-better-youtube-channel-details"&gt;API documentation&lt;/a&gt;, we see that the endpoint is located at:&lt;br&gt;
&lt;code&gt;https://the-better-youtube-channel-details.p.rapidapi.com/GetChannelDetails&lt;/code&gt;&lt;br&gt;
and it accepts a query parameter &lt;code&gt;UrlOrUsername&lt;/code&gt;. The endpoint only supports the &lt;code&gt;GET&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;With this knowledge of the API, let's write a function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;   &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_channel_details&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;urlOrUsername&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;any&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;__get_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/GetChannelDetails&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;urlencode&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;urlOrUsername&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;urlOrUsername&lt;/span&gt;&lt;span class="p"&gt;}))&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the previous post, when we were implementing &lt;code&gt;__get_request&lt;/code&gt;, we explained why this function would take a &lt;code&gt;query: dict&lt;/code&gt; parameter. Briefly, it's because &lt;code&gt;urlencode&lt;/code&gt;, which is used for encoding special characters, returns them in the form of a &lt;code&gt;dict&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  👨‍💻 Let's test the code!
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;We open a file &lt;code&gt;tests/tests.py&lt;/code&gt;. At the very beginning of the file, we add an import line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;src.youtube_channel_details_api_client_apiharbor.api_client&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;YouTubeChannelDetailsApiClient&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;it works!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's very important! Pay attention to how the &lt;code&gt;from&lt;/code&gt; construct looks, and then look at the structure of our project:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkfi2djmnoajr3f2vmqom.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkfi2djmnoajr3f2vmqom.png" alt="Running the tests" width="589" height="237"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We open &lt;code&gt;cmd&lt;/code&gt; and navigate to the directory &lt;code&gt;\libs\youtube_channel_details_api&lt;/code&gt;, then write the command to run the test: &lt;code&gt;python -m tests.tests&lt;/code&gt;&lt;br&gt;
And we should see the message: "it works!"&lt;/p&gt;

&lt;p&gt;When everything works we can move on. Let's write a simple test to check if data fetching from the API works.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;YouTubeChannelDetailsApiClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_RAPID_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_get_channel_details&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_channel_details&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@MrBeast&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;test_get_channel_details&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We run it using the previously mentioned command:&lt;br&gt;
&lt;code&gt;python -m tests.tests&lt;/code&gt; &lt;br&gt;
in the directory &lt;code&gt;\libs\youtube_channel_details_api&lt;/code&gt; and here is the result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;'description':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'OK'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'status':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'data':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;'channel_url':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'https://www.youtube.com/channel/UCX&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="err"&gt;OQ&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="err"&gt;DkcsbYNE&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="err"&gt;H&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="err"&gt;uQQuVA'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'channel_name':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'MrBeast'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'channel_id':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'UCX&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="err"&gt;OQ&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="err"&gt;DkcsbYNE&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="err"&gt;H&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="err"&gt;uQQuVA'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'joined_date_text':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'Joined&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Feb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2012&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'channel_country':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'United&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;States'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'rss_url':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🦾 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.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔄 Mapping plain JSON to python OBJECT
&lt;/h2&gt;

&lt;p&gt;Let's go back to our &lt;code&gt;get_channel_details&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;get_channel_details(self,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;urlOrUsername)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;any:&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;response&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;await&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;self.__get_request(&lt;/span&gt;&lt;span class="s2"&gt;"/GetChannelDetails"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;urlencode(&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;'urlOrUsername':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;urlOrUsername&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;print(response)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseModel&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BaseModelORM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;from_attributes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We create a new schema &lt;code&gt;schemas/channel_details.py&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;.base&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseModelORM&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChannelDetails&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModelORM&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So far, we will only map these two fields: &lt;code&gt;status&lt;/code&gt; and &lt;code&gt;description&lt;/code&gt;. We need to make sure that everything works. Only then will we map all the fields.&lt;/p&gt;

&lt;p&gt;Let's go back to &lt;code&gt;api_client.py&lt;/code&gt; and import the &lt;code&gt;ChannelDetails&lt;/code&gt; schema.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;.schemas.channel_details&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ChannelDetails&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and modify the &lt;code&gt;get_channel_details&lt;/code&gt; function so that it returns a &lt;code&gt;ChannelDetails&lt;/code&gt; object created from the JSON received from the API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_channel_details&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;urlOrUsername&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;any&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
 &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;__get_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/GetChannelDetails&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;urlencode&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;urlOrUsername&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;urlOrUsername&lt;/span&gt;&lt;span class="p"&gt;}))&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ChannelDetails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final step is to modify the &lt;code&gt;test_get_channel_details&lt;/code&gt; test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_get_channel_details&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_channel_details&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@MrBeast&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running the test, we are greeted with a beautiful error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
&lt;span class="nb"&gt;AssertionError&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All that's left for us to do is to complete the mapping for &lt;code&gt;ChannelDetails&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsh033kajl6y8hzv5muq4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsh033kajl6y8hzv5muq4.png" alt="One Eternity Later" width="516" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Just kidding. We won't be doing this mapping manually; instead, we'll use a tool available at &lt;a href="https://jsontopydantic.com/"&gt;https://jsontopydantic.com/&lt;/a&gt;. You just need to input your JSON, and the tool will generate the schema for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;p&gt;Let's summarize what we managed to do today:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We wrote the &lt;code&gt;get_channel_details&lt;/code&gt; function, which calls &lt;code&gt;__get_request&lt;/code&gt; to fetch YouTube channel details.&lt;/li&gt;
&lt;li&gt;We also wrote a test for it to check if everything works OK.&lt;/li&gt;
&lt;li&gt;We implemented mapping from JSON to a Python object.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What will we do next time? Actually, the whole package is ready, and all that's left is to publish it on &lt;a href="https://packagist.org/"&gt;Packagist&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for your time and see you next time!&lt;/p&gt;

&lt;p&gt;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 🚀&lt;/p&gt;

</description>
      <category>python</category>
      <category>programming</category>
      <category>api</category>
      <category>programmers</category>
    </item>
    <item>
      <title>Building Python Package: API Client for YouTube Channel Details (RapidAPI)</title>
      <dc:creator>apiharbor</dc:creator>
      <pubDate>Thu, 21 Dec 2023 15:07:31 +0000</pubDate>
      <link>https://dev.to/apiharbor/building-python-package-api-client-for-youtube-channel-details-rapidapi-75g</link>
      <guid>https://dev.to/apiharbor/building-python-package-api-client-for-youtube-channel-details-rapidapi-75g</guid>
      <description>&lt;p&gt;Hi!&lt;br&gt;
Today, we're going to work on &lt;strong&gt;creating a Python 3 package&lt;/strong&gt; to facilitate access to an API for fetching YouTube channel details (&lt;a href="https://rapidapi.com/dataocean/api/the-better-youtube-channel-details"&gt;The Better YouTube Channel Details&lt;/a&gt;). Even if the topic of API communication &lt;strong&gt;doesn't interest&lt;/strong&gt; you, you &lt;strong&gt;might enjoy&lt;/strong&gt; the presented complete process of creation. &lt;/p&gt;

&lt;p&gt;The entire content will be divided into three separate posts, as I don't want to clutter your time with one large monolith.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;👉 &lt;strong&gt;we are here: creating the package structure and writing code to  communicate with the API&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/apiharbor/get-youtube-channel-details-api-connection-testing-1jjg"&gt;testing the solution&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/apiharbor/how-to-publish-a-python-package-best-practices-a-youtube-channel-api-example-fin"&gt;publishing our work on pypi.org&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Don't frown! I invite you on an exciting adventure from which you'll surely learn something.&lt;/p&gt;

&lt;p&gt;Everyone ready? Camera! ACTION! 🎬&lt;/p&gt;
&lt;h2&gt;
  
  
  🧬 The Project Structure
&lt;/h2&gt;
&lt;h3&gt;
  
  
  We're creating the structure of our package in Python 3
&lt;/h3&gt;

&lt;p&gt;Every package must adhere to a specific directory and file structure. According to the &lt;a href="https://packaging.python.org/en/latest/tutorials/packaging-projects/"&gt;official documentation&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;packaging_tutorial/
├── LICENSE
├── pyproject.toml
├── README.md
├── src/
│   └── example_package_YOUR_USERNAME_HERE/
│       ├── __init__.py
│       └── example.py
└── tests/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is how the package should look.&lt;/p&gt;

&lt;p&gt;Our API will be relatively very simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;we will only connect to the API&lt;/li&gt;
&lt;li&gt;fetch JSON data&lt;/li&gt;
&lt;li&gt;map JSON to an object so that it can be easily used in other applications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's create the file structure of our project.&lt;/p&gt;

&lt;p&gt;🧙 &lt;strong&gt;Doing some magic&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fetp3yaxpel2hcxyyzijx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fetp3yaxpel2hcxyyzijx.png" alt="Project structure" width="626" height="166"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Looks great, so let's move on to writing the code, and we'll handle the metadata files later. As programmers, we love writing code, so anything not related to code isn't as appealing to us 😈&lt;/p&gt;

&lt;h2&gt;
  
  
  ⌨️ "Pressing (random) keys"
&lt;/h2&gt;

&lt;h3&gt;
  
  
  So, let's program! That's what we're paid for (right...? right!?)
&lt;/h3&gt;

&lt;p&gt;We're adding a file &lt;code&gt;src/api_client.py&lt;/code&gt;. This file will contain all the communication with the API and the mapping of the response. The constructor of the class should accept a &lt;code&gt;rapid_api_key&lt;/code&gt;, which we can obtain. How to do it? It's simple:&lt;/p&gt;

&lt;p&gt;✔️ &lt;a href="https://rapidapi.com/auth/sign-up?referral=/dataocean/api/the-better-youtube-channel-details"&gt;register&lt;/a&gt; (for free of course) &lt;br&gt;
✔️ move to the &lt;a href="https://rapidapi.com/dataocean/api/the-better-youtube-channel-details"&gt;API page&lt;/a&gt; and click on &lt;code&gt;Test Endpoint&lt;/code&gt;&lt;br&gt;
✔️ on the same page, grab the displayed value of &lt;code&gt;X-RapidAPI-Key&lt;/code&gt;, this is our &lt;code&gt;rapid_api_key&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Great, let's write the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;YouTubeChannelDetailsApiClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rapid_api_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rapidapi_host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;the-better-youtube-channel-details.p.rapidapi.com&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;X-RapidAPI-Key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rapid_api_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;X-RapidAPI-Host&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rapidapi_host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our structure has changed&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fylyy53zve6svjz2o80o2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fylyy53zve6svjz2o80o2.png" alt="Adding more files to the project" width="477" height="194"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Looks decent. There's nothing particularly interesting in it 🥱 a bit dull.&lt;/p&gt;

&lt;p&gt;We need a function that will query the API. We'll use the &lt;code&gt;aiohttp&lt;/code&gt; package for assistance. This package provides us with an HTTP client for communicating with the API.&lt;/p&gt;

&lt;p&gt;✋ Before we proceed, we need to install this package: &lt;br&gt;
&lt;code&gt;pip install aiohttp&lt;/code&gt;&lt;br&gt;
so we can create HTTP requests.&lt;/p&gt;

&lt;p&gt;Our function for communicating with the API will be named &lt;code&gt;__get_request&lt;/code&gt;. From the name, it's clear that it will be a private function accessible only within &lt;code&gt;api_client&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The function should accept &lt;code&gt;path&lt;/code&gt;, which is the path to the API endpoint, and &lt;code&gt;query&lt;/code&gt;. It's important to note that &lt;code&gt;query&lt;/code&gt; should be of type &lt;code&gt;dict&lt;/code&gt;. Why &lt;code&gt;dict&lt;/code&gt; and not, &lt;code&gt;string&lt;/code&gt;? We want to encode each parameter input by the user, and we'll use the &lt;code&gt;urlencode&lt;/code&gt; function for this, which accepts a &lt;code&gt;dict&lt;/code&gt;, not a &lt;code&gt;string&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Okay, but what should the &lt;code&gt;__get_request&lt;/code&gt; function return? The natural instinct is a &lt;code&gt;string&lt;/code&gt;, so we'll set it to return a &lt;code&gt;string&lt;/code&gt; (wow, what a surprise! 😉)&lt;/p&gt;

&lt;p&gt;Let's write the header of the &lt;code&gt;__get_request&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__get_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Moving on to programming, which is what we love the most! ;) the &lt;code&gt;__get_request&lt;/code&gt; function should:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;build the URL to the API endpoint&lt;/li&gt;
&lt;li&gt;query the API&lt;/li&gt;
&lt;li&gt;in case of a network error, retry the request after waiting 300 milliseconds&lt;/li&gt;
&lt;li&gt;in case of an API error, throw an exception&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's start writing the code for this function. Remember, we're using &lt;code&gt;aiohttp&lt;/code&gt; for the HTTP client, and we'll need to handle retries and error checking.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__get_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rapidapi_host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;scheme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;as_string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="n"&gt;session_timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;aiohttp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ClientTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;45.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;is_ok&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;aiohttp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ClientSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;session_timeout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="n"&gt;json_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  
                        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  
                            &lt;span class="n"&gt;is_ok&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
                    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;aiohttp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ContentTypeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="k"&gt;continue&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;is_ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="k"&gt;break&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json_response&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's check to make sure we have all the necessary imports added:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;aiohttp&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;urllib.parse&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urlencode&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;purl&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;URL&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sure, let's also ensure we have all &lt;strong&gt;the necessary packages&lt;/strong&gt; installed:&lt;br&gt;
✔️ &lt;code&gt;pip install asyncio&lt;/code&gt;&lt;br&gt;
✔️ &lt;code&gt;pip install aiohttp&lt;/code&gt;&lt;br&gt;
✔️ &lt;code&gt;pip install purl&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The code looks good (or even great!), &lt;strong&gt;but does it work well&lt;/strong&gt;? That's the eternal question we'll only answer by testing it ourselves.&lt;/p&gt;

&lt;p&gt;But that will come in the next post, so stay tuned!&lt;/p&gt;

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

&lt;p&gt;Thanks for your time and see you in &lt;strong&gt;the next post&lt;/strong&gt;!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>python</category>
      <category>api</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Building a Gateway to Netflix API: A Developer's Guide</title>
      <dc:creator>apiharbor</dc:creator>
      <pubDate>Mon, 20 Nov 2023 09:36:47 +0000</pubDate>
      <link>https://dev.to/apiharbor/building-a-gateway-to-netflix-api-a-developers-guide-2ip3</link>
      <guid>https://dev.to/apiharbor/building-a-gateway-to-netflix-api-a-developers-guide-2ip3</guid>
      <description>&lt;h2&gt;
  
  
  Introduction: Creating in C# .NET Netflix API Gateway
&lt;/h2&gt;

&lt;p&gt;In this article, we embark on an exciting journey to create a C# API client that interfaces with the &lt;a href="https://rapidapi.com/dataocean/api/netflix99"&gt;Netflix API&lt;/a&gt;. It's important to note that Netflix doesn't offer an official API, so we'll be utilizing a set from RapidAPI. Among the options, DataOcean's &lt;a href="https://rapidapi.com/dataocean/api/netflix99"&gt;Netflix API&lt;/a&gt; emerged as my top pick for several compelling reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Its novelty often translates to better features.&lt;/li&gt;
&lt;li&gt;The simplicity is key — with just 7 endpoints, it covers nearly all desired functionalities.&lt;/li&gt;
&lt;li&gt;Affordability is a great plus.&lt;/li&gt;
&lt;li&gt;Rapid performance seals the deal.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With these criteria in mind, let's dive in!&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Our Project in Visual Studio
&lt;/h2&gt;

&lt;p&gt;First things first, we'll adhere to a naming convention for clarity and organization: &lt;code&gt;ApiHarbor.RapidApi.Author.ApiName&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fafm5acxhghdbucy1k1p6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fafm5acxhghdbucy1k1p6.png" alt="The screenshot showcasing the initial setup in Visual Studio, emphasizing the selection of .NET Standard 2.0" width="700" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our project's initial layout looks fantastic and promising. The guiding principle here is "less code, more efficiency." At this point, our codebase is a clean slate, perfectly set up for our next steps 😉.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjn4u5lftbqww44elsvnf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjn4u5lftbqww44elsvnf.png" alt="Configure project" width="696" height="190"&gt;&lt;/a&gt;&lt;br&gt;
Now, let's break this perfection by adding the code 😉.&lt;/p&gt;

&lt;h2&gt;
  
  
  Crafting the NetflixApiClient.cs: Connecting to Netflix API
&lt;/h2&gt;

&lt;p&gt;To query an endpoint on RapidApi, two additional header values are crucial:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;X-RapidAPI-Key&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;X-RapidAPI-Host&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can find these in the Code Snippets section on the API's webpage - &lt;a href="https://rapidapi.com/dataocean/api/netflix99"&gt;https://rapidapi.com/dataocean/api/netflix99&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvpual7c2zfz1x9baiwpd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvpual7c2zfz1x9baiwpd.png" alt="The screenshot illustrating where to find these values on the website." width="708" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our &lt;code&gt;NetflixApiClient&lt;/code&gt; constructor should definitely accept a &lt;code&gt;rapidApiKey&lt;/code&gt; for use in requests. Let's consider if we need anything else. For sure something that communicates over &lt;code&gt;http/s&lt;/code&gt;. In C#, there are several methods for this, we can use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-US/dotnet/api/system.net.webclient?view=netstandard-2.0"&gt;WebClient&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.net.webrequest?view=netstandard-2.0"&gt;WebRequest&lt;/a&gt; and &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.net.webresponse?view=netstandard-2.0"&gt;WebResponse&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclient?view=netstandard-2.0"&gt;HttpClient&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://restsharp.dev/"&gt;RestSharp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://flurl.dev/"&gt;Flurl&lt;/a&gt;
and others&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We wouldn't want to restrict the user to a specific method, so our constructor will accept an &lt;code&gt;IWebClient&lt;/code&gt; interface. This way, users can choose their preferred implementation. A logger would also be handy to know what's happening during API usage. We'll follow a similar approach as before, providing a custom &lt;code&gt;ILogger&lt;/code&gt; interface, compelling the user to implement it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing IWebClient
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;IWebClient&lt;/code&gt; should be straightforward, with a single method to retrieve content from a given URL and the ability to add headers to the request.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4nms77dnuouwzjmepq85.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4nms77dnuouwzjmepq85.png" alt="A screenshot show a simple interface design for IWebClient." width="700" height="159"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing ILogger
&lt;/h2&gt;

&lt;p&gt;Here, we aim for simplicity. Our logger should have two methods: one for informational messages and another for handling exceptions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdaavad6bnsaczb2zhz59.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdaavad6bnsaczb2zhz59.png" alt="The screenshot showing the basic structure of the ILogger interface." width="698" height="222"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Returning to our &lt;code&gt;NetflixApiClient.cs&lt;/code&gt;, let's implement what we've outlined so far.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz31jx8o8et3ymiw6o0s4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz31jx8o8et3ymiw6o0s4.png" alt="The screenshot of the initial NetflixApiClient implementation." width="696" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the current implementation, we meet all our initial objectives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Flexibility in passing any &lt;code&gt;http/s&lt;/code&gt; communication implementation.&lt;/li&gt;
&lt;li&gt;Freedom from being tied to any particular logger implementation.&lt;/li&gt;
&lt;li&gt;The constructor accepts our &lt;code&gt;X-RapidAPI-Key&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's move on to the more exciting parts! 🔥&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing Netflix API Methods
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://rapidapi.com/dataocean/api/netflix99"&gt;Netflix API&lt;/a&gt; we're working with provides seven endpoints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Search titles&lt;/strong&gt; - title search (surprise! 😃)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Title lists&lt;/strong&gt; - returns titles according to defined parameters&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Title details&lt;/strong&gt; - returns title details based on the ID from Search title&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Similar titles&lt;/strong&gt; - returns similar titles also with ID received from Search&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Title credits&lt;/strong&gt; - returns a list of actors and people working on the title&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Title media&lt;/strong&gt; - returns a listing of images, posters, videos&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Person details&lt;/strong&gt; - retrieves information about a given actor or team member. Accepts ID received from Title credits.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As our first method to implement, let's choose &lt;code&gt;Search title&lt;/code&gt;, as the other endpoints require IDs returned by this method.&lt;/p&gt;

&lt;h2&gt;
  
  
  Netflix API: Search titles and Implementation
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;Search&lt;/code&gt; titles endpoint accepts several parameters, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;query&lt;/code&gt; - searched phrase&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;order&lt;/code&gt; - sorting of results&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;title type&lt;/code&gt; -  option to return results only for movies or TV shows or all (All)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;country&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;language&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;release year&lt;/code&gt; (from/to)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rating&lt;/code&gt; (min/max)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;token&lt;/code&gt; - for the next page of results&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's make a sample request and examine the response from &lt;code&gt;Search titles&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd0ecs87uvejic3zl2c0j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd0ecs87uvejic3zl2c0j.png" alt="The screenshot of the request and response structure." width="697" height="241"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Observations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Status information is provided (e.g., &lt;code&gt;status: 200&lt;/code&gt; for success).&lt;/li&gt;
&lt;li&gt;Relevant data is assigned to data.&lt;/li&gt;
&lt;li&gt;Separate pagination property includes a prepared URL for the next page and &lt;code&gt;next_page_token&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The total number of results and pages, as well as the number of titles returned per response, are provided.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Inspecting a single title element reveals:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fng5kww6n2nt09splaqot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fng5kww6n2nt09splaqot.png" alt="List key details about the title element." width="691" height="342"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This gives us a good understanding of &lt;code&gt;Search titles&lt;/code&gt;. Let's get to the implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mapping the Response
&lt;/h2&gt;

&lt;p&gt;We'll create a new class to map the JSON response from the API to a &lt;code&gt;SearchTitlesResponse&lt;/code&gt; object. In today's world, manual JSON mapping is a thing of the past. Tools like &lt;a href="https://json2csharp.com/"&gt;json2csharp&lt;/a&gt; make this task a breeze. Let's use it to generate our response class.&lt;/p&gt;

&lt;p&gt;Copy the entire JSON and then paste it into &lt;a href="https://json2csharp.com/"&gt;json2csharp &lt;/a&gt; and click on Convert.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1w0ekkql1gthn7n3ral6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1w0ekkql1gthn7n3ral6.png" alt="The process of using [json2csharp](https://json2csharp.com/)." width="681" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A beautiful response class has been generated for us. We will further enhance it by adding &lt;strong&gt;nullable **fields and using **PascalCase&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fovbhqhndnzwanzs41muo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fovbhqhndnzwanzs41muo.png" alt="Recommended settings." width="307" height="176"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now it's perfect! Just take a look at the response.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd3ohhpbobuc39d634fga.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd3ohhpbobuc39d634fga.png" alt="Response generated by json2csharp.com" width="697" height="579"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our class is ready, let's integrate it into our project.&lt;/p&gt;

&lt;p&gt;As we see something is missing. To use &lt;code&gt;JsonProperty&lt;/code&gt;, we need to install &lt;code&gt;Newtonsoft.Json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frie787cfaqx7epzmp4yi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frie787cfaqx7epzmp4yi.png" alt="Installing Newtonsoft.Json" width="695" height="216"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And by the way, we will implement a static method that will convert (deserialize) pure JSON in text form into a &lt;code&gt;SearchTitlesResponse.Root&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fohvn4f9mu31t3leu2j95.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fohvn4f9mu31t3leu2j95.png" alt="Json deserialization to SearchTitleResponse.Root" width="698" height="216"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The structure of our project currently looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9tszc97mgrd6c31whziq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9tszc97mgrd6c31whziq.png" alt="Structure of the project." width="513" height="213"&gt;&lt;/a&gt;&lt;br&gt;
Great! Now that we can map the JSON to &lt;code&gt;SearchTitlesResponse&lt;/code&gt;, it's time to fetch the JSON from the &lt;a href="https://rapidapi.com/dataocean/api/netflix99"&gt;Netflix API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's go to &lt;code&gt;NetflixApiClient&lt;/code&gt; and implement the method.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyu1gua9xl80ns70xlun7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyu1gua9xl80ns70xlun7.png" alt="Implementing SearchTitles metod in NetflixApiClient class." width="698" height="124"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Remember, Search titles can accept numerous parameters, so let's get those implemented.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fefn8eejv642osxds7j7f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fefn8eejv642osxds7j7f.png" alt="The implementation of the parameters of SearchTitles method." width="700" height="90"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quite a long process. Well, let's move on…&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3h9eh87d57e9ilv9tvpf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3h9eh87d57e9ilv9tvpf.png" alt="Too long process." width="701" height="81"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However let's STOP here! Instead of building a raw URL string in the client, let's create a separate &lt;code&gt;SearchTitlesRequest&lt;/code&gt; class that handles query parameters and returns a formatted URL for communication with the &lt;a href="https://rapidapi.com/dataocean/api/netflix99"&gt;Netflix API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F738lj0ulenflge2g1659.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F738lj0ulenflge2g1659.png" alt="Implementation of SearchTitlesRequest." width="697" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's add another method that will return joined parameters for us.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Falf24075d6zc1o6uhmpn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Falf24075d6zc1o6uhmpn.png" alt="ToQueryParams metod." width="697" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yes. In this way, I avoid writing long strings, I prefer to put each parameter separately into an array and then join them with &amp;amp;. It looks better, right? 😃 Let's look at the full implementation of SearchTitles.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fisuxxuihix07uy305hcl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fisuxxuihix07uy305hcl.png" alt="The complete implementation of SearchTitles methods." width="702" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can call the &lt;code&gt;SearchTitles&lt;/code&gt; method by passing a &lt;code&gt;SearchTitlesRequest&lt;/code&gt; object or using ordinary parameters.&lt;/p&gt;

&lt;p&gt;Now the handling of the Search title endpoint looks awesome!🔥&lt;/p&gt;

&lt;h2&gt;
  
  
  Making IWebClient and ILogger Optional for the User (Dependency Injection)
&lt;/h2&gt;

&lt;p&gt;Before testing our Search method, let's modify one assumption. We gave users the option to implement their own &lt;code&gt;http/s&lt;/code&gt; communication and logger. But not everyone might want to do this. Some might prefer a straightforward way to fetch data without extra implementation. Let's accommodate this preference.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing Default WebClient
&lt;/h2&gt;

&lt;p&gt;We add a new &lt;code&gt;DefaultWebClient&lt;/code&gt; class in &lt;code&gt;Infrastructure.Implementations&lt;/code&gt;, using &lt;code&gt;HttpClient&lt;/code&gt; for requests.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx84gxey52bzgf5t8jzf5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx84gxey52bzgf5t8jzf5.png" alt="The implementation of DefaultWebClient." width="697" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing Default Logger
&lt;/h2&gt;

&lt;p&gt;Similarly, we add a &lt;code&gt;DefaultLogger&lt;/code&gt; class in the same namespace, providing the simplest implementation of the &lt;code&gt;ILogger&lt;/code&gt; interface.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffmlzg3ovusz04rarfjdh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffmlzg3ovusz04rarfjdh.png" alt="The implementation of DefaultLogger." width="699" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The default logger will simply display messages in the Console. Users can always implement their own logger for different outputs, like file logging or database storage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modifying NetflixApiClient Constructor
&lt;/h2&gt;

&lt;p&gt;Since we're not enforcing the use of custom &lt;code&gt;IWebClient&lt;/code&gt; or &lt;code&gt;ILogger&lt;/code&gt;, we need to adjust the constructors of &lt;code&gt;NetflixApiClient&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk6dwpcghx5uejiki1t4v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk6dwpcghx5uejiki1t4v.png" alt="The new constructors providing more flexibility to the user." width="698" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With these new constructors, users now have the choice to use the defaults or implement their own!&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing Search Titles
&lt;/h2&gt;

&lt;p&gt;To test the &lt;a href="https://rapidapi.com/dataocean/api/netflix99"&gt;Netflix API&lt;/a&gt;, all we need is the &lt;code&gt;X-RapidAPI-Key&lt;/code&gt; and some code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffynwz4vtu5s7bkz7mh3r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffynwz4vtu5s7bkz7mh3r.png" alt="The test setup and results." width="704" height="226"&gt;&lt;/a&gt;&lt;br&gt;
Running the console application…&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0n84rbopnxnai3ytk105.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0n84rbopnxnai3ytk105.png" alt="The Big Test!" width="704" height="304"&gt;&lt;/a&gt;&lt;br&gt;
… yields our results. 🔥 Everything works as expected. Great job 🤝&lt;/p&gt;

&lt;p&gt;Let's also test fetching subsequent pages of results using the provided URL.&lt;/p&gt;

&lt;p&gt;We need to modify &lt;code&gt;NetflixApiClient&lt;/code&gt; to add a simple variant of the &lt;code&gt;SearchTitles&lt;/code&gt; method, named &lt;code&gt;SearchTitlesByUrl&lt;/code&gt;, accepting the &lt;code&gt;next_page_url&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2kkeeoy3a0gzznf3vk8g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2kkeeoy3a0gzznf3vk8g.png" alt="The modification of SearchTitle." width="710" height="115"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's modify the test code a bit more in the console application. The modification concerns querying the next page (we have it at hand in &lt;code&gt;NextPageUrl&lt;/code&gt;). The querying loop will operate until Data is not empty. Simple and effective 👌&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk7bf3b4wo3vdz5rfh6ry.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk7bf3b4wo3vdz5rfh6ry.png" alt="Testing code" width="709" height="261"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Running the code with modification from above…&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqrfsehvy6whddngd1gix.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqrfsehvy6whddngd1gix.png" alt="The successful test results." width="709" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;…gives us correct results. We can observe this through the titles come from the next (second) page. Brilliant!&lt;/p&gt;

&lt;p&gt;What's next? I believe it's time to tackle the &lt;code&gt;Title details&lt;/code&gt; endpoint.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;I believe it's time to tackle the Title details endpoint.&lt;/p&gt;

&lt;h2&gt;
  
  
  Netflix API: Title Details and Implementation
&lt;/h2&gt;

&lt;p&gt;From the &lt;a href="https://rapidapi.com/dataocean/api/netflix99"&gt;RapidApi documentation&lt;/a&gt; for &lt;a href="https://rapidapi.com/dataocean/api/netflix99"&gt;Netflix API&lt;/a&gt;, we know that the Title details endpoint requires an id parameter.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3iu6nby3t128v0d7w1x3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3iu6nby3t128v0d7w1x3.png" alt="The Title Details id param documentation." width="705" height="120"&gt;&lt;/a&gt;&lt;br&gt;
As we remember, we can find the id in &lt;code&gt;Search title&lt;/code&gt; and &lt;code&gt;List titles&lt;/code&gt;. Alright, let's start with mapping the response from Title details. We will use the knowledge we have already acquired!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Visit the &lt;a href="https://rapidapi.com/dataocean/api/netflix99"&gt;Netflix API&lt;/a&gt; page on RapidApi.&lt;/li&gt;
&lt;li&gt;Choose the &lt;code&gt;Title details&lt;/code&gt; endpoint and execute it.&lt;/li&gt;
&lt;li&gt;Copy the JSON result.
&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fabc9sj1qr6iyiuuxlo8o.png" alt="Copying the JSON result from the API endpoint." width="709" height="332"&gt;
&lt;/li&gt;
&lt;li&gt;Use &lt;a href="https://json2csharp.com/"&gt;json2csharp &lt;/a&gt; to generate the &lt;code&gt;TitleDetailsResponse&lt;/code&gt; class.&lt;/li&gt;
&lt;li&gt;Remember to set Property Settings as follow
&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faw2cpbeh7920tbzbuyg1.png" alt="json2csharp property settings." width="359" height="170"&gt;
&lt;/li&gt;
&lt;li&gt;We paste the JSON and click 'Convert' button.&lt;/li&gt;
&lt;li&gt;We create a new class in Responses: &lt;code&gt;TitleDetailsResponse&lt;/code&gt; and implement the Create method (as before).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffcoqo0qnpfuex3tkfgbs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffcoqo0qnpfuex3tkfgbs.png" alt="The implementation of TitleDetailsResponse.Create method." width="707" height="239"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Let's see how it looks now&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frz71ohr2zt711qi25p3c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frz71ohr2zt711qi25p3c.png" alt="TitleDatailsResponse" width="709" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JSON to response object mapping seems to be ready!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now let's implement the API request method in our &lt;code&gt;NetflixApiClient&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fygp1gjbhdrdqzpec8w63.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fygp1gjbhdrdqzpec8w63.png" alt="Image description" width="705" height="282"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yes, this simple code is sufficient. This time, we won't implement the creation of the API URL in the response class (&lt;code&gt;TitleDetailsResponse&lt;/code&gt;), as the needed URL is very simple. But of course, following good practices, we should do so… Anyways! We need the test code to check if getting &lt;code&gt;TitleDetails&lt;/code&gt; works.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8kd73jhrcosnzzy5qer1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8kd73jhrcosnzzy5qer1.png" alt="Testing the NetflixApiClient.TitleDetails method." width="715" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8vywq09t08x6d9xuy5j9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8vywq09t08x6d9xuy5j9.png" alt="The result of testing TitleDetails method." width="713" height="415"&gt;&lt;/a&gt;&lt;br&gt;
And there you have it, a quick and efficient implementation! 😊&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Today, we nearly completed an entire library for interacting with the &lt;a href="https://rapidapi.com/dataocean/api/netflix99"&gt;Netflix API&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We added default classes for &lt;code&gt;http/s&lt;/code&gt; communication with API and a console-based logger.&lt;/li&gt;
&lt;li&gt;By using Dependency Injection, we provided the option for users to create their own versions of an HTTP client and logger through our interfaces &lt;code&gt;IWebClient&lt;/code&gt; and &lt;code&gt;ILogger&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Responses are neatly mapped from raw JSON text to Response objects with the help of the &lt;a href="https://json2csharp.com/"&gt;json2csharp.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;And the most important result of the project: we are able to very easily retrieve data from the API using our client class - &lt;code&gt;NetflixApiClient&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything went smoothly and easily… perhaps even too easily 😉&lt;br&gt;
You can check out the entire project on GitHub:&lt;br&gt;
&lt;a href="https://github.com/apiharbor/ApiHarbor.RapidApi.DataOcean.NetflixApi"&gt;https://github.com/apiharbor/ApiHarbor.RapidApi.DataOcean.NetflixApi&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next time, we'll build a sample project using this library… OR! we'll write another article expanding the library with some additional interesting features. We'll see.&lt;/p&gt;

&lt;p&gt;Thanks for your time ❤️ See you!&lt;br&gt;
Follow me to not miss out on future updates! 🔥&lt;/p&gt;

</description>
      <category>programming</category>
      <category>api</category>
      <category>csharp</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
