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

推荐订阅源

G
Google Developers Blog
Jina AI
Jina AI
大猫的无限游戏
大猫的无限游戏
Martin Fowler
Martin Fowler
博客园 - 司徒正美
云风的 BLOG
云风的 BLOG
C
Cybersecurity and Infrastructure Security Agency CISA
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
S
Securelist
S
Security Affairs
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
L
LINUX DO - 热门话题
博客园 - 三生石上(FineUI控件)
T
Threatpost
T
The Blog of Author Tim Ferriss
C
CERT Recently Published Vulnerability Notes
IT之家
IT之家
P
Palo Alto Networks Blog
Microsoft Azure Blog
Microsoft Azure Blog
Spread Privacy
Spread Privacy
Cyberwarzone
Cyberwarzone
腾讯CDC
L
LangChain Blog
Know Your Adversary
Know Your Adversary
C
CXSECURITY Database RSS Feed - CXSecurity.com
GbyAI
GbyAI
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
I
Intezer
T
Tor Project blog
AWS News Blog
AWS News Blog
T
Tenable Blog
NISL@THU
NISL@THU
Security Latest
Security Latest
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
H
Hackread – Cybersecurity News, Data Breaches, AI and More
人人都是产品经理
人人都是产品经理
MongoDB | Blog
MongoDB | Blog
MyScale Blog
MyScale Blog
D
DataBreaches.Net
Microsoft Security Blog
Microsoft Security Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
量子位
美团技术团队
The Cloudflare Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
罗磊的独立博客
The GitHub Blog
The GitHub Blog
阮一峰的网络日志
阮一峰的网络日志
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Stack Overflow Blog
Stack Overflow 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!

:)