Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Exploring Kino

elixir/exploring_kino.livemd

Exploring Kino

Mix.install([
  {:kino, "~> 0.10.0"},
  {:req, "~> 0.3.10"},
  {:absinthe_client, "~> 0.1.0"}
])

Helpers

defmodule Github do
  def query(query_string) do
    Req.new(
      base_url: "https://api.github.com",
      headers: [
        {"Authorization", "bearer " <> System.get_env("LB_GITHUB_TOKEN")},
        {"Content-Type", "application/json"}
      ]
    )
    |> AbsintheClient.attach()
    |> Req.post!(graphql: query_string)
  end
end

Github Star Fetcher

defmodule StarFetcher do
  use GenServer

  def init(:ok) do
    state = %{frame: nil}
    {:ok, state, {:continue, :setup_form}}
  end

  def handle_continue(:setup_form, state) do
    form =
      [
        username: Kino.Input.text("Username"),
        repo: Kino.Input.text("Repository")
      ]
      |> Kino.Control.form(submit: "Fetch Stars")
      |> Kino.render()

    frame = Kino.Frame.new() |> Kino.render()
    Kino.Control.subscribe(form, :star_fetcher_form)
    {:noreply, %{state | frame: frame}}
  end

  def handle_info({:star_fetcher_form, %{data: %{username: username, repo: repo}}}, state) do
    response =
      Github.query("""
        query { 
          repository(owner: \"#{username}\", name: \"#{repo}\") {
            stargazerCount
          }
        }
      """)

    msg = handle_response(response, username, repo)
    Kino.Frame.append(state.frame, msg)
    {:noreply, state}
  end

  defp handle_response(%{status: 200, body: %{"errors" => errors}}, _username, _repo) do
    first_error = Enum.at(errors, 0)
    "Failed to fetch star count: #{Map.get(first_error, "message")}"
  end

  defp handle_response(%{status: 200, body: %{"data" => data}}, username, repo) do
    number_of_stars = data |> Map.get("repository") |> Map.get("stargazerCount")
    "https://github.com/#{username}/#{repo} has #{number_of_stars} stars"
  end

  defp handle_response(%{status: status}, _username, _repo) do
    "Search failed with status: #{status}"
  end
end
{:ok, star_fetcher} = GenServer.start(StarFetcher, :ok)