actix-web: make cbor optional feature, add test
This commit is contained in:
parent
ce36e73639
commit
5898f63dac
|
@ -21,11 +21,16 @@ actix-web-actors = "4.0.0-beta.9"
|
|||
async-channel = "1.6.1"
|
||||
futures-util = { version = "0.3.0", default-features = false }
|
||||
serde_json = "1.0.64"
|
||||
serde_cbor = "0.11"
|
||||
serde_urlencoded = "0.7.0"
|
||||
futures-channel = "0.3.13"
|
||||
thiserror = "1.0.30"
|
||||
serde_cbor = { version = "0.11.2", optional = true }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
cbor = ["serde_cbor"]
|
||||
|
||||
[dev-dependencies]
|
||||
actix-rt = "2.2.0"
|
||||
async-mutex = "1.4.0"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use actix_http::body::BoxBody;
|
||||
use actix_web::error::JsonPayloadError;
|
||||
use core::fmt;
|
||||
use std::future::Future;
|
||||
use std::io::{self, ErrorKind};
|
||||
use std::pin::Pin;
|
||||
|
@ -8,9 +7,7 @@ use std::pin::Pin;
|
|||
use actix_http::error::PayloadError;
|
||||
use actix_web::dev::Payload;
|
||||
use actix_web::http::{Method, StatusCode};
|
||||
use actix_web::{
|
||||
http, Error, FromRequest, HttpRequest, HttpResponse, Responder, ResponseError, Result,
|
||||
};
|
||||
use actix_web::{http, Error, FromRequest, HttpRequest, HttpResponse, Responder, Result};
|
||||
use futures_util::future::{self, FutureExt};
|
||||
use futures_util::{StreamExt, TryStreamExt};
|
||||
|
||||
|
@ -157,16 +154,22 @@ impl From<async_graphql::BatchResponse> for GraphQLResponse {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct CborSerializeError(serde_cbor::Error);
|
||||
impl fmt::Display for CborSerializeError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
#[cfg(feature = "cbor")]
|
||||
mod cbor {
|
||||
use actix_web::{http::StatusCode, ResponseError};
|
||||
use core::fmt;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Error(pub serde_cbor::Error);
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
impl ResponseError for CborSerializeError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
impl ResponseError for Error {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -187,20 +190,26 @@ impl Responder for GraphQLResponse {
|
|||
.headers()
|
||||
.get(http::header::ACCEPT)
|
||||
.and_then(|val| val.to_str().ok());
|
||||
if accept == Some("application/cbor") {
|
||||
res.content_type("application/cbor");
|
||||
let body = match serde_cbor::to_vec(&self.0) {
|
||||
Ok(body) => body,
|
||||
Err(error) => return HttpResponse::from_error(CborSerializeError(error)),
|
||||
};
|
||||
res.append_header((http::header::CONTENT_LENGTH, body.len()));
|
||||
res.body(body)
|
||||
} else {
|
||||
res.content_type("application/json");
|
||||
res.body(match serde_json::to_vec(&self.0) {
|
||||
Ok(body) => body,
|
||||
Err(error) => return HttpResponse::from_error(JsonPayloadError::Serialize(error)),
|
||||
})
|
||||
}
|
||||
let (ct, body) = match accept {
|
||||
// optional cbor support
|
||||
#[cfg(feature = "cbor")]
|
||||
// this avoids copy-pasting the mime type
|
||||
Some(ct @ "application/cbor") => (
|
||||
ct,
|
||||
match serde_cbor::to_vec(&self.0) {
|
||||
Ok(body) => body,
|
||||
Err(e) => return HttpResponse::from_error(cbor::Error(e)),
|
||||
},
|
||||
),
|
||||
_ => (
|
||||
"application/json",
|
||||
match serde_json::to_vec(&self.0) {
|
||||
Ok(body) => body,
|
||||
Err(e) => return HttpResponse::from_error(JsonPayloadError::Serialize(e)),
|
||||
},
|
||||
),
|
||||
};
|
||||
res.content_type(ct);
|
||||
res.body(body)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -220,3 +220,51 @@ async fn test_count() {
|
|||
.into_bytes()
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "cbor")]
|
||||
#[actix_rt::test]
|
||||
async fn test_cbor() {
|
||||
let srv = test::init_service(
|
||||
App::new()
|
||||
.app_data(Data::new(Schema::new(
|
||||
AddQueryRoot,
|
||||
EmptyMutation,
|
||||
EmptySubscription,
|
||||
)))
|
||||
.service(
|
||||
web::resource("/")
|
||||
.guard(guard::Post())
|
||||
.to(gql_handle_schema::<AddQueryRoot, EmptyMutation, EmptySubscription>),
|
||||
),
|
||||
)
|
||||
.await;
|
||||
let response = srv
|
||||
.call(
|
||||
test::TestRequest::with_uri("/")
|
||||
.method(Method::POST)
|
||||
.set_payload(r#"{"query":"{ add(a: 10, b: 20) }"}"#)
|
||||
.insert_header((actix_http::header::ACCEPT, "application/cbor"))
|
||||
.to_request(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(response.status().is_success());
|
||||
#[derive(Debug, serde::Deserialize, PartialEq)]
|
||||
struct Response {
|
||||
data: ResponseInner,
|
||||
}
|
||||
#[derive(Debug, serde::Deserialize, PartialEq)]
|
||||
struct ResponseInner {
|
||||
add: i32,
|
||||
}
|
||||
let body = actix_web::body::to_bytes(response.into_body())
|
||||
.await
|
||||
.unwrap();
|
||||
let response: Response = serde_cbor::from_slice(&body).unwrap();
|
||||
assert_eq!(
|
||||
response,
|
||||
Response {
|
||||
data: ResponseInner { add: 30 }
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user