GitHub App authentication in darklang

My friend introduced me to a project named darklang, or simply Dark. It's a serverless and deployless backend builder. A unique approach that sets it apart (at least for me) is stated on its Introduction page:

Darklang is an integrated language, framework, and editor for building web backends: REST API endpoints, asynchronous background workers, scheduled jobs, and persistent storage. Dark's framework is tightly coupled to the infrastructure, and as you write code you're able to develop from real incoming requests/traces.

Also, it is a functional language!

Dark is a statically-typed functional/imperative hybrid, based loosely on ML. Dark has implicit returns, and makes heavy use of pipelines and functions like List::map

So, having quite a bit of backend and API experience, I was intrigued! But mainly, I wanted to test-drive Dark and see how it felt.

I started a small project that I will share later; it uses GitHub API with App access, and I needed a way to authenticate my GitHub app. Since Dark is under active development, it doesn't have all the bells and whistles yet, but it's impressive how many features are already implemented.

This is a small, wanna-be-guide on creating and authenticating your GitHub app with Dark.

  1. Create a new GitHub App
  2. Generate a private key
  3. Add secrets to your project in Dark:
    • APP_ID - contains GitHub App ID; it can be found in the About section of your GitHub App
    • APP_PEM - contains a PEM certificate from the previous step
  4. Install the GitHub App into your profile
  5. Create a new function, github_authenticate, in your Dark functions. Add the following implementation:
let now = Date::now
let jwt = JWT::signAndEncodev1
              iat : now
              exp : Date::add now 60 * 10 - 1
              iss : APP_ID
let headers = {
                Accepts : "application/vnd.github.v3+json"
              |>Dict::set "User-Agent" "DarkGithub"
              |>Dict::merge HttpClient::bearerTokenv1 jwt
let installation = HttpClient::getv5 "" Dict::empty headers
                   |>\r -> r.body
                   |>List::getAtv1 0
let tokensUrl = String::join
let response = HttpClient::postv5 tokensUrl Dict::empty Dict::empty headers
Ok response.body

Here is how it looks in Dark:

Now we can test it with the following REPL:

let auth = github_authenticate
let headers = {
                Accepts : "application/vnd.github.v3+json"
              |>Dict::set "User-Agent" "DarkGithub"
              |>Dict::merge HttpClient::bearerTokenv1 auth.token
let response = HttpClient::getv5 "" Dict::empty headers
Ok response.body

...and look! It works! 😊