実現したいこと
Rust Axumで実装するアプリケーションのログイン画面などのフォームバリデーションをreact-fook-formで実装したい
発生している問題・分からないこと
入力フォームから送信ボタンを押してPostしようとすると、422 (Unprocessable Entity) エラーが発生し、Postできない。
Reactと、Rust Axumのソースコードは以下の通りです。
エラーメッセージ
error
1http://192.168.33.10:3000/login 422 (Unprocessable Entity) 2 3※↑入力フォーム側のConsole上のエラーメッセージ。Axum側では、以下のようにRunningとなったままで、Requestを受け付けたログなどははかれていない。 4 5 Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.77s 6 Running `target/debug/axum`
該当のソースコード
React
1import './App.css'; 2import { useForm } from 'react-hook-form'; 3import React from 'react'; 4 5function App() { 6 const { register, 7 handleSubmit, 8 formState: {errors}, 9 } = useForm({ 10 criteriaMode: 'all', 11 }); 12 13 const onSubmit = (data) => { 14 const formData = new FormData(data); 15 // formData.append("username", data.username); 16 // formData.append("password", data.password); 17 fetch("./login", { 18 method: "POST", 19 headers: { 20 "Content-Type": "application/x-www-form-urlencoded", 21 }, 22 body: formData 23 }); 24 console.log(formData); 25 }; 26 27 return ( 28 <div className="App"> 29 <form onSubmit={handleSubmit(onSubmit)}> 30 <div class="mb-3 mt-3"> 31 <input type="text" class="form-control" placeholder="user name" {...register('username', { 32 required: { 33 value: true, 34 message: 'This is a required field.', 35 }, 36 minLength: { 37 value: 6, 38 message: 'Please enter at least 6 characters.' 39 }, 40 maxLength: { 41 value: 20, 42 message: 'Please enter less than 20 characters.' 43 }, 44 pattern: { 45 value: /^[A-Za-z0-9_]+$/, 46 message: 'Please enter alphanumeric characters only.' 47 } 48 })}/> 49 {errors.username?.type === 'required' && (<div class="fs-s error-msg">{errors.username.types.required}</div>)} 50 {errors.username?.type === 'minLength' && (<div class="fs-s error-msg">{errors.username.types.minLength}</div>)} 51 {errors.username?.type === 'maxLength' && (<div class="fs-s error-msg">{errors.username.types.maxLength}</div>)} 52 {errors.username?.type === 'pattern' && (<div class="fs-s error-msg">{errors.username.types.pattern}</div>)} 53 </div> 54 <input type="password" class="form-control" placeholder="password" {...register('password', { 55 required: { 56 value: true, 57 message: 'This is a required field.', 58 }, 59 minLength: { 60 value: 8, 61 message: 'Please enter at least 8 characters.' 62 }, 63 maxLength: { 64 value: 25, 65 message: 'Please enter less than 25 characters.' 66 }, 67 pattern: { 68 value: /^[A-Za-z0-9_]+$/, 69 message: 'Please enter alphanumeric characters only.' 70 } 71 })}/> 72 {errors.password?.type === 'required' && (<div class="fs-s error-msg">{errors.password.types.required}</div>)} 73 {errors.password?.type === 'minLength' && (<div class="fs-s error-msg">{errors.password.types.minLength}</div>)} 74 {errors.password?.type === 'maxLength' && (<div class="fs-s error-msg">{errors.password.types.maxLength}</div>)} 75 {errors.password?.type === 'pattern' && (<div class="fs-s error-msg">{errors.password.types.pattern}</div>)} 76 <span class="fs-s">If you don't have account, you can <a href="/signup">Sign up</a>.</span><br/> 77 <input type="submit" class="btn submit" value="login" /> 78 </form> 79 </div> 80 ); 81} 82 83export default App;
Rust
1#[derive(Serialize, Deserialize)] 2struct LoginForm { 3 username: String, 4 password: String, 5} 6 7#[tokio::main] 8async fn main() { 9 10 let serve_dir = ServeDir::new("static").not_found_service(ServeFile::new("static")); 11 12 let app = Router::new() 13 .route("/", get(handle_index)) 14 .route("/login", post(handle_api)) 15 .nest_service("/static", serve_dir.clone()) 16 .fallback_service(serve_dir); 17 18 let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); 19 axum::serve(listener, app).await.unwrap(); 20} 21 22async fn handle_api(axum::Form(loginform): axum::Form<LoginForm>)-> axum::response::Html<String> { 23 24 let tera = tera::Tera::new("templates/*").unwrap(); 25 26 let mut context = tera::Context::new(); 27 context.insert("title", "Index page"); 28 29 let output = tera.render("app.html", &context); 30 axum::response::Html(output.unwrap()) 31}
試したこと・調べたこと
- teratailやGoogle等で検索した
- ソースコードを自分なりに変更した
- 知人に聞いた
- その他
上記の詳細・結果
Rust Axum側は、普通のHTMLファイルのformの場合は問題なくデータを受け取ることができるので、Reactの onSubmit の中の書き方が問題ではないかと色々試したが、うまくいなかい。
最初、new FormData(data); とせずに、body: data としていたが、うまくいなかった。
補足
特になし

回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2025/02/08 12:39