Build a Dynamic Portfolio With the Github API
Tags: python, webdev, github, portfolio
Published: 2021-04-22 21:13:37

_This article was originally posted on [Medium](https://medium.com/swlh/build-a-dynamic-portfolio-with-the-github-api-6d74081e5164). If you prefer reading it from there, please do check it out._

## Introduction

With the advent of countless templates and web page design applications, the task of creating a personal portfolio transitioned from a painful endeavor into a painless task. 

However, the act of constantly updating the hard-coded information and rebuilding and redeploying your portfolio turns into a tiresome burden.

In this tutorial, I will show you how I integrated the Github API into my portfolio to pull the most recent project information, solving the issue of directly updating and redeploying my portfolio.

## Agenda

* Setup

* Service

* Integrate

## Setup

Before we build the solution, let’s first understand the core idea and configure Github to ease the integration.

First, let’s talk about the Github repositories. To elaborate, I house my projects in the repositories themselves: I host the source code, keep detailed descriptions, and maintain links to demo gifs or images.

![Link to the repository [https://github.com/Ramko9999/Pathfinding-Visualizer](https://github.com/Ramko9999/Pathfinding-Visualizer)](https://cdn-images-1.medium.com/max/3536/1*qb3hbCXT2CI6gHVMqyjOSw.png)

This repository houses my Path Finding Visualizer project. 

In the right side, the section outlined in blue contains the description of the project. On the other hand, the section outlined in red has a link to the demo. Finally, the section outlined in black contains topics associated with the project. 

To sum it all up, the Github [API] (https://docs.github.com/en/rest) will return the above fields upon an HTTP request to:

    GET /users/{username}/repos

This [endpoint](https://docs.github.com/en/rest/reference/repos#list-repositories-for-a-user) will return a list of public repositories for a user. 

Here is what the return json object looks likes for the Path Finding Visualizer repository.

![](https://cdn-images-1.medium.com/max/2376/1*Y-rqrLmYUNFXvzhtZaCksA.png)

Although it is a bit difficult to see, the API returned the fields we need: description, homepage, and topics. 

This is fantastic news, since it shows that we can store and retrieve information from our repositories.

Let’s now work on configuring Github to simplify the integration.

All we need to do is generate a personal access token in the developer settings. We will use the personal access token to authenticate our requests to the Github API so we can take advantage of the generous rate limits.

First, navigate to your profile settings.

![](https://cdn-images-1.medium.com/max/2000/1*OVJwlVGOfwlSQl9lN2sR4A.png)

From your profile settings, navigate to the developer settings.

![](https://cdn-images-1.medium.com/max/2000/1*l4B3diZ1wSWr59daXuhAIg.png)

Finally, go to the personal access tokens tab.

![](https://cdn-images-1.medium.com/max/2000/1*TxbSj2cOh5seKuOcRq1nsQ.png)

At this point, you can click “Generate new token” and Github will walk you through the rest. Once you have generated the token, make sure you save it to the clipboard, since we will need it for later.

Now that we have generated our personal access token, we can work on the actual integration.

## Service

To start, let’s conceptualize how the portfolio would interact with the Github API.

Building a separate service that communicates between the portfolio and the Github API is a good idea, since we should house our Github personal access token in a secure environment. 

Here is a depiction of the network flow:

![](https://cdn-images-1.medium.com/max/2000/1*46SCXZw_jnBqiDBZq_LbRQ.png)

Let’s start building out the service. 

I will be using Python and [Flask](https://flask.palletsprojects.com/en/1.1.x/), but just understand that you can use any stack of your choice. 

First, let’s create a `config.py` file. In this file, we will store our Github username and our personal access token. Make sure you do not push this file to version control.

```python
    USERNAME = "YOUR GITHUB USERNAME"
    TOKEN = "YOUR PERSONAL ACCESS TOKEN FROM EARLIER"
```

Let’s create a `server.py` file and make a simple Flask app.

```python
    from flask import *
    from flask_cors import CORS
    from config import *

    app = Flask(__name__)
    CORS(app)

    if __name__ == "__main__":    
       app.run()
```

Now, let’s expose an endpoint that our portfolio can call to get the project data.

```python
    @app.route("/projects", methods=["GET"])
    def getProjects():
       pass
```

The `getProjects()` method will do three things.

* It will make a request to the Github API for the repository data.

* It will extract the relevant fields from each of the repositories.

* It will return the filtered data back to the portfolio.

Let’s tackle these steps one by one.

**Making a request to Github**

We can simply use the Python requests library to make the HTTP request.

```python
    url = "https://api.github.com/users/USERNAME/repos"        
    headers = {"Accept":"application/vnd.github.mercy-preview+json"}        

    repos = requests.get(url, headers=headers, auth=(USERNAME,TOKEN)).json()
```

The Github API will also include the `topics` field for each of the repositories if we pass in the above headers. 

If all goes correctly, the request should have a status of 200 and the `repos` variable should be a list of json objects.

**Extracting relevant fields**

The main fields of concern are `id`, `name`, `html_url`, `description`, `topics`, and `homepage`. The `homepage` field represents the text stored in the black outlined area:

![](https://cdn-images-1.medium.com/max/2438/1*WZNac2V96NI4CLprgWPUKA.png)

We can put links to our demo gifs in `homepage`. 

The code to parse each of the repositories is this:

```python
    projects = []
    for repo in repos:
        if repo["homepage"]:
            project = {
                "id": repo["id"],
                "name": repo["name"],
                "url": repo["html_url"],
                "description": repo["description"],
                "topics":repo["topics"],
                "images": repo["homepage"].split(";")
            }
            projects.append(project)
```

_Just to clarify, I added more than one demo link for certain projects. I separated each link with a semi-colon._

Here is what `project` would look like for the Path Finding Visualizer repository:

```python
    {
      "id": 206887035,
      "name": "Pathfinding-Visualizer",
      "url": "https://github.com/Ramko9999/Pathfinding-Visualizer",
      "description": "Built a colorful visualizer for shortest path algorithms: A star search, Breadth First Search, and Bidirectional Breadth First Search. Utilized Queues and Priority Queues to reduce collection operations such as pop() and push() to O(1) and O(log(n)) run times.",
      "topics": [
        "data-structures",
        "graph-algorithms",
        "java",
        "pathfinding",
        "swing"],
      "images": [
        "https://media.giphy.com/media/U6GuVGBOQoHUHaZ7LV/giphy.gif",
        "https://media.giphy.com/media/gg9eCb2ZBqcU4LlSML/giphy.gif",
        "https://media.giphy.com/media/l4Wyj6PQwwxZdPjfSe/giphy.gif",
        "https://media.giphy.com/media/LRgBCMGhCvqkzHzeaY/giphy.gif"]},
```
All that remains now is to return `projects` back to the initiator of the request.

**Returning a response**

We can return the filtered data back to the client with the following:

```python3
    return {"projects": projects, "error": False}

```

So with all the pieces put together, the `getProjects()` method will look as such:

{% gist
https://gist.github.com/Ramko9999/8b038dbd082caa77516217bc97e810a7

%}

Please be sure to test your service locally by calling the `/projects` endpoint. Once it is working, you can deploy it wherever you like. Personally, I deployed the service on [pythonanywhere.com](https://www.pythonanywhere.com).

 <iframe src="https://medium.com/media/52f9a931b2f4b2af09ef7f960347510f" frameborder=0></iframe>

Pat yourself on the back, as the hardest part is now over!

## Integrate

All that remains now is that we have to make an HTTP request from our portfolio website to the service we have just created. 

For example, I used React to build out my portfolio, so here is how I made the call and fetched the projects.

{% gist
https://gist.github.com/Ramko9999/4d64f6b3c0de36c9e1bdeaeacb6e625f

%}

All you need to do now is to build out the user interface based on the data.

With that said, feel free to head over to my [portfolio](https://ramki-pitch.web.app/) to check out how I implemented my user interface.

**That's it folks!**