63247


Rustのactix-webで条件を満たしたときにエラーレスポンスを返したく以下の通り実装しましたがエラーが出てしまいました。

[code]

    #[post("/backends")]
    async fn add_backend(
        pool: web::Data<DbPool>,
        form: web::Json<forms::BackendForm>,
        ) -> Result<HttpResponse, Error>{
    
        let resp = reqwest::get(&format!("{}/version", form.url))
            .await
            .map_err(|e| {
                eprintln!("{}", e);
                HttpResponse::BadRequest().finish()
            })?;
    
        if resp.status() != http::StatusCode::OK{
            HttpResponse::BadRequest().finish()
        }
    
        let version = resp.text()
            .await
            .map_err(|e| {
                eprintln!("{}", e);
                HttpResponse::BadRequest().finish()
            })?;
    
        if version == ""{
            Ok(HttpResponse::BadRequest().finish())
        }
    
        let conn = pool.get().expect("cant get db pool");
        let backend = web::block(move || actions::create_backend(&form.name, &form.url, &version, &conn))
            .await
            .map_err(|e| {
                eprintln!("{}", e);
                HttpResponse::InternalServerError().finish()
            })?;
    
        Ok(HttpResponse::Ok().json(backend))
    }
    
    
    
    error[E0308]: mismatched types
      --> src/main.rs:58:9
       |
    57 | /     if resp.status() != http::StatusCode::OK{
    58 | |         HttpResponse::BadRequest().finish()
       | |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `actix_http::response::Response`
    59 | |     }
       | |_____- expected this to be `()`
       |
       = note: expected unit type `()`
                     found struct `actix_http::response::Response`
    help: try adding a semicolon
       |
    58 |         HttpResponse::BadRequest().finish();
       |                                            ^
    help: consider using a semicolon here
       |
    59 |     };
       |      ^
    
    error[E0308]: mismatched types
      --> src/main.rs:69:9
       |
    68 | /     if version == ""{
    69 | |         Ok(HttpResponse::BadRequest().finish())
       | |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found enum `std::result::Result`
    70 | |     }
       | |_____- expected this to be `()`
       |
       = note: expected unit type `()`
                       found enum `std::result::Result<actix_http::response::Response, _>`
    help: try adding a semicolon
       |
    69 |         Ok(HttpResponse::BadRequest().finish());
       |                                                ^
    help: consider using a semicolon here
       |
    70 |     };
       |      ^
    
    error: aborting due to 2 previous errors
    
[/code]

`finish()`の返り値は`Result<HttpResponse, HttpError>`なのでこれで良いと考えましたがだめでした。  
`Ok`で包んでも同様のエラーが出てしまいます。セミコロンをつけることを推奨されていますが、つけるとエラーは消えますが、当然下まで実行されます。このような場合はどのように実装すれば良いのでしょうか。

参考: <https://docs.rs/actix-
web/0.3.1/actix_web/dev/struct.HttpResponseBuilder.html>


CC BY-SA 4.0
2020-02-21T13:41:55.093
63240
2020-02-22T04:03:14.473
7232
question
rust
actix-webで早期にレスポンスを返したい。


Rustでは単に`Ok(..)`などと式を書いただけでは関数からはリターンしません。早期にリターンさせるためには`return`文が必要です。ただし、関数の最後の式だけは例外で`return`は書かずに式だけを書きます。

以下のように2つの`if`文から返す値に`return`をつけてください。

[code]

        if resp.status() != http::StatusCode::OK{
            // 関数から早期リターンするために return 文を使う
            return Ok(HttpResponse::BadRequest().finish())
        }
    
        // 余談だが version == "" の代わりに version.is_empty() としてもよい
        if version.is_empty() {
            // 関数から早期リターン
            return Ok(HttpResponse::BadRequest().finish())
        }
    
[/code]

これでエラーが直るはずです。

ではなぜ、`if`文以外のところでは`return`文を書かずに関数から早期リターンできていたのでしょうか？
その理由は`?`後置演算子にあります。`?`演算子は引数に`Result`型か`Option`型の値をとり、それらが`Ok(..)`か`Some(..)`なら、包まれている値をアンラップします。また、もしそれらが`Err(..)`か`None`なら、`return`文のように関数から早期リターンします。`?`演算子の働きにより、`return`を書かなくても関数からの早期リターンが行われていたわけです。

もし、Rustのエラー処理全般について詳しく知りたいなら、こちらの和訳ドキュメントが参考になります。  
<https://doc.rust-jp.rs/the-rust-programming-language-ja/1.9/book/error-
handling.html>

ただし、このドキュメント（`1.9/book`）は2016年ごろに和訳されたものですので、全体的に内容が古くなっています。`try!()`マクロというものが出てきますが、現在ではそれに代わって`?`後置演算子を使います。`try!(値)`のところは`値?`と読み替えてください。

このドキュメントよりもう少し新しい、2018年ごろの2nd
Editionという和訳ドキュメントもあります。Rustの基本について知りたいときは、そちらも参照してください。ただ、残念なことに、2nd
Editionではエラー処理についてはあまり詳しく解説されていません。

参考までに、和訳ドキュメントの一覧はこちらにあります。 <https://doc.rust-jp.rs/>

あと、actix-
webに限らずフレームワークやライブラリはそのバージョンによって書き方が変わったりしますので、質問される際に、こんな感じでバージョンに関する情報を載せてもらえると助かります。（今回は別の質問の
[回答](https://ja.stackoverflow.com/a/63238/14101) を参考にしました）

  * Rust 1.41.0
  * actix-web 2.0
  * reqwest 0.10
  * serde 1.0


CC BY-SA 4.0
2020-02-22T01:37:33.437
63247
2020-02-22T04:03:14.473
2020-02-22T04:03:14.473
14101
14101
63240
answer