Make a Custom Portfolio Site Generator with StepZen's Developer Publishing Pack
Tags: graphql, netlify, showdev, tutorial
Published: 2021-11-09 13:33:44

_This post was originally published on [StepZen.com](https://stepzen.com/blog/make-a-custom-portfolio-site-generator-with-stepzens-developer-publishing-pack)_

## Introduction

We all know it's a pain to keep static portfolio sites updated -- copy/pasting content, managing layout, rebuilding and redeploying, etc.

![tweet bemoaning the state of a portfolio site](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6akdv44qtxkgdkglpjlc.png)

What if your developer portfolio website updated automatically along with your content? Beyond that, what if you could generate your portfolio site with no code involved?

## Using a pre-built GraphQL API

Let me show you how I made [this dynamic, no-code portfolio solution](https://unruffled-jepsen-48941e.netlify.app/) using a GraphQL API I assembled in the [StepZen GraphQL Studio](https://graphql.stepzen.com)!

![screenshot of the StepZen GraphQL Studio](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j9u23krvn7ydl6bv8vvg.png)

The StepZen GraphQL Studio lets you explore single or combination GraphQL schemas and their queries for popular APIs - no StepZen account needed.

(However, I do recommend [signing up](https://stepzen.com/signup) for a StepZen account -- it makes key management a breeze in the long run.)

For my project I chose a combination - the Developer Publishing Pack - which includes the three APIs I need to power my portfolio site: Dev-to, GitHub, and Twitter.

## Looking at the overall project map

First off, let's zoom out and take a look at the overall design of my portfolio site.

![excalidraw graph](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/71djlkbde5gf8qzewgbi.png)

> Note: The original static structure of the project and the logic surrounding env variables comes [from a blog post by Cassidy Williams](https://css-tricks.com/hack-the-deploy-to-netlify-button-using-environment-variables-to-make-a-customizable-site-generator/).

There's a template repository, which is deployed to a new instance via the [Netlify click to deploy button](https://docs.netlify.com/site-deploys/create-deploys/#deploy-to-netlify-button). As you can see, the final values in the site are determined by entries in a form in the generator, and these values remain static.

So we've got the generator with this version of the design, but every time that you have a new portfolio project featured on GitHub, you'd have to either a) edit your custom site instance or b) generate a whole new version of the site.

## Making the site dynamic

How do we make the deployed site dynamic, so that you don't have to worry about editing the site when you make a new project?

This is where the endpoint from StepZen's GraphQL Studio comes in!

![dynamic graph](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xno2472qojkw4u1n7yp6.png)

I made the template here using NextJS, because Netlify has a [NextJS plugin](https://github.com/netlify/netlify-plugin-nextjs), which automates the process of using serverless functions. I inserted the call to my StepZen GraphQL endpoint in the [`pages/api`](https://nextjs.org/docs/api-routes/introduction) folder to keep sensitive info off the client.

I created the generator site in AlpineJS, as the only capabilities in the generator that I needed were capturing values from the client and dynamically inserting them in the **Deploy to Netlify** button.

Here's the key bit of information: Because each custom site instance now includes a call to my StepZen endpoint, the information returned can be dynamic. Specifically, my endpoint connects the GitHub, Twitter, and DEV.to APIs in a Developer Publishing Pack and returns the top posts from DEV.to as well as the current pinned tweet and GitHub repositories.

This means that to keep your site updated with content, all you have to do is change your pins on Twitter or GitHub, and sit and watch your top stats change on DEV.to!

## Generating the GraphQL endpoint

I started by selecting the Developer Publishing Pack combination in the StepZen GraphQL Studio.

![close up screenshot of studio](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s0ov959nf8bwa8fv32v2.png)

Next, I played around with the APIs and queries using mock data until I found a query that returned top DEV.to posts along with Twitter and GitHub pins.

![query in graphiql](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2y3yr34g6tfeldz5myc7.png)

Here's that query.

```
query MyQuery ($github_token: Secret! $twitter_bearerToken: Secret!, $username: String! ) {
        devto_getArticles(username: $username, top: 3) {
          title
          published_at
          user {
            github_details(github_token: $github_token) {
              pinnedItems(first: 3) {
                nodes {
                  ... on Github_Repository {
                    id
                    name
                    description

                  }
                }
              }
            }

            twitter_details(
              twitter_bearerToken: $twitter_bearerToken
            ) {
              pinned_tweet(
                twitter_bearerToken: $twitter_bearerToken
              ) {
                text
              }
            }
            github_username
            username
            twitter_username
          }
        }
      }
```

The GraphQL Studio allows us to access the endpoint we've assembled and use it in my application.

Here, I clicked **Publish** in the GraphQL Studio to reveal the endpoint I had assembled and copied it:

![screenshot of publishing button](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zlv97kql8fqa9kuq1kq1.png)

## Consuming the GraphQL endpoint

After creating the GraphQL endpoint in the Studio you can send a request to it from a frontend application. Alternatively, you could also download your schema and [sign up](https://stepzen.com/signup) for a StepZen account, to make key management easier.

From a new file in the `pages/api` directory in a Next.js project you can add a simple `fetch` request to interact with the GraphQL endpoint:

```
const response = await fetch(
    "https://graphql1f.steprz.net/api/1fec739d90f6028c74a6f19855c34277/__graphql",

    {
      method: "POST",

      headers: {
        "Content-Type": "application/json",
      },

      body: INSERT_QUERY_BODY_HERE
      `,
        variables: {
          github_token: github_token,
          twitter_bearerToken: twitter_bearerToken,
          username: username,
        },
      }),
    }
  );
```

The values for the variables object in the fetch requested are retrieved from the environment variables. These variables are set when you enter the values in the [generator](https://zealous-albattani-13f59a.netlify.app/).

![generator screenshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4f4sb9p6kmib9fjhxkl8.png)

These variables then give you access to the GitHub and Twitter APIs (the information retrieved from the DEV.to API does not require a key to access).

Hit 'Deploy to Netlify', follow Netlify's instructions, and there you go!

![screenshot of template site](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ke0uoz2hxhxk3jmyzpht.png)

## Conclusion

We covered the overall design of our custom dynamic portfolio site solution, as well as how I created the endpoint that gave the site its dynamic quality by calling an endpoint I created in the StepZen GraphQL Studio.

We also took a look at how I consumed that endpoint on the frontend.

There are a lot of pre-built API combinations available in the GraphQL Studio, including:

- Google Maps + Yelp Reviews
- Outdoor Dining Search
- Social Media Sentiment Analysis

Or you could make your own!

I'm curious to hear about your ideas for a dynamic site generator. Would you create a generator that makes dynamically updated image collages based on the user's input? Or perhaps a generator that creates a review widget for a chain of restaurants, depending on which chain you use in the environment variables? We'd love to hear your ideas! Jump into our [Discord channel](https://discord.com/invite/9k2VdPn2FR) anytime.