Skip to content

ルーティング

パスパラメーター、クエリパラメーターについて

http://example.com/path/param1/param2?query1=param3&query2=param4

この URL の、param1param2のように、パスに埋め込まれている情報をパスパラメーターと呼びます。

また、パスパラメーターの後にkey=value&key=value&...の形で埋め込まれる情報をクエリパラメーターと呼びます。この URL のparam3param4の部分です。

パスパラメーターを取得してみよう

"hello/{ユーザー名}"というパスのリクエストが来たときに、以下を返すサーバーを書いてみましょう。

Hello, {ユーザー名}.

axum ではパスに/:hogeのようなコロンから始まる文字列を含めると、ハンドラに渡される Path という構造体に格納されます。 考えうるユーザー名全てに対して 1 つずつハンドラを設定するのは不可能なので、パスパラメーターを取得して、それをもとにレスポンスを生成します。

rs
use axum::{extract::Path, routing::get, Router};

#[tokio::main]
async fn main() {
    // GETリクエストの"/hello/:username"というパターンに対応するルートを設定し、
    // URLのパラメータ(:username)を使用してhello_handler関数を呼び出す
    let app = Router::new().route("/hello/:username", get(hello_handler));

    // ポート8080でリスナーを作成する
    let listener = tokio::net::TcpListener::bind("127.0.0.1:8080")
        .await
        .unwrap();

    println!("listening on {}", listener.local_addr().unwrap());

    // サーバーを起動する
    axum::serve(listener, app).await.unwrap();
}

// ":username"というパスパラメーターを取得する
async fn hello_handler(Path(username): Path<String>) -> String {
    format!("Hello, {}.\n", username)
}

サーバーを立て直した後、localhost:8080/hello/kenken にアクセスして実際に機能していることを確かめましょう。 また、URL の kenken の部分を自分の名前や任意の文字列にしても動く事を確認しましょう。

/hello/:usernameとすることでPath(username)によってkenkenをとれることが分かりました。

参考

Path in axum::extract

クエリパラメータを取得してみよう

/hello/kenken?page=2&lang=ja

パスパラメーターではPath(param)を使いましたが、クエリパラメーターは受け取るための構造体を定義し、 Query(params)を使って取得します。 クエリパラメータは順不同で?lang=ja&page=2でも同じ意味になります。

基本問題

試しに、"hello/{ユーザー名}?lang={言語名}&page={ページ数}"というパスのリクエストが来たときに、以下を返すサーバーを書いてみましょう。

Hello, {ユーザー名}.
language: {言語名}
page: {ページ数}

書いたらサーバーを立て直した後、localhost:8080/hello/kenken?page=5&lang=ja にアクセスして実際に機能していることを確かめましょう。

解答
rs
use axum::{
    extract::{Path, Query},
    routing::get,
    Router,
};

#[tokio::main]
async fn main() {
    // GETリクエストの"/hello/:username"というパターンに対応するルートを設定し、
    // URLのパラメータ(:username)を使用してhello_handler関数を呼び出す
    let app = Router::new().route("/hello/:username", get(hello_handler));

    // ポート8080でリスナーを作成する
    let listener = tokio::net::TcpListener::bind("127.0.0.1:8080")
        .await
        .unwrap();

    println!("listening on {}", listener.local_addr().unwrap());

    // サーバーを起動する
    axum::serve(listener, app).await.unwrap();
}

// クエリパラメータを受け取るための構造体を定義
#[derive(serde::Deserialize)]
pub struct HelloQueryParam {
    lang: Option<String>,
    page: Option<String>,
}

async fn hello_handler(
    Path(username): Path<String>,
    // クエリパラメータを受け取る
    Query(query): Query<HelloQueryParam>,
) -> String {
    format!(
        "Hello, {}.\nlang: {}\npage: {}",
        username,
        query.lang.unwrap_or("".to_string()),
        query.page.unwrap_or("".to_string())
    )
}

このクエリパラメータは検索のリクエストを受け取るときに使うことが多いです。
例として、Google 検索だとこんな風になってます(Google検索のパラメータ(URLパラメータ)一覧)。

参考

Query in axum::extract