Intro
Github is a remote source control solution that can act as a source of truth and remote backup for your local versioning system, in this case Git.
It makes development and collaboration when working in small to large codebases and has a handy web client that offers you all the tools .
But as a developer you're bound to want more or a very specific layout that's not supported in their native implementation , and hats where APIs come in , Github has one of the best APIs i've tinkered with .this tutorial will start off with the REST implementation then we'll switch to their GraphQL api
final project
silly little app i call gitpals
Expand your github circle and find new developers along the way
uses github rest api and react with vite /br>
scripts
npm run dev
to start the dev server
npm run deploy
To deploy your site to gitpages
*this requires a bunch of initial set-up
Add add your github personal access token in the field , to clear it from local storage click on the profile pic icon on the right end of the toolbar
live preview on live page link
open to colaboration
fork the repo and make a pull request if you make any progress
usefull links
for starters i'd recommend setting up an api testing environment
and before we do that we'll also need a personal access token
then we'll an api client like postman or it's alternatives
and set the token in the header as such
remember to space the keyword Bearer to the actual token and
also add the application/json as shown below
and for example hitting the endpoint https://api.github.com/user will give you back the currently logged in user
and with that set up you can now experiment with queries even and make sure they work before using them .
Once sure of that we can start setting up react ,in this case i used axios with react-query
and the above query would look something like this
first we make the query function
export const getAuthedUserDetails=async(token:string,url:string)=>{
// const token = "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"
const res = await axios({
method: 'get',
url: url,
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
},
})
// console.log("response == ",res)
const user = res.data
// console.log("authed user == ",user)
return user
}
then we pass it into react-query
const query = useQuery(["main-user", token], () =>
getAuthedUserDetails(token, authed_user)
);
const user = query.data as MainAuthedUser;
type casting query.data to MainAuthedUser to give us the type checking when using this in the code.
I generated the types manually by pasting the json response to json-to-ts
And viola.
this works fine but you'll notice we're barely using 30% of the json returned which is where GraphQL shines by only requesting what we need it also has more data because of it;s flexible nature
Let's take the user query for example
"login": "tigawanna",
"id": 72096712,
"node_id": "MDQ6VXNlcjcyMDk2NzEy",
"avatar_url": "https://avatars.githubusercontent.com/u/72096712?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/tigawanna",
"html_url": "https://github.com/tigawanna",
"followers_url": "https://api.github.com/users/tigawanna/followers",
"following_url": "https://api.github.com/users/tigawanna/following{/other_user}",
"gists_url": "https://api.github.com/users/tigawanna/gists{/gist_id}",
"starred_url": "https://api.github.com/users/tigawanna/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/tigawanna/subscriptions",
"organizations_url": "https://api.github.com/users/tigawanna/orgs",
"repos_url": "https://api.github.com/users/tigawanna/repos",
"events_url": "https://api.github.com/users/tigawanna/events{/privacy}",
"received_events_url": "https://api.github.com/users/tigawanna/received_events",
"type": "User",
"site_admin": false,
"name": "Dennis kinuthia",
"company": null,
"blog": "https://next-portfolio-zeta-two.vercel.app/",
"location": "Nairobi Kenya ",
"email": "denniskinuthiaw@gmail.com",
"hireable": null,
"bio": "React GraphQL Node Go",
"twitter_username": null,
"public_repos": 49,
"public_gists": 0,
"followers": 11,
"following": 39,
"created_at": "2020-09-29T17:03:46Z",
"updated_at": "2022-09-01T21:26:46Z",
"private_gists": 0,
"total_private_repos": 6,
"owned_private_repos": 6,
"disk_usage": 47541,
"collaborators": 0,
"two_factor_authentication": false,
"plan": {
"name": "free",
"space": 976562499,
"collaborators": 0,
"private_repos": 10000
}
This is quite the response and you'll notice that it has the
followers and following url which will point you to an endpoint
with the list of them
My objective was to have something like this , because i wanted this app to make discovering other users and their projects easier
but the response for one follower looks like this
{
"login": "Harmon758",
"id": 9403740,
"node_id": "MDQ6VXNlcjk0MDM3NDA=",
"avatar_url": "https://avatars.githubusercontent.com/u/9403740?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/Harmon758",
"html_url": "https://github.com/Harmon758",
"followers_url": "https://api.github.com/users/Harmon758/followers",
"following_url": "https://api.github.com/users/Harmon758/following{/other_user}",
"gists_url": "https://api.github.com/users/Harmon758/gists{/gist_id}",
"starred_url": "https://api.github.com/users/Harmon758/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/Harmon758/subscriptions",
"organizations_url": "https://api.github.com/users/Harmon758/orgs",
"repos_url": "https://api.github.com/users/Harmon758/repos",
"events_url": "https://api.github.com/users/Harmon758/events{/privacy}",
"received_events_url": "https://api.github.com/users/Harmon758/received_events",
"type": "User",
"site_admin": false
},
The issue is it doesn't have information on whether I am following the user in order to know whether to show a follow or unfollow button.
so i used this work around
query 1 : to find if user is following another user , returns success if yes and 404 if false
export const getIsUserFollowingMe=async(token:string,me:string,them:string)=>{
const res = await axios({
method: 'get',
url:`https://api.github.com/users/${me}/following/${them}`,
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
},
})
// //console.log("response == ",res)
if(res.status === 204){
return true
}
return false
}
query 2 - the main query that will go through the array of followers urls and for each one pause to make an async call to check follow status and insert it into the final object then push it into an array
export const getUserWithFollowingDetails = async (token: string, url: string, username: string) => {
//console.log("user with following details ", username, url);
let followers:any=[]
const users = await getAuthedUserFollowers(token,url) as Follower[]
for await (const user of users) {
// //console.log("user with following details ",username,user.login);
//@ts-ignore
user.following_me = await getIsUserFollowingMe(token, username, user.login)
.catch((e)=>{})
followers.push(user)
}
return followers
}
Not only is this technique noticeably slower but will also burn through your rate limit very fast , and given the point of the app is to go deep into user profiles and fall deeper as you check who's following who and what repos they're working on you'll get timed out really fast
You could side step all of this and just remove the feature and only fetch those details if the follower card is clicked on or switch to the GraphQL api which unlocks some very handy features
Top comments (0)