Rustで基本的なCLIアプリを構築する方法

CLI(コマンドラインインターフェース)は、ソフトウェア開発とシステム管理において不可欠です。CLIは軽量なテキストベースのプログラムで、コンピューターと対話するための合理化された方法を提供します。これは、自動化、スクリプティング、リモート管理など、さまざまなユースケースで開発者やパワーユーザーに好まれています。

Rustは、CLIアプリの構築で人気が高まっています。Rustは、メモリ割り当てとスレッドセーフティ、メモリセーフティ、コンカレンシー、並列処理を細かく制御する強力な機能を提供しており、これらを活用して強力なCLIアプリを構築できます。Rustは、CLIアプリケーションの構築に特化したライブラリとフレームワークで構成される活気に満ちたエコシステムも備えています。

RustでCLIアプリの構築を開始する

RustでCLIアプリを構築するためのサードパーティパッケージには、**Clap**、**StructOpt**、**Termion**クレートなどがあります。これらのクレートは、最新のCLIツールを開発するために必要な機能を提供します。

また、Rustは標準ライブラリに**std::env**クレートを提供しており、環境変数とコマンドライン引数で動作するための機能を提供します。**std::env**クレートは、プラットフォームに依存しない方法で環境で動作するためのさまざまなメソッドと型を提供します。

**std::env**クレートを使用すると、Rustプログラムは環境と対話し、環境変数、コマンドライン引数、現在の作業ディレクトリなど、さまざまな要素に基づいて動作を調整できます。

Rustのパッケージ管理ツールであるCargoを使用して、CLIアプリの新しいRustプロジェクトを作成するには、このコマンドを実行します。

cargo new crypto_cli

RustでHTTPリクエストを行うための機能を提供する**Reqwest**クレートを使用して、CoinmarketcapのAPIを呼び出すCLIアプリケーションの構築方法を学習します。

**Cargo.toml**ファイルを開き、プロジェクトの依存関係に**reqwest**と**tokio**クレートを追加します。

[dependencies]
tokio = { version = "1.15", features = ["full"] }
reqwest = { version = "0.11", features = ["json"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

**tokio**クレートは、非同期プログラミングのための**reqwest**と相互運用する非同期ランタイムライブラリです。**serde**と**serde_json**クレートは、JSONのシリアル化と逆シリアル化に役立ちます。

Rustプロジェクトの**src**フォルダーで、API呼び出しとCLI機能を実装する**api.rs**と**cli.rs**ファイルを作成します。

touch src/api.rs src/cli.rs

このコマンドは、プロジェクトの作業ディレクトリに必要なファイルを作成する必要があります。懸念の分離のために指定されたファイルに機能を書き込んだ後、**main.rs**ファイルの**main**関数で関数を呼び出します。

ReqwestでCoinMarketCapのAPIにAPIリクエストを行う

CoinMarketCapのAPIを使用すると、暗号通貨データをアクセスしてアプリケーションに統合できます。このAPIは、リスト、市場の見積もり、取引所の情報、変換ツール、履歴データ、メタデータのエンドポイントを提供します。

サインインすると、CoinMarketCapのアカウントにサインアップし、Coinmarketcapの開発者ページでAPIキーを取得できます。詳細な手順と速度制限については、ドキュメントを参照することもできます。

1つまたは複数の暗号通貨の最新の市場の見積もりを返す**v2/cryptocurrency/quotes/latest**エンドポイントにAPIリクエストを行うには、APIから抽出するデータの構造体を定義し、Serdeのderiveトレイトで属性を指定する必要があります。

その後、エンドポイントにAPIをリクエストし、**serde_json**クレートを使用してJSONデータを構造体に逆シリアル化し、Rustデータ型で操作を容易にします。

指定された暗号通貨の**id**、**name**、**symbol**、**quote**データを取得する構造体の定義を次に示します。

#[derive(Debug, Deserialize, Serialize)]
struct ApiResponse {
data: Data,
}
#[derive(Debug, Deserialize, Serialize)]
struct Data {
// Add fields that you need from the data object
#[serde(rename = "1")]
crypto_1: Cryptocurrency,
#[serde(rename = "2")]
crypto_2: Cryptocurrency,
#[serde(rename = "3")]
crypto_3: Cryptocurrency,
#[serde(rename = "4")]
crypto_4: Cryptocurrency,
}
#[derive(Debug, Deserialize, Serialize)]
struct Cryptocurrency {
id: u32,
name: String,
symbol: String,
// Add other fields as needed
quote: Quote,
}
#[derive(Debug, Deserialize, Serialize)]
struct Quote {
USD: QuoteDetails,
}
#[derive(Debug, Deserialize, Serialize)]
struct QuoteDetails {
price: f64,
volume_24h: f64,
// Add other fields as needed
}

APIは必要以上のデータを返しますが、**serde**クレートを使用すると、上で示したように必要なデータを正確に指定できます。

次に、必要なパラメータでGETリクエストを行う新しいクライアントを作成することで、Reqwestでエンドポイントをリクエストできます。

use reqwest::Client;
use reqwest::Error;
pub async fn crypto() -> Result<(), Error> {
let client = Client::new();
let url = "https://pro-api.coinmarketcap.com/v2/cryptocurrency/quotes/latest";
let params = [
("id", "1,2,3,4"),
("convert", "USD"), // Convert market values to USD
];
let response = client.get(url)
.header("X-CMC_PRO_API_KEY", "YOUR API KEY HERE")
.query(¶ms)
.send().await?;
;
let result: ApiResponse = serde_json::from_str(&*response.text().await?;).unwrap();
println!("{:#?}", result);
Ok(())
}

**crypto**関数は、**Client::new**メソッドでクライアントインスタンスを作成した後、**client.get**関数でエンドポイントをリクエストするtokio対応の非同期関数です。

リクエストビルダーインスタンスの**header**関数呼び出しはあなたのAPIキーを取り、**query**関数はパラメータを取り、**send**関数はリクエストを送信します。

**crypto**関数は、JSON文字列を取り込むserde_jsonの**from_str**メソッドでJSON応答を逆シリアル化します。

最後に、**crypto**関数は逆シリアル化操作の結果をコンソールに出力します。

RustでのCLI引数の取得

**cli.rs**ファイルでは、**api.rs**ファイルから**crypto**関数をインポートし、ユーザーが**cargo run**コマンドでプロジェクトを実行するときに引数として「crypto」を指定した場合にその関数を呼び出します。

**std::env**関数を使用してコマンドラインから引数を取得する方法を次に示します。

use std::env;
use crate::api::crypto;
pub async fn cli() {
let args: Vec<String> = env::args().collect();
if args.len() > 1 && args[1] == "crypto" {
crypto().await.unwrap();
} else {
println!("Invalid command. Usage: cargo run crypto");
}
}

**cli**関数は、**env::args().collect()**関数でコマンドラインからすべての引数を取得します。**if-else**ステートメントは、追加の引数「crypto」があるかどうかを確認します。条件式がtrueを評価すると、**cli**関数は**crypto**関数を呼び出します。それ以外の場合は、**cli**関数は文字列をコンソールに出力します。

最後に、**main**関数で**cli**関数を呼び出すことができます。**main**関数はRustでは非同期にできないため、**#[tokio::main]**属性を追加する必要があります。

mod api;
mod cli;
use crate::cli::cli;
#[tokio::main]
async fn main() {
cli().await;
}

**main**関数は、**Future**の結果が準備できるまで実行を中断する**await**関数で**cli**関数を呼び出します。

**cargo run crypto**コマンドを実行した結果を次に示します。

Rustで洗練されたWebアプリを構築できます

Rustは、多くのユースケースとアプリケーションを持つ汎用的なプログラミング言語です。Actix、Rocket、WarpなどのサードパーティのWebフレームワークを活用して、RustでWebアプリケーションを構築できます。これらのフレームワークは、最新のWebアプリを構築するために必要な機能のほとんどを提供します。