<?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: Jahir Fiquitiva</title>
    <description>The latest articles on DEV Community by Jahir Fiquitiva (@jahirfiquitiva).</description>
    <link>https://dev.to/jahirfiquitiva</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%2F20618%2Fdff647d7-6990-4f13-9609-2c392c260d96.jpg</url>
      <title>DEV Community: Jahir Fiquitiva</title>
      <link>https://dev.to/jahirfiquitiva</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jahirfiquitiva"/>
    <language>en</language>
    <item>
      <title>Create a Next.js API Route to retrieve GitHub Sponsors data</title>
      <dc:creator>Jahir Fiquitiva</dc:creator>
      <pubDate>Sun, 31 Jul 2022 22:40:57 +0000</pubDate>
      <link>https://dev.to/jahirfiquitiva/create-a-nextjs-api-route-to-retrieve-github-sponsors-data-137a</link>
      <guid>https://dev.to/jahirfiquitiva/create-a-nextjs-api-route-to-retrieve-github-sponsors-data-137a</guid>
      <description>&lt;p&gt;&lt;small&gt;Cover image from &lt;a href="https://www.tinykat.cafe/github-sponsors" rel="noopener noreferrer"&gt;tinykat.cafe&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;For some time I’ve been wanting to be able to get my current GitHub Sponsors data using an API. The API GitHub offers is currently set for GraphQL only, so it was a bit of a struggle to get the data, because I’m not really much familiar with GraphQL. &lt;/p&gt;

&lt;p&gt;Besides that, setting up GraphQL in a project where only one query would be used, seemed like overkill for me. Anyway, I found out that we could send the GraphQL query in a normal REST API request using the body parameter. I used &lt;a href="https://github.com/TiagoDanin/Fetch-GitHub-Graphql" rel="noopener noreferrer"&gt;this repository&lt;/a&gt; for reference.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL:DR;&lt;/strong&gt; You can find the finalized project code at &lt;a href="https://github.com/jahirfiquitiva/sponsors-edge-api" rel="noopener noreferrer"&gt;https://github.com/jahirfiquitiva/sponsors-edge-api&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The GraphQL Query
&lt;/h2&gt;

&lt;p&gt;It took me quite a while to explore the &lt;a href="https://docs.github.com/en/graphql/reference/interfaces#sponsorable" rel="noopener noreferrer"&gt;GitHub GraphQL API docs&lt;/a&gt; and build the query to get all the info needed so I’ll skip the details. I basically used their &lt;a href="https://docs.github.com/en/graphql/overview/explorer" rel="noopener noreferrer"&gt;GraphQL Explorer&lt;/a&gt; and went through multiple &lt;code&gt;Interface&lt;/code&gt;s, &lt;code&gt;Object&lt;/code&gt;s and other data, while doing a trial-and-error process to get the final query.&lt;/p&gt;

&lt;p&gt;Some of the data I used was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User&lt;/li&gt;
&lt;li&gt;Sponsorable&lt;/li&gt;
&lt;li&gt;SponsorConnection&lt;/li&gt;
&lt;li&gt;SponsorsListing&lt;/li&gt;
&lt;li&gt;SponsorsTierConnection&lt;/li&gt;
&lt;li&gt;SponsorsTier&lt;/li&gt;
&lt;li&gt;SponsorsTierAdminInfo&lt;/li&gt;
&lt;li&gt;Sponsorship&lt;/li&gt;
&lt;li&gt;Sponsor&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the final query is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jahirfiquitiva"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;sponsorsListing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;tiers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SponsorsTier&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="n"&gt;adminInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="n"&gt;sponsorships&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="n"&gt;totalRecurringMonthlyPriceInDollars&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sponsorship&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="n"&gt;sponsorEntity&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                      &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="n"&gt;avatarUrl&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="n"&gt;websiteUrl&lt;/span&gt;&lt;span class="w"&gt;
                      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
                      &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Organization&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="n"&gt;avatarUrl&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="n"&gt;websiteUrl&lt;/span&gt;&lt;span class="w"&gt;
                      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="n"&gt;tierSelectedAt&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="n"&gt;monthlyPriceInDollars&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="n"&gt;isOneTime&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="n"&gt;isCustomAmount&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sponsorable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;sponsors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;totalCount&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What does this query do?
&lt;/h3&gt;

&lt;p&gt;Basically, it gets the GitHub Sponsors listing data and the sponsors total count for the user defined at the query beginning: &lt;code&gt;user(login: "jahirfiquitiva")&lt;/code&gt; here I used my GitHub username, but you can replace it with yours.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I am getting the listing data because I wanted to group my sponsors by their tier, as well as knowing the tier price and other details. If you only wanted to know the sponsors, regardless of their tier, a simpler query might be built using the &lt;code&gt;sponsors&lt;/code&gt; property at the end of the query above.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;From the Sponsors listing data, I get the different tiers. A tier is basically a donation option, for example, I have &lt;a href="https://github.com/sponsors/jahirfiquitiva" rel="noopener noreferrer"&gt;6 monthly tiers&lt;/a&gt;: star, crystal ball, rocket, robot, lightning and diamond based on different price. This is because I “named” them although they don’t really have a name by default. This just helps me categorize my sponsors.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;tiers(first: 20)&lt;/code&gt; will return the first 20 tiers from your sponsors listing. As I said, I have 6 monthly tiers, and 3 one-time tiers: 9 tiers in total, so even 20 is more than needed. Also, you can only have a total of 10 published monthly tiers and 10 published one-time tiers.&lt;/p&gt;

&lt;p&gt;From each tier, I get the following info:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;monthlyPriceInDollars&lt;/code&gt;: How much this tier costs per month in USD.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;isOneTime&lt;/code&gt;: Whether this tier is only for use with one-time sponsorships.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;isCustomAmount&lt;/code&gt;: Whether this tier was chosen at checkout time by the sponsor rather than defined ahead of time by the maintainer who manages the Sponsors listing.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;name&lt;/code&gt;: The name of the tier. (iirc this name is just something like &lt;code&gt;${price} per month&lt;/code&gt;, which might not be very helpful depending on the use case)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;description&lt;/code&gt;: The description of the tier. (in MarkDown format)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;adminInfo&lt;/code&gt;: Object that contains the &lt;code&gt;sponsorships&lt;/code&gt; property, which includes:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;totalRecurringMonthlyPriceInDollars&lt;/code&gt;: The total amount in USD of all recurring sponsorships in the connection whose amount you can view. Does not include one-time sponsorships.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;nodes&lt;/code&gt;: Which would correspond to data related to the sponsorship, including the sponsor information using the &lt;code&gt;sponsorEntity&lt;/code&gt; property. &lt;code&gt;sponsorEntity&lt;/code&gt; can be a User or Organization, so that’s why we access both.

&lt;ul&gt;
&lt;li&gt;Additionally, &lt;code&gt;sponsorEntity&lt;/code&gt; includes &lt;code&gt;tierSelectedAt&lt;/code&gt; which identifies the date and time when the given tier was chosen for this sponsorship.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;sponsorships(first: 100)&lt;/code&gt; returns the first 100 nodes for this sponsorship tier. I don’t really have many sponsors, so this one is fine for me. If you have more sponsors, you’ll have to look into &lt;a href="https://docs.github.com/en/graphql/reference/objects#sponsorshipconnection" rel="noopener noreferrer"&gt;pagination&lt;/a&gt; for this property.&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;If you need more information about your sponsors or the sponsorships, you can &lt;a href="https://docs.github.com/en/graphql/reference/objects#sponsorconnection" rel="noopener noreferrer"&gt;explore the docs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authorization
&lt;/h2&gt;

&lt;p&gt;Before we actually use this query to access this data, we must create a Personal Access Token, as it requires authorization.&lt;/p&gt;

&lt;p&gt;To do so, go to your GitHub account Settings, then go to Developer Settings and finally select Personal Access Tokens, or just follow this link: &lt;a href="https://github.com/settings/tokens" rel="noopener noreferrer"&gt;https://github.com/settings/tokens&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There, click on the &lt;a href="https://github.com/settings/tokens/new" rel="noopener noreferrer"&gt;&lt;code&gt;Generate new token&lt;/code&gt;&lt;/a&gt; button, give it a specific name, set the expiration period to one you’d like, although this one only reads data, so I think &lt;code&gt;No expiration&lt;/code&gt; is fine.&lt;/p&gt;

&lt;p&gt;The scopes required for this query are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ]  admin:org

&lt;ul&gt;
&lt;li&gt;[x]  read:org&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;[ ]  user

&lt;ul&gt;
&lt;li&gt;[x]  read:user&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Then scroll down and click on &lt;code&gt;Generate token&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Make sure to save the token in a safe and accessible place, as you &lt;strong&gt;won’t&lt;/strong&gt; be able to access its value ever again.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Project setup
&lt;/h2&gt;

&lt;p&gt;Let’s create a new NextJS project. We’ll use TypeScript in this guide, so we do it with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="err"&gt;npx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;create-next-app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;--ts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;folder&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;{folder}&lt;/code&gt; with the name of the folder you want the project to be at.&lt;/p&gt;

&lt;p&gt;Now, open the project with your favorite editor or IDE.&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;.env.local&lt;/code&gt; file with the Personal Access Token previously generated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GH_PAT=ghp_XXxxXXxxXX
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can name the variable differently, but be careful when we access it in code later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initial request
&lt;/h2&gt;

&lt;p&gt;Let’s quickly setup the API and the code to make an initial request.&lt;/p&gt;

&lt;p&gt;Aiming to keep things organized, let’s create a folder named &lt;code&gt;lib&lt;/code&gt; on the project root, and another folder named &lt;code&gt;sponsors&lt;/code&gt; inside.&lt;/p&gt;

&lt;p&gt;Create a file named &lt;code&gt;request.ts&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { GH_PAT: githubPat = '' } = process.env;

const graphQlQuery = `
...
`;

export const getSponsorsGraphQLResponse = async () =&amp;gt; {
  return fetch('https://api.github.com/graphql', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${githubPat}` },
    body: JSON.stringify({ query: graphQlQuery }),
  }).then((res) =&amp;gt; res.json());
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Put the query content from the one showed at the beginning of this post, inside the backticks in &lt;code&gt;graphQlQuery&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here we are getting GitHub Personal Access Token (PAT) via the &lt;code&gt;GH_PAT&lt;/code&gt; environment variable (setup previously in &lt;code&gt;.env.local&lt;/code&gt;), and creating a function that will do a simple fetch POST request to &lt;a href="https://api.github.com/graphql" rel="noopener noreferrer"&gt;&lt;code&gt;https://api.github.com/graphql&lt;/code&gt;&lt;/a&gt; sending the PAT in an &lt;code&gt;Authorization&lt;/code&gt; header, then get the JSON body from the response and return it.&lt;/p&gt;

&lt;p&gt;Now create a file named &lt;code&gt;index.ts&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export * from './request';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we just export everything already exported in the &lt;code&gt;request.ts&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Now, let’s setup the API route. Go to file &lt;code&gt;pages/api/hello.ts&lt;/code&gt; and rename it to &lt;code&gt;sponsors.ts&lt;/code&gt;, there, modify it to look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import type { NextApiRequest, NextApiResponse } from 'next';
import { getSponsorsGraphQLResponse } from './../../lib/sponsors/request';

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  const rawResponse = await getSponsorsGraphQLResponse();
  return res.status(200).json(rawResponse);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we import the function previously created, then we call it using the &lt;code&gt;async&lt;/code&gt; function &lt;code&gt;handler&lt;/code&gt; , then we get the JSON body from it and return it as our API response.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing
&lt;/h3&gt;

&lt;p&gt;Let’s test our simple API, in order to do that, run &lt;code&gt;npm run dev&lt;/code&gt; or &lt;code&gt;yarn dev&lt;/code&gt; in your Terminal or CMD from the project root.&lt;/p&gt;

&lt;p&gt;Once the project is running, you’ll see this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ready - started server on 0.0.0.0:3000, url: http://localhost:3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, go to &lt;code&gt;http://localhost:3000/api/sponsors&lt;/code&gt;, if everything was setup correctly, you will see the raw response from the API, which format isn’t really nice to read or use, and looks like this:&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="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"sponsorsListing"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MDExxxxxxxxxxxxxxxx=="&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"tiers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"nodes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MDExxxxxxxxxxxxxxxx=="&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"adminInfo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"sponsorships"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"totalRecurringMonthlyPriceInDollars"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"nodes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                      &lt;/span&gt;&lt;span class="nl"&gt;"sponsorEntity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="nl"&gt;"login"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xxxx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="nl"&gt;"avatarUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://avatars.githubusercontent.com/u/xxxxxx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Xxxxx Xxxxx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="nl"&gt;"websiteUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://jahir.dev/"&lt;/span&gt;&lt;span class="w"&gt;
                      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                      &lt;/span&gt;&lt;span class="nl"&gt;"tierSelectedAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2022-03-02T07:59:51Z"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"monthlyPriceInDollars"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"isOneTime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"isCustomAmount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$2 a month"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Lorem ipsum dolor sit amet."&lt;/span&gt;&lt;span class="w"&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;...&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"sponsors"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"totalCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;I recommend using the &lt;a href="https://chrome.google.com/webstore/detail/ink-for-google/hmanckoiohnlgdommlcckcflkmllobgj" rel="noopener noreferrer"&gt;JSON viewer extension&lt;/a&gt;, to read the response more easily&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Typing raw response
&lt;/h2&gt;

&lt;p&gt;Let’s define interfaces for the raw response from the GitHub GraphQL API. Create a file named &lt;code&gt;types.ts&lt;/code&gt; under the &lt;code&gt;lib/sponsors&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;We can start with the deepest nested object, which would be the &lt;code&gt;sponsorEntity&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export interface SponsorEntity {
  login: string;
  name?: string;
  avatarUrl: string;
  websiteUrl?: string;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can go one level up to &lt;code&gt;sponsorships&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface Sponsorships {
  totalRecurringMonthlyPriceInDollars: number;
  nodes: Array&amp;lt;{
    sponsorEntity: SponsorEntity;
    tierSelectedAt?: string; // TimeStamp
  }&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since &lt;code&gt;adminInfo&lt;/code&gt; only includes the &lt;code&gt;sponsorships&lt;/code&gt; property, let’s go a couple levels up at a time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export interface SponsorsTier {
  id: string;
  adminInfo?: {
    sponsorships: Sponsorships;
  };
  monthlyPriceInDollars: number;
  isOneTime: boolean;
  isCustomAmount: boolean;
  name: string;
  description?: string;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let’s go up to &lt;code&gt;sponsorsListing&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface SponsorsListing {
  id: string;
  tiers: {
    nodes: Array&amp;lt;SponsorsTier&amp;gt;;
  };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally the whole response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export interface SponsorsResponse {
  data?: {
    user: {
      sponsorsListing: SponsorsListing;
      sponsors: {
        totalCount: number;
      };
    };
  };
  message?: string;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, can import the &lt;code&gt;SponsorsResponse&lt;/code&gt; interface in &lt;code&gt;request.ts&lt;/code&gt; and type the &lt;code&gt;getSponsorsGraphQLResponse&lt;/code&gt; function, so it will look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import type { SponsorsResponse } from './types';

...

export const getSponsorsGraphQLResponse = async (): Promise&amp;lt;SponsorsResponse&amp;gt; =&amp;gt; {
  ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Typing the response won’t affect anything in the API as it is at this point, but will allow us to transform that data into a more readable format in an easy way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Transforming the raw response
&lt;/h3&gt;

&lt;p&gt;First, let’s plan the desired object format to make the response easier to read:&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="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tiers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MDExxxxxxxxxxxxxxxx=="&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"isOneTime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"isCustomAmount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$2 a month"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Lorem ipsum dolor sit amet."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"totalEarningsPerMonth"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"sponsors"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xxxx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Xxxxx Xxxxx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"avatar"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://avatars.githubusercontent.com/u/xxxxxx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"website"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://jahir.dev/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"since"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2022-03-02T07:59:51Z"&lt;/span&gt;&lt;span class="w"&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;...&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&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;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"total"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this format, we have an object with 2 properties: &lt;code&gt;tiers&lt;/code&gt; and &lt;code&gt;total&lt;/code&gt;. Tiers will have all its corresponding information including a &lt;code&gt;sponsors&lt;/code&gt; object array with the information for each sponsor. There’s a couple fields renamed from the raw response, to make them a bit simpler:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;login&lt;/code&gt; → &lt;code&gt;username&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;avatarUrl&lt;/code&gt; → &lt;code&gt;avatar&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;websiteUrl&lt;/code&gt; → &lt;code&gt;website&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tierSelectedAt&lt;/code&gt; → &lt;code&gt;since&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;totalRecurringMonthlyPriceInDollars&lt;/code&gt; → &lt;code&gt;totalEarningsPerMonth&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;totalCount&lt;/code&gt; → &lt;code&gt;total&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s create the interfaces for this new object in &lt;code&gt;lib/sponsors/types.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export interface Sponsor {
  username: string;
  name?: string;
  avatar: string;
  website?: string;
  since?: string;
}

export interface Tier {
  id: string;
  price: number;
  isOneTime: boolean;
  isCustomAmount: boolean;
  name: string;
  description?: string;
  totalEarningsPerMonth: number;
  sponsors: Array&amp;lt;Sponsor&amp;gt;;
}

export interface Sponsors {
  tiers: Array&amp;lt;Tier&amp;gt;;
  total: number;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, let’s create a function to transform the &lt;code&gt;SponsorsResponse&lt;/code&gt; object into the &lt;code&gt;Sponsors&lt;/code&gt; one, in the &lt;code&gt;lib/sponsors/request.ts&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import type {
  SponsorsResponse,
  Sponsors,
  SponsorEntity,
  Sponsor,
  SponsorsTier,
  Tier,
} from './types';

...

const transformSponsorEntityIntoSponsor = (
  entity: SponsorEntity,
  tierSelectedAt?: string
): Sponsor =&amp;gt; {
  return {
    name: entity.name,
    username: entity.login,
    avatar: entity.avatarUrl,
    website: entity.websiteUrl,
    since: tierSelectedAt,
  };
};

const transformRawTierIntoTier = (tier: SponsorsTier): Tier =&amp;gt; {
  return {
    id: tier.id,
    price: tier.monthlyPriceInDollars,
    isOneTime: tier.isOneTime,
    isCustomAmount: tier.isCustomAmount,
    name: tier.name,
    description: tier.description,
    totalEarningsPerMonth: tier.adminInfo?.sponsorships.totalRecurringMonthlyPriceInDollars || 0,
    sponsors: (tier.adminInfo?.sponsorships?.nodes || []).map((node) =&amp;gt; {
      // Transform `SponsorEntity` into `Sponsor` using the `transformSponsorEntityIntoSponsor` function
      // and the `tierSelectedAt` property
      return transformSponsorEntityIntoSponsor(node.sponsorEntity, node.tierSelectedAt);
    }),
  };
};

export const transformResponseIntoSponsorships = (rawResponse: SponsorsResponse): Sponsors =&amp;gt; {
  // Get the listing and sponsors object from the raw response.
  // We rename `sponsorsListing` to just `listing` for ease.
  // This is done locally only and does not modify the `rawResponse` object.const { sponsorsListing: listing, sponsors } = rawResponse.data?.user || {};
  if (!listing || !sponsors) {
    return { tiers: [], total: 0 };
  }
  return {
    // Transform `SponsorsTier` into `Tier` using the `transformRawTierIntoTier` function
    tiers: listing.tiers.nodes.map(transformRawTierIntoTier),
    total: sponsors.totalCount,
  };
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, let’s update our API to use the new function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import type { NextApiRequest, NextApiResponse } from 'next';
import {
  getSponsorsGraphQLResponse,
  transformResponseIntoSponsorships,
} from './../../lib/sponsors/request';

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  const rawResponse = await getSponsorsGraphQLResponse();
  return res.status(200).json(transformResponseIntoSponsorships(rawResponse));
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now if we go to &lt;code&gt;http://localhost:3000/api/sponsors&lt;/code&gt;, we will see a response with the format we initially planned for. 🎉&lt;/p&gt;

&lt;p&gt;You can try the deployed version of this endpoint at &lt;a href="https://sponsors-edge-api.vercel.app/api/sponsors" rel="noopener noreferrer"&gt;https://sponsors-edge-api.vercel.app/api/sponsors&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Extra: Edge Runtime
&lt;/h2&gt;

&lt;p&gt;Additionally, and this is completely optional, we can modify the API to use the new Edge Runtime.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Next.js Edge Runtime is based on standard Web APIs. The &lt;a href="https://nextjs.org/docs/api-routes/edge-api-routes" rel="noopener noreferrer"&gt;Edge API routes&lt;/a&gt;, enable you to build high performance APIs with Next.js. Using the &lt;a href="https://nextjs.org/docs/api-reference/edge-runtime" rel="noopener noreferrer"&gt;Edge Runtime&lt;/a&gt;, they are often faster than Node.js-based API Routes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To achieve this, we can modify the API to be like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- import type { NextApiRequest, NextApiResponse } from 'next';
+ import type { NextRequest } from 'next/server';
import {
  getSponsorsGraphQLResponse,
  transformResponseIntoSponsorships,
} from './../../lib/sponsors/request';

export const config = {
  runtime: 'experimental-edge',
};

- export default async function handler(req: NextApiRequest, res: NextApiResponse) {
+ export default async function handler(req: NextRequest) {
  const rawResponse = await getSponsorsGraphQLResponse();
-  return res.status(200).json(transformResponseIntoSponsorships(rawResponse));
+  return new Response(JSON.stringify(transformResponseIntoSponsorships(rawResponse)), {
+    status: 200,
+    headers: { 'content-type': 'application/json' },
+  });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we change the type &lt;code&gt;NextApiRequest&lt;/code&gt; for &lt;code&gt;NextRequest&lt;/code&gt;, remove the &lt;code&gt;res&lt;/code&gt; parameter from the handler function, and change the way we return the JSON response by using the &lt;code&gt;Response&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;You can try the deployed version of this endpoint at &lt;a href="https://sponsors-edge-api.vercel.app/api/sponsors-edge" rel="noopener noreferrer"&gt;https://sponsors-edge-api.vercel.app/api/sponsors-edge&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing up
&lt;/h2&gt;

&lt;p&gt;That’s it, now you have an API to get your GitHub sponsors and use that data to anything you’d like.&lt;/p&gt;

&lt;p&gt;I have used it to list &lt;a href="https://jahir.dev/donate#thanks" rel="noopener noreferrer"&gt;my sponsors&lt;/a&gt; in my &lt;a href="https://jahir.dev/donate" rel="noopener noreferrer"&gt;donate page&lt;/a&gt;, for example. I hope it’s useful for you too.&lt;/p&gt;

&lt;p&gt;You can find the finalized project code at &lt;a href="https://github.com/jahirfiquitiva/sponsors-edge-api" rel="noopener noreferrer"&gt;https://github.com/jahirfiquitiva/sponsors-edge-api&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Have a great day! 👋😀&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>graphql</category>
      <category>nextjs</category>
      <category>github</category>
    </item>
    <item>
      <title>Things you can do to get started with development</title>
      <dc:creator>Jahir Fiquitiva</dc:creator>
      <pubDate>Wed, 05 Jan 2022 23:48:35 +0000</pubDate>
      <link>https://dev.to/jahirfiquitiva/things-you-can-do-to-get-started-with-development-ehe</link>
      <guid>https://dev.to/jahirfiquitiva/things-you-can-do-to-get-started-with-development-ehe</guid>
      <description>&lt;p&gt;I think a few of the first things you’ll need are: patience, time and willingness to learn.&lt;/p&gt;

&lt;p&gt;Patience and time because learning is a long process. I think once you start, you will also keep finding more and more things to learn. You don’t need to do it all at once. Take your time, go at your own pace and you eventually will.&lt;/p&gt;

&lt;p&gt;Really, try not to feel overwhelmed by the amount of things to learn. There’s always more coming and being built, but it’s ok to not know them all.&lt;br&gt;
What I suggest you do is try to explore a few, find the ones you like or enjoy using the most and then learn and practice a lot about it.&lt;/p&gt;

&lt;p&gt;The willingness to learn will keep you focused and help you overcome many challenges you might find during the process.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjahir.dev%2Fstatic%2Fimages%2Fblog%2Fthings-to-get-started-development%2Froadmap.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjahir.dev%2Fstatic%2Fimages%2Fblog%2Fthings-to-get-started-development%2Froadmap.jpg" alt="Image of a todo list in a notebook" width="800" height="400"&gt;&lt;/a&gt;&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Choose a path
&lt;/h3&gt;

&lt;p&gt;Now, to get started with development you will need to choose a path, and I know it might be hard at the beginning if you haven’t explored any before. I think you can start by asking yourself what kind of things you would like to build, be it websites, server-side work, mobile apps (for android or iOS), desktop apps along others.&lt;/p&gt;

&lt;p&gt;The next things I will mention are mostly not focused on a single path, therefore you might be a bit lost on where to start. Like, which topics should you learn first for the path you’ve chosen?&lt;/p&gt;

&lt;p&gt;Well, &lt;a href="https://roadmap.sh/" rel="noopener noreferrer"&gt;Developer Roadmaps&lt;/a&gt; is a great tool that can help you with that. It will show you the whole path you can follow to become a developer on a specific area. From the basics to complex stuff.&lt;/p&gt;

&lt;h3&gt;
  
  
  Find resources
&lt;/h3&gt;

&lt;p&gt;Here’s a few sites that will provide resources or content for you to keep learning and get deep into the topics you want to explore.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.freecodecamp.org/" rel="noopener noreferrer"&gt;FreeCodeCamp&lt;/a&gt;:&lt;br&gt;
This platform includes articles and interactive courses to learn about algorithms and data structures, web, backend, python and much more. The content is translated to multiple languages and you can also even get certifications for what you learn. Everything completely free&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.codewell.cc/" rel="noopener noreferrer"&gt;Codewell&lt;/a&gt;:&lt;br&gt;
Provides different challenging projects for you to build and practice your web development skills. You will get access to design assets so you can have a reference of what you would build. Many of them are free.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;YouTube and Udemy&lt;br&gt;
You will find many on these platforms. Courses on Udemy might not be free, but they frequently have discounts, and you can access them anytime, anywhere, and learn little by little, at your own pace.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Git and GitHub
&lt;/h3&gt;

&lt;p&gt;Learning git is really important. If you learn it in your early days as a developer, you will already have a useful skill.&lt;/p&gt;

&lt;p&gt;Git can help you have your projects stored somewhere on the internet, allowing you to work on them from anywhere, plus also allowing you to do collaborative work and even learn by helping others when contributing to their projects.&lt;/p&gt;

&lt;p&gt;GitHub is one of the platforms you can use to store your projects. Other options are GitLab, BitBucket and there’s even self-hosted options such as &lt;a href="https://gitea.io/" rel="noopener noreferrer"&gt;Gitea&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Some resources to help you learn about these tools are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/learn/modules/intro-to-git/" rel="noopener noreferrer"&gt;Microsoft’s Introduction to Git&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.udemy.com/course/learngit/" rel="noopener noreferrer"&gt;Free Git course on Udemy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.freecodecamp.org/news/learn-the-basics-of-git-in-under-10-minutes-da548267cc91/" rel="noopener noreferrer"&gt;Git basics on FreeCodeCamp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lab.github.com/" rel="noopener noreferrer"&gt;GitHub Learning Lab&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjahir.dev%2Fstatic%2Fimages%2Fblog%2Fthings-to-get-started-development%2Fresources.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjahir.dev%2Fstatic%2Fimages%2Fblog%2Fthings-to-get-started-development%2Fresources.jpg" alt="Image of glasses in front of a blurred laptop" width="800" height="400"&gt;&lt;/a&gt;&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Get better at search
&lt;/h3&gt;

&lt;p&gt;While learning, you will usually find yourself searching for concepts, videos, tutorials and more about the topics you’re learning.&lt;/p&gt;

&lt;p&gt;When searching, it’s important that you learn to find the best and most interesting/useful results.&lt;/p&gt;

&lt;p&gt;One thing you can do is using search operators, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Quotes&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;Will provide results including exactly that text.&lt;/p&gt;

&lt;p&gt;Example: &lt;code&gt;android "FloatingActionButton"&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Site&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;site&lt;/code&gt; operator will bring results from a specific website.&lt;/p&gt;

&lt;p&gt;Example: &lt;code&gt;javascript site:dev.to&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With just these two, I’ve always found great results. You can find more advanced and complex search operators &lt;a href="https://ahrefs.com/blog/google-advanced-search-operators/" rel="noopener noreferrer"&gt;on this site&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Additionally, even if you’re primary language is other than English, I suggest you do search in English. You will find even more content and you will be working on an extra skill.&lt;/p&gt;

&lt;p&gt;Searching can also help with getting more specific results. Say you want to create a rounded button for a website. When you search with those exact words, you will find results focused on achieving that, instead of long blog posts or videos telling a lot of other things too. Which isn’t bad at all, but I have found myself wanting to go straight to the point, and that specifying what I’m looking for has helped.&lt;/p&gt;

&lt;h3&gt;
  
  
  Learn by example
&lt;/h3&gt;

&lt;p&gt;When I was starting, I usually looked at existing projects on GitHub and I still do every now and then. Exploring their code, how they are built, the tools, frameworks or libraries they use, all those things provide a wider view about the things I can do and learn about.&lt;/p&gt;

&lt;p&gt;Besides seeing the code of others has helped me learn a bit about best practices, why a thing is chosen instead of another, how a project can be structured and more.&lt;/p&gt;

&lt;h3&gt;
  
  
  Learn with games
&lt;/h3&gt;

&lt;p&gt;I just know a couple games that are focused on learning CSS, but if these exist, I’m sure there’s more out there to learn about other stuff. If you eventually get interested in CSS, these might come in handy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://flexboxfroggy.com/" rel="noopener noreferrer"&gt;Flexbox Froggy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cssgridgarden.com/" rel="noopener noreferrer"&gt;Grid Garden&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.guess-css.app/" rel="noopener noreferrer"&gt;Guess CSS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://codepip.com/games/" rel="noopener noreferrer"&gt;More codepip games&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These might result in a more interactive and fun way to learn.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjahir.dev%2Fstatic%2Fimages%2Fblog%2Fthings-to-get-started-development%2Fbuild.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjahir.dev%2Fstatic%2Fimages%2Fblog%2Fthings-to-get-started-development%2Fbuild.jpg" alt="Image of a person highlighting texts in front of a computer" width="800" height="400"&gt;&lt;/a&gt;&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Build!
&lt;/h3&gt;

&lt;p&gt;You should really put the things you learn into practice. Don’t just stay with what you watch in videos, read in blogs or tutorials, and your notes. Build projects.&lt;/p&gt;

&lt;p&gt;Many of the resources you might find, will encourage you or guide you to build projects while learning. If that’s the case, dare to build something else too. Build a different project where you can implement the same concepts and even a few more. Or give a twist to the project you’ve built and give your own touch to it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ask for help
&lt;/h3&gt;

&lt;p&gt;Yeah, if you feel lost at some point, don’t know what to do next, or have trouble understanding a concept, feel free to ask for help. Asking for help is ok and there’s nothing bad about it.&lt;/p&gt;

&lt;p&gt;On Twitter there’s a lot of people that wouldn’t mind sharing feedback and support. You just have to find the right ones and get in touch. What I’d suggest though, is you do it in public, via a tweet, instead of a private message. Believe it or not, many people might have a similar question, or get benefit of the reply you get so they can learn a bit more too.&lt;/p&gt;

&lt;p&gt;You can also find many posts on &lt;a href="https://dev.to/"&gt;dev.to&lt;/a&gt; with advice, guidance, questions and more. Go to that site and search for the topic you’re learning or use the &lt;code&gt;site:&lt;/code&gt; operator in your favorite search provider/tool. &lt;a href="https://dev.to/"&gt;dev.to&lt;/a&gt; is definitely a great place for learning and sharing knowledge, and people are always nice and kind and open to provide help if you need it.&lt;/p&gt;



&lt;p&gt;That’s it for now. If you know more resources or things you think I could add to this post, feel free to &lt;a href="https://jahir.dev/contact" rel="noopener noreferrer"&gt;share them with me&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thank you for reading. Until next time 👋&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://jahir.dev/blog/things-to-get-started-development" rel="noopener noreferrer"&gt;jahir.dev&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>career</category>
      <category>codenewbie</category>
      <category>motivation</category>
    </item>
    <item>
      <title>Publishing a React component package on npm</title>
      <dc:creator>Jahir Fiquitiva</dc:creator>
      <pubDate>Sun, 02 Aug 2020 23:01:07 +0000</pubDate>
      <link>https://dev.to/jahirfiquitiva/publishing-a-react-component-package-on-npm-3dn5</link>
      <guid>https://dev.to/jahirfiquitiva/publishing-a-react-component-package-on-npm-3dn5</guid>
      <description>&lt;p&gt;Recently at work I had to create and publish a React component on npm, which is planned to be used in multiple projects with little functionality or styles changes.&lt;/p&gt;

&lt;p&gt;Due to being a company project, I can't share the source code, but I will share some important snippets as needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  It isn't as easy as expected 😕
&lt;/h3&gt;

&lt;p&gt;When I was asked to do such task, we already had the component built and working as a &lt;code&gt;create-react-app&lt;/code&gt; project, which was also a website and stuff.&lt;/p&gt;

&lt;p&gt;I thought it would be as simple as running &lt;code&gt;npm publish&lt;/code&gt; and that I was going to be able to import it in the other project right away.&lt;/p&gt;

&lt;p&gt;Unfortunately it wasn't like that and I ran into compilation issues in the project that implemented it. So I started looking for the &lt;em&gt;right&lt;/em&gt; way to do it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Meet &lt;code&gt;create-react-library&lt;/code&gt; 🤓
&lt;/h3&gt;

&lt;p&gt;While searching how to achieve that, I came across with &lt;a href="https://github.com/transitive-bullshit/create-react-library" rel="noopener noreferrer"&gt;&lt;code&gt;create-react-library&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I was looking for the simplest approach to do what I needed, and didn't want to deal with &lt;code&gt;webpack&lt;/code&gt; or &lt;code&gt;babel&lt;/code&gt; stuff and whatnot, so that project definitely came in handy because it was easy to use and pretty straight forward.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using &lt;code&gt;create-react-library&lt;/code&gt; 👨🏼‍💻
&lt;/h3&gt;

&lt;p&gt;Creating a library project is as easy as running&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-react-library project-name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will be prompted for some config, similar to &lt;code&gt;create-react-app&lt;/code&gt;, but once done, you get the project and everything setup to work right away.&lt;/p&gt;

&lt;p&gt;I liked it because I didn't have to do much else, and it also comes with an example project inside, that uses your library, so you can test everything will be working properly after you've "published" the package.&lt;/p&gt;

&lt;p&gt;Next thing for me was just migrating the component from the previous project to the library project. It was pretty much a copy-paste process with some little refactoring, but nothing significant else.&lt;/p&gt;

&lt;h3&gt;
  
  
  The challenges 😬
&lt;/h3&gt;

&lt;p&gt;Despite requiring no configuration, I encountered a couple problems during the process...&lt;/p&gt;

&lt;h5&gt;
  
  
  1. React Fragments 🖼
&lt;/h5&gt;

&lt;p&gt;I was getting compilation errors for using React Fragments like this &lt;code&gt;&amp;lt;&amp;gt;{...}&amp;lt;/&amp;gt;&lt;/code&gt;, so I changed that to &lt;code&gt;&amp;lt;React.Fragment&amp;gt;{...}&amp;lt;/React.Fragment&amp;gt;&lt;/code&gt; and they stopped... well, kinda.&lt;/p&gt;

&lt;p&gt;Then I started getting &lt;code&gt;ReferenceError: Fragment is not defined&lt;/code&gt; errors. It wasn't easy to solve so I asked for help in the &lt;a href="https://discord.gg/FMcvc6T" rel="noopener noreferrer"&gt;Unicorn Utterances&lt;/a&gt; discord server, and &lt;a href="http://crutchcorn.dev/" rel="noopener noreferrer"&gt;Corbin&lt;/a&gt; found &lt;a href="https://github.com/transitive-bullshit/create-react-library/issues/243#issuecomment-653525598" rel="noopener noreferrer"&gt;an issue&lt;/a&gt; in the &lt;code&gt;create-react-library&lt;/code&gt; repo that mentioned adding &lt;code&gt;--jsxFragment React.Fragment&lt;/code&gt; to the &lt;code&gt;build&lt;/code&gt; and &lt;code&gt;start&lt;/code&gt; scripts.&lt;/p&gt;

&lt;p&gt;And then it was all working again.&lt;/p&gt;

&lt;h5&gt;
  
  
  2. Included SVGs 📐
&lt;/h5&gt;

&lt;p&gt;The component included an SVG (the company logo), imported and used something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;CompanyLogo&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./company-logo.svg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;CompanyLogo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Company Logo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;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;It worked fine locally, even with the local project that imported the component library, but after published in npm and imported in the other project, compilation failed, because the svg file was "compiled" with a different name, similar to &lt;code&gt;company-logo~aBcDe.svg&lt;/code&gt;. Notice the &lt;code&gt;~&lt;/code&gt; character. That was the issue, because it can't be used in JS var names.&lt;/p&gt;

&lt;p&gt;The quick solution, was to make it a prop and allow passing it to the component, so it wasn't compiled by the library but the other project. Again, I didn't want to deal with &lt;code&gt;webpack&lt;/code&gt; or &lt;code&gt;babel&lt;/code&gt; or any extra config, so this was the easiest for me.&lt;/p&gt;

&lt;h5&gt;
  
  
  3. CSS 🎨
&lt;/h5&gt;

&lt;p&gt;I was using css modules for the library components, but I also needed a little of normal css, because the component used other components from &lt;a href="//rmwc.io"&gt;&lt;code&gt;rmwc&lt;/code&gt;&lt;/a&gt;, and they use that and I needed to override a few styles.&lt;/p&gt;

&lt;p&gt;From what I understood &lt;code&gt;create-react-library&lt;/code&gt; the normal css and the module css files would coexist and work along normally, but for some reason, it wasn't like that, and the normal css was still compiled as a module, i.e. the compiled classes names would have some random suffix to make them unique, and therefore none of the overriden styles were applied.&lt;/p&gt;

&lt;p&gt;At the end, I ended up changing the css modules to normal css, so no suffix was added during compilation, and then it all worked as expected.&lt;/p&gt;

&lt;h3&gt;
  
  
  Closing up 👋🏼
&lt;/h3&gt;

&lt;p&gt;So, after struggling with those few things, I was able to use the component from the library without any other issues, and everything was working as expected, including react hooks like &lt;code&gt;useContext&lt;/code&gt; and &lt;code&gt;useReducer&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Also, &lt;code&gt;create-react-library&lt;/code&gt; definitely allowed publishing the package by just running &lt;code&gt;npm publish&lt;/code&gt; as I wanted it to be.&lt;/p&gt;

&lt;p&gt;There are probably other approaches to build a react component(s) package, but this one worked for me and was easy to use, so I liked it and wanted to share my experience.&lt;/p&gt;

&lt;p&gt;If you have further questions, I'll try to answer.&lt;br&gt;
Find more about me @ &lt;a href="https://jahir.dev" rel="noopener noreferrer"&gt;jahir.dev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Special thanks to &lt;a href="http://crutchcorn.dev/" rel="noopener noreferrer"&gt;Corbin Crutchley&lt;/a&gt;, &lt;a href="https://ajd.sh/" rel="noopener noreferrer"&gt;Alex Dueppen&lt;/a&gt; and Robert Mennell from the &lt;a href="https://discord.gg/FMcvc6T" rel="noopener noreferrer"&gt;Unicorn Utterances&lt;/a&gt; discord server, who helped me solve the issues and get the library working.&lt;/p&gt;

&lt;p&gt;Cover image is from &lt;a href="https://unsplash.com/photos/FkjaN-7gWC0" rel="noopener noreferrer"&gt;unsplash.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>npm</category>
    </item>
    <item>
      <title>Direct download any Xcode</title>
      <dc:creator>Jahir Fiquitiva</dc:creator>
      <pubDate>Mon, 29 Oct 2018 00:45:09 +0000</pubDate>
      <link>https://dev.to/jahirfiquitiva/direct-download-any-xcode-385o</link>
      <guid>https://dev.to/jahirfiquitiva/direct-download-any-xcode-385o</guid>
      <description>&lt;p&gt;Downloading Xcode from the App Store, or even the &lt;strong&gt;.xip&lt;/strong&gt; file while using a browser, regardless of which one it is, can be a pain when your connection is not as stable and fast as others' and when the download can be interrupted at any time and you're most likely going to have to restart the whole download.&lt;/p&gt;

&lt;p&gt;This just happened to me and I'm writing this as a note-to-self but also to share this with others who might be facing a similar situation.&lt;/p&gt;

&lt;p&gt;Here's what I did to download it…&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Install Xcode Command Line Tools
&lt;/h3&gt;

&lt;p&gt;It is a small package of ~183Mb which I think it's enough to be downloaded via your browser.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to &lt;a href="https://developer.apple.com/download/more/" rel="noopener noreferrer"&gt;Developer Downloads site&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Sign in with your Apple ID if you need to&lt;/li&gt;
&lt;li&gt;Search for the command line package you want to download (I'm going to use the latest stable Command Line tools for Xcode 10 and macOS Mojave).
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffqyf29djjh3dy7v7svv5.png" alt="Command Line Tools download option" width="741" height="152"&gt;
&lt;/li&gt;
&lt;li&gt;Press the link on the right side and wait for download to complete&lt;/li&gt;
&lt;li&gt;Once downloaded, install it as any other .dmg package.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Install &lt;a href="https://brew.sh/" rel="noopener noreferrer"&gt;Homebrew&lt;/a&gt; and wget
&lt;/h3&gt;

&lt;p&gt;I used &lt;a href="https://brew.sh/" rel="noopener noreferrer"&gt;Homebrew&lt;/a&gt; to install &lt;strong&gt;&lt;em&gt;wget&lt;/em&gt;&lt;/strong&gt;. There might be another way, but this is how I did it. 😅&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open Terminal&lt;/li&gt;
&lt;li&gt;Run
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Follow the prompted steps&lt;/li&gt;
&lt;li&gt;Once done, run
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install wget
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Install and get cookies.txt from your browser
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://chrome.google.com/webstore/detail/cookiestxt/njabckikapfpffapmjgojcnbfjonfjfg" rel="noopener noreferrer"&gt;Download for Google Chrome&lt;/a&gt; (Don't have a link for other browsers, sorry)&lt;/li&gt;
&lt;li&gt;Visit the &lt;a href="https://developer.apple.com/download/more/" rel="noopener noreferrer"&gt;Developer Downloads site&lt;/a&gt; again.&lt;/li&gt;
&lt;li&gt;Click the cookies.txt icon&lt;/li&gt;
&lt;li&gt;In the top part you will see a link that says &lt;strong&gt;&lt;em&gt;'click here'&lt;/em&gt;&lt;/strong&gt;. Click it to download the &lt;strong&gt;&lt;em&gt;cookies.txt&lt;/em&gt;&lt;/strong&gt; file&lt;/li&gt;
&lt;li&gt;Save it wherever you want&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Get Xcode direct download link
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Visit the &lt;a href="https://developer.apple.com/download/more/" rel="noopener noreferrer"&gt;Developer Downloads site&lt;/a&gt; once more.&lt;/li&gt;
&lt;li&gt;Select the Xcode version you want to download (I'm going to download Xcode 10).
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwljrtbjso1g9sn904edr.png" alt="Xcode 10 download option" width="746" height="138"&gt;
&lt;/li&gt;
&lt;li&gt;Right-click the link on the right side an select "Copy link address"&lt;/li&gt;
&lt;li&gt;Alternatively, visit this &lt;a href="https://stackoverflow.com/a/10335943" rel="noopener noreferrer"&gt;StackOverflow answer&lt;/a&gt; for links to all Xcode versions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Start download
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Open Terminal and go to the location of your &lt;strong&gt;&lt;em&gt;cookies.txt&lt;/em&gt;&lt;/strong&gt; file.&lt;/li&gt;
&lt;li&gt;Now run
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wget --load-cookies=cookies.txt -c https://download.developer.apple.com/Developer_Tools/Xcode_10/Xcode_10.xip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Replace the link at the end with the one you want for the file you want to download which you got in last step.&lt;/li&gt;
&lt;li&gt;Wait for the download to finish.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Notes:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add &lt;strong&gt;&lt;em&gt;-b&lt;/em&gt;&lt;/strong&gt; to the download command to run it in the background, although it is easier to check progress and state without it.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;&lt;em&gt;-c&lt;/em&gt;&lt;/strong&gt; option in the command allows you to &lt;strong&gt;c&lt;/strong&gt;ontinue with the download even if you close your terminal, or cancel the process, or restart your laptop, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6. Install Xcode
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Open the downloaded file so it starts uncompressing.&lt;/li&gt;
&lt;li&gt;Move the uncompressed file to the &lt;strong&gt;&lt;em&gt;Applications folder&lt;/em&gt;&lt;/strong&gt; and you're done!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hope you find this useful and please don't forget to share it with others!&lt;br&gt;
Get to know more about me @ &lt;a href="https://jahir.xyz" rel="noopener noreferrer"&gt;jahir.xyz&lt;/a&gt;&lt;br&gt;
Image credits: &lt;a href="https://unsplash.com/photos/xNKy-Cu20d4" rel="noopener noreferrer"&gt;unsplash.com&lt;/a&gt;&lt;br&gt;
Originally published on &lt;a href="https://medium.com/@jahirfiquitiva/direct-download-any-xcode-57f9cb969bf2" rel="noopener noreferrer"&gt;medium.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mac</category>
      <category>macos</category>
      <category>xcode</category>
      <category>ios</category>
    </item>
  </channel>
</rss>
