How can I send a JSON 400 error with a specific message, using Rocket?

I am new to Rust. I am using Rocket.

I have a function for file uploads. The size of the upload is restricted.

Doing an upload of a small file succeeds and returns my JSON success message:

curl --form file='@temp.pdf' http://localhost:8000/upload
{"status":"success"}

Doing an upload of a file that is too large returns some other 400 message.

curl --form file='@/home/ubuntu/out.img' http://localhost:8000/upload
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>400 Bad Request</title>
</head>
<body align="center">
    <div role="main" align="center">
        <h1>400: Bad Request</h1>
        <p>The request could not be understood by the server due to malformed syntax.</p>
        <hr />
    </div>
    <div role="contentinfo" align="center">
        <small>Rocket</small>
    </div>
</body>
</html>

The server console says:

🚀 Rocket has launched from http://0.0.0.0:8000
POST /upload multipart/form-data:
   >> Matched: (upload) POST /upload
   >> Outcome: Success
   >> Response succeeded.
POST /upload multipart/form-data:
   >> Matched: (upload) POST /upload
   >> Data guard `Form < FileUploadForm < '_ > >` failed: Errors([Error { name: Some("file"), value: None, kind: Io(Custom { kind: Other, error: field "file" received with incomplete data }), entity: Form }]).
   >> Outcome: Failure
   >> No 400 catcher registered. Using Rocket default.
   >> Response succeeded.
POST /upload multipart/form-data:
   >> Matched: (upload) POST /upload
   >> Outcome: Success
   >> Response succeeded.
POST /upload multipart/form-data:
   >> Matched: (upload) POST /upload
   >> Outcome: Success
   >> Response succeeded.
POST /upload multipart/form-data:
   >> Matched: (upload) POST /upload
   >> Data guard `Form < FileUploadForm < '_ > >` failed: Errors([Error { name: Some("file"), value: None, kind: Io(Custom { kind: Other, error: field "file" received with incomplete data }), entity: Form }]).
   >> Outcome: Failure
   >> No 400 catcher registered. Using Rocket default.
   >> Response succeeded.

Here is my code:

Can anyone suggest why I cannot send my own 400 error?

thanks!

#[macro_use] extern crate rocket;

mod paste_id;
#[cfg(test)] mod tests;

use std::io;

use rocket::{Request, Route, Catcher, route, catcher};
use rocket::data::{Data, ToByteUnit};
use rocket::http::uri::Absolute;
use rocket::response::content::RawText;
use rocket::tokio::fs::{self, File};
use rocket::form::Form;
use rocket::fs::{FileServer, TempFile, relative};
use rocket::serde::json::{Json, Value, json};
use rocket::serde::{Serialize, Deserialize};
use rocket::serde::uuid::Uuid;
use crate::paste_id::PasteId;
use rocket::response;
use rocket::response::status;
use rocket::data::Capped;
use rocket::http::{Status, ContentType};
use std::io::Cursor;
use rocket::response::{Responder, Response};
const HOST: Absolute<'static> = uri!("http://localhost:8000");

#[derive(FromForm)]
pub struct FileUploadForm<'f> {
    #[field(validate = len(1..))]
    file: Capped<TempFile<'f>>,
}

#[derive(Debug)]
struct ApiResponse {
    json: Value,
    status: Status,
}

impl<'r> Responder<'r, 'r> for ApiResponse {
    fn respond_to(self, req: &Request) -> response::Result<'r> {
        Response::build_from(self.json.respond_to(&req).unwrap())
            .status(self.status)
            .header(ContentType::JSON)
            .ok()
    }
}

#[post("/upload", data = "<form>")]
pub async fn upload(mut form: Form<FileUploadForm<'_>>) -> ApiResponse {

    if form.file.is_complete() {
        form.file.persist_to("file.bin").await;
    } else {
        return ApiResponse {
            json: json!({"status": "application error"}),
            status: Status::BadRequest,
        }
    }
    ApiResponse {
        json: json!({"status": "success"}),
        status: Status::Ok,
    }
}


#[launch]
fn rocket() -> _ {
    rocket::build()
        .mount("/", routes![upload])

}


Looks like its something like this per docs... (I've never used rocket so this may not work)

#[rocket::catch(400)]
fn bad_request() -> &'static str {
    "Bad Request"
}

#[launch]
fn rocket() -> _ {
    rocket::build()
        .mount("/", routes![upload])
        .register(rocket::catchers![bad_request])

}

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.