Rust/Yewで型を使って作業ミスを減らせた話
フロントエンド開発をしていると、特定のページに遷移する際にはmiddleware(特定の処理の前に割り込んで処理をする)が欲しいと思うことはよく有ります。
特に、ページ遷移するたびに、HTMLを表示したりAPIを叩いたりする前にユーザがログインしているかどうかをチェックしたい、というのは頻出のパターンですね。
Yewではそのようなmiddleware的な処理はpub children: Children
というプロパティを持った構造体を用意してComponentに渡すようにすれば簡単に実現できます。
#[derive(Properties, PartialEq)]
pub struct Props {
pub children: Children,
}
それはそれで良いのですが、実際に表示するページ側でそのmiddlewareを指定するのはあまりよろしくありません。
middlewareなので、各ページ的には「自分はそんな事に関心ないよ、自動でやっといてよね」となるのが普通です。
そこで、 yew-router
を使っているなら以下のようにルーティング時点でmiddlewareを指定してあげることが出来ます。
なお、以下の<Secure>
という部分が、私が作成したmiddleware相当のComponentです。
#[derive(Clone, Routable, PartialEq, Eq, Debug)]
pub enum Route {
#[at("/")]
Top,
#[at("/index2")]
Top2,
#[at("/signin/")]
Signin,
}
// これだと、ページが追加されていくと<Secure>をつけ忘れそう
pub fn switch(routes: Route) -> Html {
match routes {
Route::Top => html! {<Secure><index::Index /></Secure>},
Route::Top2 => html! {<index2::Index />},
Route::Signin => html! {<signin::Model />}
}
}
しかし、コメントに書いている通り、手動でmiddlewareを指定しているので、本来は指定しないといけないのに書き忘れてしまった、ということが発生しそうです。
と言うより実際に上記のコードは私がミスした実例です。本当はRoute::Top2
でも<Secure>
を付けるべきところ、それを忘れていました。
そこで、以下のようにして直接middlewareを指定するのではなく、「どのようなmiddlewareが必要か」という情報を持たせるようにしてあげます。
#[derive(Clone, Routable, PartialEq, Eq, Debug)]
pub enum Route {
#[at("/")]
Top,
#[at("/index2")]
Top2,
#[at("/signin/")]
Signin,
}
// 以下のように書くことで、ページを追加する際に必ずSecureTypeの指定をしないとコンパイルエラーになるので、ミスでつけ忘れることがなくなる。
enum SecureType {
Secure,
NonSecure,
}
pub fn switch(routes: Route) -> Html {
let (html: VNode, secure_type: SecureType) = match routes {
Route::Top => (html! {<index::Index />}, SecureType::Secure),
Route::Top2 => (html!{<index2::Index />}, SecureType::Secure),
Route::Signin => (html! {<signin::Model />}, SecureType::NonSecure)
};
match (html, secure_type) {
(html, SecureType::Secure) => html!{<Secure>{html}</Secure>},
(html, _) => html
}
}
このように書けば、必要なmiddlewareの情報をまとめたenumの値を書き忘れたらコンパイルエラーになるので、「必要だったのに書き忘れた」というミスを型を使って防止することが出来ます。
公開日:2023/01/26