Livebook から curl を実行する

## はじめに

CLI で API を呼び出すとき、 curl をよく使います

Livebook からもターミナルでやっているのと同じように curl を実行することができます

実装したノートブックはこちら

https://github.com/RyoWakabayashi/elixir-learning/blob/main/livebooks/kino/kino_curl.livemd

## セットアップ

KinoCurl をインストールします

https://github.com/open-status/kino_curl

```elixir
Mix.install([
  {:kino_curl, "~> 0.1"},
  {:ex_curl, "~> 0.3", override: true}
])
```

:::note info
2024/12/4 現在、 `ex_curl` のバージョンを更新しないとインストールできません

インストールには Zig が必要です
:::

## スマートセルの追加

KinoCurl をインストールすると、 `cURL Command` のスマートセルが追加できるようになります

![スクリーンショット 2023-12-28 9.07.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/3330b715-39ed-4849-ead0-da537f20a61e.png)

`cURL Command` のスマートセルを追加すると以下のような表示になります

![スクリーンショット 2023-12-28 9.09.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/68180405-6e60-37ab-4237-661731d5a861.png)

セルの中身は curl コマンドそのものですね

## curl の実行

デフォルトのまま実行してみましょう

```bash
curl "https://hex.pm"
```

以下のような実行結果が返ってきます

```elixir
%ExCurl.Response{
  body: "<!DOCTYPE html>\n<html lang=\"en\" prefix=\"og: " <> ...,
  headers: %{
    "alt-svc" => "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000",
    "cache-control" => "max-age=0, private, must-revalidate",
    "content-length" => "28933",
    "content-type" => "text/html; charset=utf-8",
    "date" => "Thu, 28 Dec 2023 00:11:16 GMT",
    "referrer-policy" => "strict-origin-when-cross-origin",
    "server" => "Cowboy",
    "strict-transport-security" => "max-age=31536000",
    "vary" => "accept-encoding",
    "via" => "1.1 google",
    "x-content-type-options" => "nosniff",
    "x-download-options" => "noopen",
    "x-frame-options" => "SAMEORIGIN",
    "x-permitted-cross-domain-policies" => "none",
    "x-request-id" => "F6TWYmeXkQ-KBCUVHnKB"
  },
  status_code: 200,
  total_time: 0,
  namelookup_time: 0,
  connect_time: 0,
  appconnect_time: 0,
  pretransfer_time: 0,
  starttransfer_time: 0,
  metrics_returned: false
}
```

セルの右上 `<>` のボタンをクリックすると、実際に実行されている Elixir のコードが確認できます

![curl.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/4d775cbd-4856-b93f-e561-4d43ce241085.gif)

実態としては以下のようなコードが実行されていて、 ExCurl をラッピングしていることがわかります

```elixir
response = ExCurl.get!("https://hex.pm")
```

https://github.com/open-status/ex_curl

## 各種メソッド

各種メソッドについて、 httpbin.org にリクエストを投げてみましょう

https://httpbin.org/

### GET

curl コマンド
```bash
curl -X GET "https://httpbin.org/get?lang=elixir"
```

Elixir コード
```elixir
response = ExCurl.get!("https://httpbin.org/get?lang=elixir")
```

### POST

curl コマンド
```bash
curl -X POST --data '{"lang": "elixir"}' -H 'Content-Type: application/json' "https://httpbin.org/post"
```

Elixir コード
```elixir
response =
  ExCurl.post!("https://httpbin.org/post",
    body: "{\"lang\": \"elixir\"}",
    headers: %{"Content-Type" => "application/json"}
  )
```

### PUT

curl コマンド
```bash
curl -X PUT --data '{"lang": "elixir"}' --header 'Content-Type: application/json' "https://httpbin.org/put"
```

Elixir コード
```elixir
response =
  ExCurl.put!("https://httpbin.org/put",
    body: "{\"lang\": \"elixir\"}",
    headers: %{"Content-Type" => "application/json"}
  )
```

### PATCH

curl コマンド
```bash
curl -X PATCH -d 'lang=elixir' "https://httpbin.org/patch"
```

Elixir コード
```elixir
response =
  ExCurl.patch!("https://httpbin.org/patch",
    body: "lang=elixir",
    headers: %{"Content-Type" => "application/x-www-form-urlencoded"}
  )
```

### DELETE

curl コマンド
```bash
curl -X DELETE "https://httpbin.org/delete"
```

Elixir コード
```elixir
response = ExCurl.delete!("https://httpbin.org/delete")
```

## まとめ

curl コマンドをちゃんと解釈して Elixir に変換してくれるので、シェルコマンドはよくわかるけど Elixir にはまだ不慣れ、と言う人にはいいかもしれませんね