背景
- $20 USDはらってGPT-4とRustでペアプロをしていた
- GPT-4君、2021年9月までしか学習してない
- 中途半端に本のコードを写経していただけだったのでハンドラの返り値の型の設定とかわかんね
→ ドキュメントを見に行こう
Trait for generating responses.
Types that implement IntoResponse can be returned from handlers.
(https://docs.rs/axum/0.6.16/axum/response/trait.IntoResponse.html より引用)
あれいままで気にしてなかったけどこれちゃんとやんないといけないやつだな……?
というか今まで適当に自作構造体を適当にJSON変換してハンドラに返答させてたけどなんでこれ動くんだ……?
仮説
- 書籍で
IntoResponse
のトレイトの実装を考えたことはなく、せいぜいハンドラの返り値で-> Result<impl IntoResponse, StatusCode>
とかしていた。 - ハンドラでかえすときは大抵
Ok((StatusCode, Json(Hoge))
とかしてたので、Json()
がIntoResponse
の振る舞いを定義してるならJSONに変換できる構造体、ってことにしておけばレスポンスの本体に加工できるのでは?
探すもの
-
axum::Json
のsource
にimpl IntoResponse for Json
が存在してれば勝
やったこと
まず docs.rsのaxum に行きます(執筆時最新バージョンを参照)
IntoResponseを探します。
sourceを見に行きます。Rustのドキュメント集はコード参照持ってきてくれるのがすごくすごいですね。
impl<T> IntoResponse for Json<T>
where
T: Serialize,
{
fn into_response(self) -> Response {
// Use a small initial capacity of 128 bytes like serde_json::to_vec
// https://docs.rs/serde_json/1.0.82/src/serde_json/ser.rs.html#2189
let mut buf = BytesMut::with_capacity(128).writer();
match serde_json::to_writer(&mut buf, &self.0) {
Ok(()) => (
[(
header::CONTENT_TYPE,
HeaderValue::from_static(mime::APPLICATION_JSON.as_ref()),
)],
buf.into_inner().freeze(),
)
.into_response(),
Err(err) => (
StatusCode::INTERNAL_SERVER_ERROR,
[(
header::CONTENT_TYPE,
HeaderValue::from_static(mime::TEXT_PLAIN_UTF_8.as_ref()),
)],
err.to_string(),
)
.into_response(),
}
}
}
仮説はあっていました。やったね!
余談
宝さがしみたいでおもろかった。