🗿

Rust で実装したモック用 REST API サーバーを実行できる CLI を crates.io と Homebrew で公開する

2024/09/16に公開

CLI ツールを公開・配布する

Rust で実装した CLI ツールを公開・配布したいなと思い、crates.ioHomebrew で公開・配布する方法を試してみました!!!!

ripgrep から学ぶ

Rust 実装の有名なツールとして、ripgrep (rg) という 正規表現でディレクトリを再帰的に grep できる ツールがあります。

次のコマンドを実行すると、特定の glob にマッチするファイルの中から、マッチする単語 foo を検索することができます。

rg foo -g 'README.*'

この ripgrep は CLI ツールの実装の参考としてはもちろん、
様々な方法でインストールすることができるので、ツールの公開・配布する方法も学ぶことができます!

crates.io と cargo install

Rust プログラマーなら馴染みがあるであろう crates.io ですが、ライブラリとなるクレートだけでなく、作成したツールであるバイナリクレートを共有することもできます。

バイナリクレートは cargo install でインストールすることができます。

例えば、SQLx なども以下のコマンドで sqlx-cli をインストールして開発時に使用します。

cargo install sqlx-cli

バイナリクレートとは、クレートが src/main.rs ファイルやバイナリとして指定された他のファイルを持つ場合に生成される実行可能なプログラムのことを指します。[1]

大雑把にいうと cargo new --bin で作成した Rust アプリケーションです。

crates.io に公開する

CLI ツールを crates.io で公開する手順については、同僚の Shota.i さんが紹介してくれているので、ここでは割愛します!

以下の記事を参考にしてください😉🌟

https://zenn.dev/collabostyle/articles/c54fdd44938e9f

なお、公開する際は以下のメタデータを Cargo.toml に記載する必要があります。

最初に作成される Cargo.toml にないものもあるので、追記を忘れないようにしましょう!

(最初、必要な情報がないよと怒られてエラーで公開できませんでした...笑)

参考のために、公開したツールの Cargo.toml もおいておきます!

Cargo.toml
[package]
name = "mocks"
version = "0.2.1"
edition = "2021"
authors = ["codemountains <codemountains@gmail.com>"]
description = "Get a mock REST APIs with zero coding within seconds."
homepage = "https://github.com/mocks-rs/mocks"
repository = "https://github.com/mocks-rs/mocks"
documentation = "https://github.com/mocks-rs/mocks"
readme = "README.md"
license = "MIT"

cargo install

無事に crates.io に公開することができました!

https://crates.io/crates/mocks

以下のコマンドでインストールできます。

cargo install mocks
アンインストール

もちろん、アンインストールもできます。

cargo uninstall mocks

Homebrew で公開する

Homebrew は、macOS 向けのオープンソースのパッケージ管理システムで、ターミナルを使って簡単にさまざまなソフトウェアをインストール・アップデート・削除できます。

macOS において、開発ツールやアプリケーションをインストールする手段として一般的に利用されているため、Mac で開発しているエンジニアなら一度は触ったことがある方も多いのではないでしょうか!

公開手順で Ruby のファイルを作成するので気になって調べてみると、
[brew](https://github.com/Homebrew/brew) コマンドは Ruby 製なんですね...!

なんちゃって Ruby デビューです🙌笑

brew install できるようにする

Homebrew でインストールする場合のコマンドは brew install です。

このコマンドで作成した CLI をインストールできるようにします!

Homebrew でインストールを可能にするには、以下の方法があります。

  1. Github に homebrew-xxx repository を作成する
  2. Github に homebrew-tap repository を作成する
  3. Homebrew の公式リポジトリに Formula を追加する

公式リポジトリに Formula を追加する方法以外では、brew tap コマンドを使い、
サードパーティのツールをインストールできる仕組みを利用していきます!

では、順番に手順を確認していきます。

1. homebrew-xxx repository を作成する

まず、homebrew-{ツール名} というリポジトリを作成します。

ローカルにクローンして作業を進めます。

cargo build する

ツールをビルドして、tar コマンドで tar.gz に圧縮していきます。

また、次のステップで Formula を作成する際に、SHA ハッシュ値を使用するため shasum を実行して、値を控えておきます。

cargo build --release
cd target/release
tar -czf mocks-0.1.1-x86_64-apple-darwin.tar.gz mocks
shasum -a 256 mocks-0.1.1-x86_64-apple-darwin.tar.gz

作成した tar.gz を Github のリリースに添付します!
この添付したファイルを Homebrew がダウンロード・解凍してツールを格納してくれるわけです。

なお、ファイル名は ripgrep (rg) を参考に命名しました。

Homebrew Formula の作成

以下の構成で Formula/mocks.rb を作成します。

.rb ということで、Ruby で記述する必要があります!
Ruby 未経験者なので、テンプレートをコピーして改変していきます笑

homebrew-mocks
└── Formula
    └── mocks.rb
mocks.rb
class Mocks < Formula
    desc "Get a mock REST APIs with zero coding within seconds."
    homepage "https://github.com/mocks-rs/mocks"
    url "https://github.com/mocks-rs/mocks/releases/download/0.1.1/mocks-0.1.1-x86_64-apple-darwin.tar.gz"
    sha256 "0acdf8512f8a22f5a2766d63fd9dea92930b09859b36694e9ed6372fa7170dda"
    version "0.1.1"

    def install
        bin.install "mocks"
    end
end

ここまで作成したら、プッシュして完了です。

以下のコマンドで公開したツールをインストールすることができます

brew tap mocks-rs/mocks
brew install mocks
アンインストール

もちろん、アンインストールもできます。

brew remove mocks
brew untap mocks-rs/mocks

homebrew-mocks repository

プッシュしたリポジトリです。

2. homebrew-tap repository を作成する

Github で homebrew-tap というリポジトリを作成します。

必ず -tap を付ける必要があり、tap とは Homebrew のパッケージの定義ファイルである Formula を集めたリポジトリです。

この tap で有名なものとして aws/homebrew-tap があります。

この公開手順も、先ほどの homebrew-mocks の手順と大きな違いはありません。

cargo build する

上述した cargo build する と同じ手順です。

すでにリリースでビルドしたツールを公開している場合、
そのツールのダウンロード URL は同じで OK なのでスキップします。

Homebrew Formulaの作成

以下の構成で Formula/mocks.rb を作成します。

homebrew-tap
└── Formula
    └── mocks.rb
mocks.rb
class Mocks < Formula
    desc "Get a mock REST APIs with zero coding within seconds."
    homepage "https://github.com/mocks-rs/mocks"
    url "https://github.com/mocks-rs/mocks/releases/download/0.1.1/mocks-0.1.1-x86_64-apple-darwin.tar.gz"
    sha256 "0acdf8512f8a22f5a2766d63fd9dea92930b09859b36694e9ed6372fa7170dda"
    version "0.1.1"

    def install
        bin.install "mocks"
    end
end

ここまで作成したら、プッシュして完了です。

以下のコマンドで公開したツールをインストールすることができます🥳🎉

tap -> install の流れではなく、install コマンドのみになりました!!!

brew install mocks-rs/tap/mocks
アンインストール

もちろん、アンインストールもできます。

brew remove mocks
brew untap mocks-rs/tap

homebrew-tap repository

プッシュしたリポジトリです。

3. Homebrew の公式リポジトリに Formula を追加する

以下の記事が参考になりそうです。

公式リポジトリ Homebrew/homebrew-core にプルリクを送り、マージされることで追加される仕組みのようです。

公式リポジトリに追加されると、brew install {ツール名} でインストールすることができます。

機会があれば、こちらにも挑戦してみたいと思います!

[最後に] mocks の紹介

最後に...

作成したツールにも触れていきます...🤫笑

公開手順で出てきた mocks が気になった方や Rustacean の方は見ていってください🫶

https://github.com/mocks-rs/mocks

mocks とは

npm でいうところの json-server のような REST API を検証するためのモックサーバーを起動できるツールです。

mocks の使い方

詳細は mocks-rs/mocks をご確認ください✊

REST API サーバーを起動する

まず --help でオプションなどを確認できます。

% mocks --help
Get a mock REST APIs with zero coding within seconds.

Usage: mocks [OPTIONS] <FILE>

Arguments:
  <FILE>  Path of json file for data storage

Options:
  -H, --host <HOST>   Host [default: localhost]
  -p, --port <PORT>   Port [default: 3000]
      --no-overwrite  No overwrite save to json file
  -h, --help          Print help
  -V, --version       Print version

データを格納した JSON ファイルのパスを指定してコマンドを実行することで、モック用 REST API サーバーの起動することができます。

mocks storage.json
storage.json
{
  "posts": [
    { "id": "01J7BAKH37HPG116ZRRFKHBDGB", "title": "first post", "views": 100 },
    { "id": "01J7BAKH37GE8B688PT4RC7TP4", "title": "second post", "views": 10 }
  ],
  "comments": [
    { "id": 1, "text": "a comment", "post_id": "01J7BAKH37HPG116ZRRFKHBDGB" },
    { "id": 2, "text": "another comment", "post_id": "01J7BAKH37HPG116ZRRFKHBDGB" }
  ],
  "profile": { "id": "01J7BAQE1GMD78FN3J0FJCNS8T", "name": "mocks" },
  "friends": []
}

JSON ファイルを読み取り、エンドポイントを作成してくれます。

% mocks storage.json
`mocks` started
Press CTRL-C to stop

Index:
http://localhost:3000

Storage files:
storage.json

Overwrite:
YES

Endpoints:
http://localhost:3000/comments
http://localhost:3000/friends
http://localhost:3000/posts
http://localhost:3000/profile
% curl http://localhost:3000/posts
{"posts":[{"id":"01J7BAKH37HPG116ZRRFKHBDGB","title":"first post","views":100},{"id":"01J7BAKH37GE8B688PT4RC7TP4","title":"second post","views":10},{"id":"01J7WV7H1KE5RJN7W0HMW9YQTH","title":"new post","views":0}]}
% curl -X POST http://localhost/posts -H 'Content-Type: application/json' -d '{"id":"01J7WV7H1KE5RJN7W0HMW9YQTH","title":"new post","views":0}'
{"id":"01J7WV7H1KE5RJN7W0HMW9YQTH","title":"new post","views":0}

最初に添付した GIF 画像を見ていただけると分かりますが、
JSON ファイルの更新されるところを見ながら操作するのが個人的には好きです笑

--no-overwrite モード

JSON ファイルを上書きしないように実行することができます。

上書きしない場合、メモリ上にデータが保存されるので起動中は参照することができますが、
ファイルに書き込みに行くことはしません。

再実行した際に、元々の綺麗なデータの状態から API を起動することができます!!

mocks の実装について

以下のクレートを使って実装しています。

  • axum
    • Web フレームワーク、REST API サーバーを起動
  • clap
    • CLI ツールのインターフェースを構築
  • serde_json
    • JSON オブジェクトの操作
  • tokio
    • 非同期ランタイム

型の決まっていない不定形の JSON オブジェクトの取り扱いに難儀しました...。
型が決まっていれば、serde で簡単に扱えると思うのですが...🥶🥶

テストコードを追加して、リファクタリングもやっていきたいところです。

興味のある方が Github をのぞいてみてください🤝✨

まとめ

CLI ツールを crates.io と Homebrew で公開・配布する方法を試してみました!

ただ、crates.io は Rust プログラマー向けですし、Homebrew は Mac ユーザー向けです。
様々環境でのインストールに対応するには、まだまだやることがあるかなと思います。

自分も OSS で誰かの役に立つツールを開発できるようになりたいものです🔥🔥

mocks もページング対応だったり、ソーティング対応だったり...
もう少しパワーアップできるように細々とメンテしていきたいです!!!!

参考

脚注
  1. cargo installでCrates.ioからバイナリをインストールする を参照 ↩︎

コラボスタイル Developers

Discussion