在 Rocket 中返回 HTTP 状态不是 200 的 JSON [英] Return JSON with an HTTP status other than 200 in Rocket
问题描述
我希望我的 Rocket API 有这样的路由:
I want my Rocket API to have a route like this:
#[post("create/thing", format = "application/json", data="<thing>")]
当客户端发送 { "name": "mything";}
,一切都应该没问题,我知道该怎么做,但是当它发送 { "name": "foo";}
它应该响应如下:
When the client sends { "name": "mything" }
, everything should be alright and I know how to do that, but when it sends { "name": "foo" }
it should respond with something like this:
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json
{
"errors": [
{
"status": "422",
"title": "Invalid thing name",
"detail": "The name for a thing must be at least 4 characters long."
}
]
}
如何在 Rocket 中使用 JSON 对象和不同于 200 的 HTTP 状态代码之类的结果进行响应?
How do I respond with a result like a JSON object and a HTTP status code different than 200 in Rocket?
这是我目前尝试过的:
impl
FromRequest
用于我的Thing
类型.这让我可以选择一个状态代码,因为我可以编写自己的from_request
函数,但我不能返回任何其他内容.- 注册一个错误捕捉器,如this example,但这样我只能对一个没有上下文的 HTTP 状态代码做出反应.我有太多的失败模式,无法为每个模式保留一个 HTTP 状态代码.
impl
FromRequest
for myThing
type. This lets me choose a status code as I can write my ownfrom_request
function, but I can't return anything else.- Registering an error catcher like in this example, but this way I only can react to one HTTP status code without context. I have too many failure modes to reserve one HTTP status code for each.
推荐答案
在@hellow 的帮助下,我想通了.解决方案是为新结构 ApiResponse
实现 Responder
特征,该结构包含状态代码以及 Json
.这样我就可以做我想做的事:
With @hellow's help, I figured it out. The solution is to implement the Responder
trait for a new struct ApiResponse
, which contains a status code as well the Json
. This way I can do exactly what I wanted:
#[post("/create/thing", format = "application/json", data = "<thing>")]
fn put(thing: Json<Thing>) -> ApiResponse {
let thing: Thing = thing.into_inner();
match thing.name.len() {
0...3 => ApiResponse {
json: json!({"error": {"short": "Invalid Name", "long": "A thing must have a name that is at least 3 characters long"}}),
status: Status::UnprocessableEntity,
},
_ => ApiResponse {
json: json!({"status": "success"}),
status: Status::Ok,
},
}
}
完整代码如下:
#![feature(proc_macro_hygiene)]
#![feature(decl_macro)]
#[macro_use]
extern crate rocket;
#[macro_use]
extern crate rocket_contrib;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
use rocket::http::{ContentType, Status};
use rocket::request::Request;
use rocket::response;
use rocket::response::{Responder, Response};
use rocket_contrib::json::{Json, JsonValue};
#[derive(Serialize, Deserialize, Debug)]
pub struct Thing {
pub name: String,
}
#[derive(Debug)]
struct ApiResponse {
json: JsonValue,
status: Status,
}
impl<'r> Responder<'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("/create/thing", format = "application/json", data = "<thing>")]
fn put(thing: Json<Thing>) -> ApiResponse {
let thing: Thing = thing.into_inner();
match thing.name.len() {
0...3 => ApiResponse {
json: json!({"error": {"short": "Invalid Name", "long": "A thing must have a name that is at least 3 characters long"}}),
status: Status::UnprocessableEntity,
},
_ => ApiResponse {
json: json!({"status": "success"}),
status: Status::Ok,
},
}
}
fn main() {
rocket::ignite().mount("/", routes![put]).launch();
}
这篇关于在 Rocket 中返回 HTTP 状态不是 200 的 JSON的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!