2018-05-20 21:03:29 -07:00
|
|
|
use actix_web::{
|
2019-03-07 14:50:29 -08:00
|
|
|
error, middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer,
|
2018-05-20 21:03:29 -07:00
|
|
|
};
|
2019-12-07 23:59:24 +06:00
|
|
|
use futures::StreamExt;
|
2018-04-13 09:18:42 +08:00
|
|
|
use json::JsonValue;
|
2020-01-12 14:04:02 +01:00
|
|
|
use serde::{Deserialize, Serialize};
|
2018-04-13 09:18:42 +08:00
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
|
|
struct MyObj {
|
|
|
|
name: String,
|
|
|
|
number: i32,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// This handler uses json extractor
|
2019-12-07 23:59:24 +06:00
|
|
|
async fn index(item: web::Json<MyObj>) -> HttpResponse {
|
2018-04-13 09:18:42 +08:00
|
|
|
println!("model: {:?}", &item);
|
2018-05-08 11:08:43 -07:00
|
|
|
HttpResponse::Ok().json(item.0) // <- send response
|
2018-04-13 09:18:42 +08:00
|
|
|
}
|
|
|
|
|
2018-06-02 08:28:33 -07:00
|
|
|
/// This handler uses json extractor with limit
|
2019-12-07 23:59:24 +06:00
|
|
|
async fn extract_item(item: web::Json<MyObj>, req: HttpRequest) -> HttpResponse {
|
2019-03-07 14:50:29 -08:00
|
|
|
println!("request: {:?}", req);
|
|
|
|
println!("model: {:?}", item);
|
|
|
|
|
|
|
|
HttpResponse::Ok().json(item.0) // <- send json response
|
2018-06-02 08:28:33 -07:00
|
|
|
}
|
|
|
|
|
2018-05-08 11:08:43 -07:00
|
|
|
const MAX_SIZE: usize = 262_144; // max payload size is 256k
|
2018-04-13 09:18:42 +08:00
|
|
|
|
|
|
|
/// This handler manually load request payload and parse json object
|
2019-12-07 23:59:24 +06:00
|
|
|
async fn index_manual(mut payload: web::Payload) -> Result<HttpResponse, Error> {
|
2019-03-07 14:50:29 -08:00
|
|
|
// payload is a stream of Bytes objects
|
2020-09-12 16:49:45 +01:00
|
|
|
let mut body = web::BytesMut::new();
|
2019-12-07 23:59:24 +06:00
|
|
|
while let Some(chunk) = payload.next().await {
|
|
|
|
let chunk = chunk?;
|
|
|
|
// limit max size of in-memory payload
|
|
|
|
if (body.len() + chunk.len()) > MAX_SIZE {
|
|
|
|
return Err(error::ErrorBadRequest("overflow"));
|
|
|
|
}
|
|
|
|
body.extend_from_slice(&chunk);
|
|
|
|
}
|
|
|
|
|
|
|
|
// body is loaded, now we can deserialize serde-json
|
|
|
|
let obj = serde_json::from_slice::<MyObj>(&body)?;
|
|
|
|
Ok(HttpResponse::Ok().json(obj)) // <- send response
|
2018-04-13 09:18:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// This handler manually load request payload and parse json-rust
|
2020-09-12 16:49:45 +01:00
|
|
|
async fn index_mjsonrust(body: web::Bytes) -> Result<HttpResponse, Error> {
|
2019-12-07 23:59:24 +06:00
|
|
|
// body is loaded, now we can deserialize json-rust
|
|
|
|
let result = json::parse(std::str::from_utf8(&body).unwrap()); // return Result
|
|
|
|
let injson: JsonValue = match result {
|
|
|
|
Ok(v) => v,
|
|
|
|
Err(e) => json::object! {"err" => e.to_string() },
|
|
|
|
};
|
|
|
|
Ok(HttpResponse::Ok()
|
|
|
|
.content_type("application/json")
|
|
|
|
.body(injson.dump()))
|
2018-04-13 09:18:42 +08:00
|
|
|
}
|
|
|
|
|
2020-09-12 16:49:45 +01:00
|
|
|
#[actix_web::main]
|
2019-12-07 23:59:24 +06:00
|
|
|
async fn main() -> std::io::Result<()> {
|
2019-03-07 14:50:29 -08:00
|
|
|
std::env::set_var("RUST_LOG", "actix_web=info");
|
2018-04-13 09:18:42 +08:00
|
|
|
env_logger::init();
|
|
|
|
|
2019-03-07 14:50:29 -08:00
|
|
|
HttpServer::new(|| {
|
2018-04-13 09:18:42 +08:00
|
|
|
App::new()
|
|
|
|
// enable logger
|
2019-03-26 04:29:00 +01:00
|
|
|
.wrap(middleware::Logger::default())
|
2019-05-04 21:52:24 -07:00
|
|
|
.data(web::JsonConfig::default().limit(4096)) // <- limit size of the payload (global configuration)
|
|
|
|
.service(web::resource("/extractor").route(web::post().to(index)))
|
2019-03-07 14:50:29 -08:00
|
|
|
.service(
|
2019-05-04 21:52:24 -07:00
|
|
|
web::resource("/extractor2")
|
|
|
|
.data(web::JsonConfig::default().limit(1024)) // <- limit size of the payload (resource level)
|
2019-12-07 23:59:24 +06:00
|
|
|
.route(web::post().to(extract_item)),
|
2019-03-07 14:50:29 -08:00
|
|
|
)
|
2019-12-07 23:59:24 +06:00
|
|
|
.service(web::resource("/manual").route(web::post().to(index_manual)))
|
|
|
|
.service(web::resource("/mjsonrust").route(web::post().to(index_mjsonrust)))
|
2019-03-07 14:50:29 -08:00
|
|
|
.service(web::resource("/").route(web::post().to(index)))
|
|
|
|
})
|
|
|
|
.bind("127.0.0.1:8080")?
|
2019-12-25 20:48:33 +04:00
|
|
|
.run()
|
2019-12-07 23:59:24 +06:00
|
|
|
.await
|
2018-04-13 09:18:42 +08:00
|
|
|
}
|
2019-11-13 18:20:24 +01:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
use actix_web::dev::Service;
|
2019-12-07 23:59:24 +06:00
|
|
|
use actix_web::{http, test, web, App};
|
2019-11-13 18:20:24 +01:00
|
|
|
|
2019-12-11 11:33:12 +09:00
|
|
|
#[actix_rt::test]
|
|
|
|
async fn test_index() -> Result<(), Error> {
|
|
|
|
let mut app = test::init_service(
|
|
|
|
App::new().service(web::resource("/").route(web::post().to(index))),
|
|
|
|
)
|
|
|
|
.await;
|
2019-11-13 18:20:24 +01:00
|
|
|
|
|
|
|
let req = test::TestRequest::post()
|
|
|
|
.uri("/")
|
2019-12-07 23:59:24 +06:00
|
|
|
.set_json(&MyObj {
|
|
|
|
name: "my-name".to_owned(),
|
|
|
|
number: 43,
|
|
|
|
})
|
2019-11-13 18:20:24 +01:00
|
|
|
.to_request();
|
2019-12-11 11:33:12 +09:00
|
|
|
let resp = app.call(req).await.unwrap();
|
2019-11-13 18:20:24 +01:00
|
|
|
|
|
|
|
assert_eq!(resp.status(), http::StatusCode::OK);
|
|
|
|
|
|
|
|
let response_body = match resp.response().body().as_ref() {
|
|
|
|
Some(actix_web::body::Body::Bytes(bytes)) => bytes,
|
|
|
|
_ => panic!("Response error"),
|
|
|
|
};
|
|
|
|
|
|
|
|
assert_eq!(response_body, r##"{"name":"my-name","number":43}"##);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|