I saw an example showing that the GitHub API had been enabled to support the CORS protocol, and successfully managed to do a JavaScript fetch() of a file blob from it. It was very cool when it worked--especially since the Base64 decoding I used was libRebol!
It turns out that wasn't actually necessary: What I didn't know was that GitHub had enabled fetch() on the raw.github.com
family of URLs too (!) So just using those URLs is much cleaner.
But it was a good thing to test and get working. And I'm sure people will be wanting to make GitHub API requests of other kinds. So here's the function I had. It has a spec that's a Rebol block, and can be called from Rebol...but which has a body of JavaScript (that also calls back into Rebol via the libRebol JS API...!)
github-read: js-awaiter [
owner [text!]
repo [text!] ; !!! TBD: branch?
path [text!]
]{
let owner = reb.Spell(reb.ArgR('owner'))
let repo = reb.Spell(reb.ArgR('repo'))
let path = reb.Spell(reb.ArgR('path'))
let url = "https://api.github.com/repos/" + owner + "/" + repo
+ "/contents" + path
let response = await fetch(url)
if (!response.ok) // https://www.tjvantoll.com/2015/09/13/fetch-and-errors/
throw Error(response.statusText)
let json = await response.json() // GitHub gives Base64 in JSON envelope
return reb.Promise("debase/base", reb.T(json.content), reb.I(64)) // see note
}
Note: The actual way you have to return that "promise" at this exact moment isn't as pretty, but that's what I'm working on. Current code makes you write it as a function that calls reb.Run()
return function () { return reb.Run("debase/base", reb.T(json.content), reb.I(64)) }
Despite needing to perform various I/O operations that need to unblock the stack, it will not return to the Rebol caller until the final result is finished. It's a tricky process to orchestrate and do the bookkeeping of threads to allow the back and forth to make it all happen. And when threads are NOT available, it's very tricky too!
(But the absolute trickiest bit is writing one codebase that can be built both ways, and does all that management in a non-invasive way to the Rebol core!)
Another piece of this puzzle was the code that transformed URLs, which was just a little parse rule. It shows the use of :(...) as a way of running code and then splicing the result of the rule in. If it's null, it vaporizes. (There's no /blob in the raw URLs)
parse url [
["https://github.com/" (raw: false) | "https://raw.github.com" (raw: true)]
copy owner: to "/" skip
copy repo: to "/" skip
:(if not raw ["blob/"])
copy branch: to "/"
copy path: to end ; include the leading /
] else [
; Not a GitHub file URL
]