Closed5
Webアプリ開発で学ぶRust言語入門やる

-
(StatusCode, R)
というタプル型にIntoResponse型を実装している - R型は、IntoResponse型を実装していることを要求
-
let mut res = self.1.into_response();
レスポンスを取得し、そのレスポンスに*res.status_mut() = self.0;
ステータスコードを代入している

このトレイト境界が難しい
#[async_trait]
impl<T, B> FromRequest<B> for ValidatedJson<T>
where
T: DeserializeOwned + Validate,
B: http_body::Body + Send, // NOTE: 最新バージョンだとコンパイルエラー
B::Data: Send,
B::Error: Into<BoxError>,
{
type Rejection = (StatusCode, String);
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
let Json(value) = Json::<T>::from_request(req).await.map_err(|rejection| {
let message = format!("Json parse error: [{}]", rejection);
(StatusCode::BAD_REQUEST, message)
})?;
value.validate().map_err(|rejection| {
let message = format!("Validation error: [{}]", rejection).replace('\n', ", ");
(StatusCode::BAD_REQUEST, message)
})?;
Ok(ValidatedJson(value))
}
}

どう考えれば導出できるか考えてみる
```rust
#[async_trait]
pub trait FromRequest<B>: Sized {
/// If the extractor fails it'll use this "rejection" type. A rejection is
/// a kind of error that can be converted into a response.
type Rejection: IntoResponse;
/// Perform the extraction.
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection>;
}

DeserializeOwned
はコピーが走っているのかな。Deserialize
はjsonの参照を持っていてライフタイムの制約があるから、使えないのかな。
use serde::{Deserialize, Serialize};
use std::borrow::Cow;
#[derive(Serialize, Deserialize)]
struct NormalStruct {
data: String,
}
#[derive(Serialize, Deserialize)]
struct BorrowingStruct<'a> {
data: Cow<'a, str>,
}
fn deserialize_owned<T: serde::de::DeserializeOwned>(json: &str) -> Result<T, serde_json::Error> {
serde_json::from_str(json)
}
fn deserialize_lifetime<'a, T: Deserialize<'a>>(json: &'a str) -> Result<T, serde_json::Error> {
serde_json::from_str(json)
}
fn main() {
let json = r#"{"data": "test"}"#;
// DeserializeOwned (works with owned data)
let normal: NormalStruct = deserialize_owned(json).unwrap();
println!("Normal: {}", normal.data);
// Deserialize (can work with borrowed data)
let borrowing: BorrowingStruct = deserialize_lifetime(json).unwrap();
println!("Borrowing: {}", borrowing.data);
// Serialize (for completeness)
let serialized = serde_json::to_string(&normal).unwrap();
println!("Serialized: {}", serialized);
}

Json<T>::from_request(req)
を実装するんだから、定義通りトレイト境界は書けばいいんだな
#[async_trait]
impl<T, B> FromRequest<B> for Json<T>
where
T: DeserializeOwned,
B: HttpBody + Send,
B::Data: Send,
B::Error: Into<BoxError>,
{
type Rejection = JsonRejection;
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
if json_content_type(req)? {
let bytes = Bytes::from_request(req).await?;
let value = serde_json::from_slice(&bytes).map_err(InvalidJsonBody::from_err)?;
Ok(Json(value))
} else {
Err(MissingJsonContentType.into())
}
}
}
このスクラップは2024/12/27にクローズされました