惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

N
Netflix TechBlog - Medium
Blog — PlanetScale
Blog — PlanetScale
月光博客
月光博客
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
爱范儿
爱范儿
量子位
博客园 - 聂微东
Engineering at Meta
Engineering at Meta
WordPress大学
WordPress大学
GbyAI
GbyAI
MyScale Blog
MyScale Blog
IT之家
IT之家
P
Proofpoint News Feed
M
MIT News - Artificial intelligence
The Cloudflare Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Hugging Face - Blog
Hugging Face - Blog
The Register - Security
The Register - Security
Microsoft Security Blog
Microsoft Security Blog
博客园_首页
MongoDB | Blog
MongoDB | Blog
F
Fortinet All Blogs
博客园 - 三生石上(FineUI控件)
Y
Y Combinator Blog
雷峰网
雷峰网
V
Visual Studio Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
Last Week in AI
Last Week in AI
博客园 - 叶小钗
D
DataBreaches.Net
B
Blog
B
Blog RSS Feed
大猫的无限游戏
大猫的无限游戏
aimingoo的专栏
aimingoo的专栏
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
The GitHub Blog
The GitHub Blog
云风的 BLOG
云风的 BLOG
Recent Announcements
Recent Announcements
阮一峰的网络日志
阮一峰的网络日志
小众软件
小众软件
腾讯CDC
T
Threat Research - Cisco Blogs
SecWiki News
SecWiki News
Martin Fowler
Martin Fowler
D
Docker
Cisco Talos Blog
Cisco Talos Blog
T
Tenable Blog
Webroot Blog
Webroot Blog
宝玉的分享
宝玉的分享

kefan.me

Two Classes 在冰岛抵抗白昼 用Rust重构了后端 写前端如逆水行舟 鱼王 Coding in Wenyan 去开会成为一个人新生活的标志 Install Clang-Format Without Root Privileges Build a Web App - Part 2/2 Build a Web App - Part 1/2 我说我不来你非要让我来 痛苦还是无聊 从零搭建博客 写前端不是请客吃饭 一些片段 Running Valgrind on macOS Catalina 适合私人沉迷 Odd Ways to Find Odd Numbers 关于李志 Miller-Rabin素性测试和大素数生成 你好,博客 再见
Fetching Github Stats using GraphQL
2019-12-19 · via kefan.me

While I was making my personal website dongkefan.me, I wanted to added a section that would display my pinned projects on Github. At first I thought about hardcode all the content in an array and simply render it out, but in that way, I would have to update my code once I made any new project. I wanted to make sure whenever I added/removed my personal profile, my website get updated automatically. Due to this requirement, the data I render had to be actively fetched from Github, rather than locally stored in the repository.

To reach this goal, I had two options: REST and GraphQL. Both API achieves the same target: I send a request to the Github server asking information, and I would be returned with what I need. After some research work, I decided to use the latter option. Not because one is superior to the other - in the end, I’m only using it for retrieving a tiny amount of data once per load, any efficiency difference is negligible - but because it is simpler to use and easier to set up. In this blog I would share my experiences and code that accomplish my needs.

The first thing I need is a personal access token. It is linked to each account that grants the user the access to the server. You can create one from Settings - Developer settings - Personal access tokens - Generate new token. For safety purpose, make sure this token only contains the access for reading repos but not writing.

Then I’ll need to use this token in my react project. There are many node packages that contains GraphQL, including the official Javascript implementation made by Facebook themselves, but it is not so user-friendly and requires I didn’t need all the functionalities. Since I’m only using it for Github, I chose @octokit/graphql as my package. It is made my Github and has all the API I want. To install it on your project, simple do npm I @octokit/graphql —save (or yarn add @octokit/graphql if you’re using yarn)

On the React side, we then need to write out the schema. For REST, the response would contain all the available information, and I will choose what to use locally, but for GraphQL, I can specify what to fetch in the forms of a query. Thanks to Github, there’s a live modal that visualizes the data flow, where we can write our code and test it on production data. It even gives us an explorer that has all the available data types. I just needed to check what I wanted and the query forms itself. In this case, I wanted the name, description, url, and the language of the first six pinned repositories on my account. The result looks like this:

After knowing this query works, I then saved in locally in React.

const PinnedProjects = `
{
  viewer {
    pinnedItems(first: 6, types: REPOSITORY) {
      nodes {
        … on Repository {
          id
          name
          languages(orderBy: {field: SIZE, direction: DESC}, first: 1) {
            nodes {
              name
              color
            }
          }
          description
          url
        }
      }
    }
  }
}
`

At this point, there’s only one thing left to do and that’s to use the GitHub token perviously created and authorize the call. The official documentation written by Github tells me to do this:

const githubGraphRequest = graphql.defaults({
  headers: {
    authorization: `Bearer ${process.env.REACT_APP_GITHUB_GQL_TOKEN}`,
  },
})

In this code snippet, I stored my token as an environment variable in order for it to remain hidden in my Repo.

After all the setup work is finished, I just need to use these two pieces and forms my call. Notice that it takes time for the data to be returned, so I used react hooks and async calls with a loading indicator to make sure the data will only be rendered once the fetching is complete. The full code looks like this:

import React, { useEffect, useState } from "react"
import { graphql } from "@octokit/graphql"

const githubGraphRequest = graphql.defaults({
  headers: {
    authorization: `Bearer ${process.env.REACT_APP_GITHUB_GQL_TOKEN}`
  }
})

export const getPinnedProjects = async () =>
  await githubGraphRequest(PinnedProjects)

const PinnedProjects = `
{
  viewer {
    pinnedItems(first: 6, types: REPOSITORY) {
      nodes {
        ... on Repository {
          id
          name
          languages(orderBy: {field: SIZE, direction: DESC}, first: 1) {
            nodes {
              name
              color
            }
          }
          description
          url
        }
      }
    }
  }
}
`

const Github = () => {
  const [loading, setLoading] = useState(true)
  const [pinned, setPinned] = useState([])

  useEffect(() => {
    setLoading(true)
    Promise.all([getPinnedProjects()])
      .then(([p]) => {
        setPinned(p.viewer.pinnedItems.nodes)
      })
      .finally(() => setLoading(false))
  }, [])

  return (
    !loading && (
      <>
        {console.log(pinned)}
        {/* your code here */}
      </>
    )
}

export default Github

The logged data looks like this:

Eventually I was able to implement the feature on my website hehe

Compared to my Github profile:

I’m not a good writer, so I apologize in advance if any explaination is unclear. Thanks for reading!

:)