<?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: f-llewellyn</title>
    <description>The latest articles on DEV Community by f-llewellyn (@fllewellyn).</description>
    <link>https://dev.to/fllewellyn</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%2F856493%2F3491d4b8-a97a-4170-8ae3-e1dfc5fce92c.jpeg</url>
      <title>DEV Community: f-llewellyn</title>
      <link>https://dev.to/fllewellyn</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fllewellyn"/>
    <language>en</language>
    <item>
      <title>How to use the GitHub rest API with SvelteKit</title>
      <dc:creator>f-llewellyn</dc:creator>
      <pubDate>Mon, 02 May 2022 15:12:01 +0000</pubDate>
      <link>https://dev.to/fllewellyn/how-to-use-the-github-rest-api-with-sveltekit-3pbn</link>
      <guid>https://dev.to/fllewellyn/how-to-use-the-github-rest-api-with-sveltekit-3pbn</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As a self taught developer wanting to find himself a job in the near future, I was thinking about projects to develop to add to my portfolio. I soon decided upon a markdown editor with a live preview and predefined markdown components, that could be used to write READMEs for GitHub repos (the project can be found &lt;a href="https://read-me-murex.vercel.app/" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Wanting to continue my practice with SvelteKit, I decided that would be my framework of choice for this project.&lt;/p&gt;

&lt;p&gt;After developing a minimum viable product, I thought that pulling existing READMEs from a users GitHub repos would be an awesome feature. As I'm sure many of you know, GitHub is owned by Microsoft. This is apparent when you go to take one look at the documentation for the GitHub rest API, as in true Microsoft fashion, it's pretty poor. This coupled with my use of SvelteKit (which is still in beta) meant that implementing the GitHub rest API was going to be a lot harder than I first thought.&lt;/p&gt;

&lt;p&gt;After a lot of research, trial and error I was able to find a YouTube video that focused on what I wanted to do. The only issue was that the video was created with an older version of SvelteKit.&lt;br&gt;
The original video can be found here:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/D4ZcbudB1n0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;After refactoring for the most recent version of SvelteKit, I decided that I would share what I have learnt, in case anyone in the future faces the same difficulties as me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;To get started, you need to create a local SvelteKit project as you would normally with the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm init svelte my-app
cd my-app
npm install
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, it's time to set up things on the GitHub side...&lt;/p&gt;

&lt;h2&gt;
  
  
  Set up the OAuth app in GitHub
&lt;/h2&gt;

&lt;p&gt;To set up an OAuth app with GitHub, go to &lt;strong&gt;Your Profile &amp;gt; Settings &amp;gt; Developer Settings &amp;gt; OAuth Apps &amp;gt; New OAuth App&lt;/strong&gt; or alternatively, go to this &lt;a href="https://github.com/settings/applications/new" rel="noopener noreferrer"&gt;link&lt;/a&gt; if you're already logged into GitHub.&lt;/p&gt;

&lt;p&gt;Enter the following into the OAuth setup screen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Application Name:&lt;/strong&gt; Whatever you would like&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Homepage URL:&lt;/strong&gt; Set to &lt;code&gt;http://localhost:3000&lt;/code&gt; for now, as this is the default port that SvelteKit runs on out of the box. If you have configured the port from the default, enter that port instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application Description:&lt;/strong&gt; Again, whatever you would like&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authorization callback URL:&lt;/strong&gt; The same as the Homepage URL, with &lt;code&gt;/callback&lt;/code&gt; at the end. In this example, &lt;code&gt;http://localhost:3000/callback&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;NOTE: UNLESS CONFIGURED OTHERWISE, ENSURE &lt;code&gt;http&lt;/code&gt; AND NOT &lt;code&gt;https&lt;/code&gt; IS USED&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Environment Variables
&lt;/h2&gt;

&lt;p&gt;Next on the list is to configure the Client ID and Client Secret within your application. To do this, create a file called &lt;code&gt;.env&lt;/code&gt; in the project root.&lt;/p&gt;

&lt;p&gt;In this file, write two variables; &lt;code&gt;VITE_CLIENT_ID&lt;/code&gt; and &lt;code&gt;VITE_CLIENT_SECRET&lt;/code&gt;, and then copy these values from the OAuth app settings. You may need to generate a new client secret.&lt;br&gt;
&lt;a href="https://media.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%2Fd93lyhirdgnwqqt39xts.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fd93lyhirdgnwqqt39xts.png" alt="The client id and secret options in github"&gt;&lt;/a&gt;&lt;br&gt;
Your &lt;code&gt;.env&lt;/code&gt; file should look something like this, but with your apps' details:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VITE_CLIENT_ID=****cc378
VITE_CLIENT_SECRET=****984b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reason we use the &lt;code&gt;VITE&lt;/code&gt; prefix is because SvelteKit uses a tool aclled vite under the hood. The &lt;code&gt;VITE&lt;/code&gt; prefix indicates to vite that the variable should be broadcast to the rest of the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the routes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Homepage link
&lt;/h3&gt;

&lt;p&gt;Within your index.svelte file, create an a tag that links to "/login" like so:&lt;br&gt;
&lt;code&gt;&amp;lt;a href="/login"&amp;gt;Login&amp;lt;/a&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Login logic
&lt;/h3&gt;

&lt;p&gt;Then, create a file called &lt;code&gt;login.js&lt;/code&gt; in the &lt;code&gt;routes&lt;/code&gt; directory and copy the below code in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Address to make a request to
const target = "https://github.com/login/oauth/authorize";
// Import from environment variables
const clientId = import.meta.env.VITE_CLIENT_ID;

// Send a request to the target URL with some parameters
export async function get(request) {
    const sessionId = "1234";
    return {
        // 302 is a redirect status code
        status: 302,
        headers: {
            location: `${target}?client_id=${clientId}&amp;amp;state=${sessionId}`,
        },
    };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This logic makes a GET request to the authorization URL for GitHub, which in turn redirects us to out callback URL (which we entered as &lt;code&gt;http://localhost:3000/callback&lt;/code&gt;) and gives us a code as a query parameter.&lt;/p&gt;

&lt;h3&gt;
  
  
  Callback
&lt;/h3&gt;

&lt;p&gt;Next, create a file called &lt;code&gt;callback.js&lt;/code&gt; within the same &lt;code&gt;routes&lt;/code&gt; directory. We want to set the URL to retrieve an access token, the URL to retrieve the User data and import the client id and secret from our &lt;code&gt;.env&lt;/code&gt; file. Your &lt;code&gt;callback.js&lt;/code&gt; should look like this so far:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const tokenURL = "https://github.com/login/oauth/access_token";
const userURL = "https://api.github.com/user";
const clientId = import.meta.env.VITE_CLIENT_ID;
const secret = import.meta.env.VITE_CLIENT_SECRET;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we need to create a function that retrieves the access token and returns it through a POST request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async function getToken(code) {
    const res = await fetch(tokenURL, {
        method: "POST",
        headers: {
            "Content-Type": "application/json",
            Accept: "application/json",
        },
        body: JSON.stringify({
            client_id: clientId,
            client_secret: secret,
            code,
        }),
    });
    const data = await res.json();
    return data.access_token;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, using this token, we can access the user's data using a GET request to the GitHub API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async function getUser(token) {
    const res = await fetch(userURL, {
        headers: {
            Accept: "application/json",
            Authorization: `Bearer ${token}`,
        },
    });
    const data = await res.json();
    return data;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function returns the user data so that it is accessible to the application.&lt;/p&gt;

&lt;p&gt;Finally, we want to pass the username from the data (called login in the response) into SvelteKit's local storage to allow it to be processed by middleware, and redirect us back to index.svelte.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export async function get(event) {
    const code = event.url.searchParams.get("code");
    // Get access token
    const token = await getToken(code);

    // Get user
    const user = await getUser(token);
    event.locals.user = user.login;

    return {
        status: 302,
        headers: {
            location: "/",
        },
    };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Middlware
&lt;/h3&gt;

&lt;p&gt;Before we go back to the homepage, we need to implement the middleware. SvelteKit does this in a file called &lt;code&gt;hooks.js&lt;/code&gt; in the &lt;code&gt;src&lt;/code&gt; directory. Create this file, and then install a package called cookie:&lt;br&gt;
&lt;code&gt;npm install cookie&lt;/code&gt;&lt;br&gt;
We then want to import this into &lt;code&gt;hooks.js&lt;/code&gt; as so:&lt;br&gt;
&lt;code&gt;import cookie from "cookie"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We then want to use the &lt;code&gt;handle()&lt;/code&gt; function included in SvelteKit. to parse cookies into every path within the application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export async function handle({ event, resolve }) {
    // Empty string in case of user not being logged in
    const cookies = cookie.parse(event.request.headers.get("cookie") || "");
    // Store the value from cookies in the local storage
    event.locals.user = cookies.user;
    const response = await resolve(event);

    // Set a cookie of the username stored in sveltekit local storage that is accessable from any directory and is only editble by http
    response.headers.set(
        "set-cookie",
        `user=${event.locals.user || ""}; path=/; HttpOnly`
    );
    return response;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we need to make this value publicly available within the application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export async function getSession(event) {
    return {
        user: event.locals.user,
    };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're now ready to use this variable in the homepage.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using the data in the homepage
&lt;/h3&gt;

&lt;p&gt;To access the data from the frontend, we need to run some code in the backend. In SvelteKit, we can do this using the module context for a script element.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;index.svelte&lt;/code&gt;, we want to add the following code to the top of the file to run the &lt;code&gt;load()&lt;/code&gt; function from SvelteKit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script context="module"&amp;gt;
    export async function load({ session }) {
        return {
            props: {
                user: session.user,
            },
        };
    }
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To access this variable, we need to pass it into the homepage as a prop with &lt;code&gt;export let user&lt;/code&gt; in a regular &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag.&lt;br&gt;
The further down, if we try to use this in the markup like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{#if user}
        &amp;lt;h1&amp;gt;Hello {user}&amp;lt;/h1&amp;gt;
    &amp;lt;a href="/logout"&amp;gt;Logout&amp;lt;/a&amp;gt;
{:else}
    &amp;lt;a href="/login"&amp;gt;Login&amp;lt;/a&amp;gt;
{/if}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We should see the follwing displayed after logging in:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F6xca9o9cmcuniza24uit.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F6xca9o9cmcuniza24uit.png" alt="Username being passed into homepage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Persistence
&lt;/h3&gt;

&lt;p&gt;Due to the cookies being given no timeout value, the user will stay logged in until they decide to logout.&lt;/p&gt;

&lt;h3&gt;
  
  
  Logging out
&lt;/h3&gt;

&lt;p&gt;We also need to provide the user with a way to logout of the app. We can do this with some simple logic.&lt;/p&gt;

&lt;p&gt;Create a file called &lt;code&gt;logout.js&lt;/code&gt; in the &lt;code&gt;routes&lt;/code&gt; directory and enter the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export async function get(event) {
    event.locals.user = null;

    return {
        status: 302,
        headers: {
            location: "/",
        },
    };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All this does is remove the user from SvelteKit's local storage and redirect to the homepage.&lt;/p&gt;

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

&lt;p&gt;I hope people find this useful in the future and put this code to good use. My readme project can be found &lt;a href="https://read-me-murex.vercel.app/" rel="noopener noreferrer"&gt;here&lt;/a&gt; and the GitHub repo &lt;a href="https://github.com/f-llewellyn/read.me" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can checkout my &lt;a href="https://github.com/f-llewellyn" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; and contact me if you have any questions.&lt;/p&gt;

&lt;p&gt;Also, feel free to give me a job if you'd like, I won't complain.&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>github</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
