Public
Edited
Nov 3, 2023
Paused
3 forks
Importers
12 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
response = gh("https://github.com/periscopic/github-api-demo/blob/main/penguins.json")
Insert cell
dataJson = (await response).json()
Insert cell
Insert cell
repoPenguins = gh("https://github.com/periscopic/github-api-demo/blob/main/penguins.json")
.then(response => response.json())
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
files = gh("https://github.com/periscopic/github-api-demo/tree/main")
.then(response => response.json())
Insert cell
Insert cell
json = gh("https://github.com/periscopic/github-api-demo/blob/main/aapl.json")
.then(response => response.json())
Insert cell
Insert cell
csv = gh("https://github.com/periscopic/github-api-demo/blob/main/aapl.csv")
.then(res => res.text())
.then(text => d3.csvParse(text, d3.autoType))
Insert cell
Insert cell
db = gh("https://github.com/periscopic/github-api-demo/blob/main/chinook.db")
.then(SQLiteDatabaseClient.open)
Insert cell
db.describe("tracks")
Insert cell
Insert cell
arrowTable = gh("https://github.com/periscopic/github-api-demo/blob/main/flights-200k.arrow")
.then(res => res.arrayBuffer())
.then(buffer => Arrow.Table.from(new Uint8Array(buffer)))
Insert cell
Insert cell
aqArrow = gh("https://github.com/periscopic/github-api-demo/blob/main/flights-200k.arrow")
.then(res => res.arrayBuffer())
.then(buffer => Arrow.Table.from(new Uint8Array(buffer)))
.then(arrowTable => aq.fromArrow(arrowTable))
Insert cell
Insert cell
duckDb = gh("https://github.com/periscopic/github-api-demo/blob/main/flights-200k.arrow")
.then(res => res.arrayBuffer())
.then(buffer => Arrow.Table.from(new Uint8Array(buffer)))
.then(x => DuckDBClient.of({demo: aq.fromArrow(x).objects()}))
Insert cell
Insert cell
Insert cell
xlsx = require("xlsx@0.17.0/dist/xlsx.core.min.js")
Insert cell
workbook = gh("https://github.com/periscopic/github-api-demo/blob/main/Data%20Analyst%20Excel%20Meetup.xlsx")
.then(res => res.arrayBuffer())
.then(buffer => xlsx.read(new Uint8Array(buffer), { type: "array" }))
Insert cell
// example function to parse sheet from workbook object
// adapted from Fetch an Excel sheet by @neocarto
// - https://observablehq.com/@neocartocnrs/fetch-an-excel-sheet
function parseSheet(workbook, sheetname) {
let sheet = workbook.Sheets[sheetname];
// get the data
let range = xlsx.utils.decode_range(sheet["!ref"]);
range.s.r = 0; // skip rows
range.s.c = 0; // skip cols
sheet["!ref"] = xlsx.utils.encode_range(range);
return xlsx.utils.sheet_to_json(sheet);
}
Insert cell
excel = parseSheet(workbook, "StreetEasy Data")
Insert cell
Insert cell
image = gh("https://github.com/periscopic/github-api-demo/blob/main/li-zhang-HYwU-Fl6IoM-unsplash.jpeg")
.then(res => res.blob())
Insert cell
<img src=${URL.createObjectURL(image)} width=400>
Insert cell
Insert cell
gh("https://github.com/periscopic/github-api-demo/blob/main/secretPenguins.json")
.then(res => res.json())
Insert cell
Insert cell
gh("https://github.com/periscopic/github-api-demo/blob/9c954753a3548a1e2830eacde445cb95e099e404/secretPenguins.json")
.then(res => res.json())
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
recentCommits = gh("", {endpoint: "repos/periscopic/github-api-demo/commits"})
.then(res => res.json())
Insert cell
Insert cell
Insert cell
Insert cell
allInOne = {
let res = gh("https://github.com/periscopic/github-api-demo")
return (await res).json()
}
Insert cell
Insert cell
Insert cell
Insert cell
resRefresh = { // source cell
refreshButton2
return gh("https://github.com/periscopic/github-api-demo")
}
Insert cell
{ // wrangling cell
refreshButton1
return resRefresh.json()
}
Insert cell
Insert cell
gh("https://github.com/periscopic/github-api-demo", {debug: true})
Insert cell
Insert cell
async function gh(
link // chosen link in github repo
, {
endpoint = "repos", // endpoint string
ghToken = credentials[0].ghToken, // GitHub Personal Access Token, see https://docs.github.com/en/rest
debug = false // if true, return API url
} = {}) {

// main url endpoint for API, see https://docs.github.com/en/rest/repos/contents#custom-media-types-for-repository-contents
const URL_PREFIX = 'https://api.github.com'

// create header for accepting responses, see https://docs.github.com/en/rest/overview/media-types?apiVersion=2022-11-28
const headers = {
Accept: `application/vnd.github.raw`
}
if (ghToken !== null) {
headers["Authorization"] = `token ${ghToken}`
}

// parse data link: url → path
if (link == undefined) { return "Include GitHub Link (Docs: https://observablehq.com/@periscopic/github-api-in-observable)"}

// parsing the github link
let urlLink = ""
if (link !== "") {
const rawLink = String(link)
let inputLink = rawLink

// get url components to ping api
let unpack = inputLink.split("/").slice(3)
let owner = unpack.slice(0, 1)
let repo = unpack.slice(1, 2)
let flowType = unpack.slice(2, 3) // the kind of link, tree or blob
let branch = unpack.slice(3, 4)
let path = unpack.slice(4)

// get the default branch via the api
let fetchMeta = `${URL_PREFIX}/repos/${[owner, repo].join("/")}`
let resMeta = await fetch(fetchMeta, {
headers: headers
}).then((response) => response.json())
let defaultBranch = resMeta.default_branch

// define branch parameter
let branchRef = branch.slice(0, 1).length === 0 | branch.slice(0, 1)[0] === defaultBranch ? "" : "?ref=" + branch.slice(0, 1)[0]

// define the owner/repo/path
let linkArray = [owner, repo, "contents", path, branchRef]
let linkCollapsed = linkArray.flat()

// finish creating url link
urlLink = linkCollapsed.slice(0, -1).join("/") + linkCollapsed.slice(-1)
if (!urlLink.startsWith("/") & urlLink !== "") { urlLink = '/' + urlLink }
}

// parse the endpoint
const rawEndpoint = String(endpoint)
let urlEndpoint = rawEndpoint
if (!urlEndpoint.startsWith("/")) { urlEndpoint = '/' + urlEndpoint }

// make full link to ping api
let fetchQuery = `${URL_PREFIX}${urlEndpoint}${urlLink}`
if (debug) { return fetchQuery }

// get response, use username/password if provided
const response = await fetch(fetchQuery, {
headers: headers
})

// return response
return response

}
Insert cell
Insert cell
// pack up Observable Secrets, or return empty
credentials = {
try {
let ghToken = Secret("GH_API_PAT")
return [{ghToken}]
} catch (error) {
return [{ghToken: null}]
}
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more