use crate::http::{Body, ResponseBuilder, Status};
use crate::rpc::protocol;
use std::collections::HashMap;
#[derive(Default, Debug)]
pub struct HttpResponse {
pub(crate) data: protocol::RpcHttp,
pub(crate) status: Status,
}
impl HttpResponse {
pub(crate) fn new() -> Self {
HttpResponse {
data: protocol::RpcHttp::new(),
status: Status::Ok,
}
}
pub fn build() -> ResponseBuilder {
ResponseBuilder::new()
}
pub fn status(&self) -> Status {
self.status
}
pub fn body(&self) -> Body {
if self.data.has_body() {
Body::from(self.data.get_body())
} else {
Body::Empty
}
}
pub fn headers(&self) -> &HashMap<String, String> {
&self.data.headers
}
}
impl<'a, T> From<T> for HttpResponse
where
T: Into<Body<'a>>,
{
fn from(data: T) -> Self {
HttpResponse::build().body(data).into()
}
}
impl From<ResponseBuilder> for HttpResponse {
fn from(builder: ResponseBuilder) -> Self {
builder.0
}
}
impl Into<protocol::TypedData> for HttpResponse {
fn into(mut self) -> protocol::TypedData {
self.data.set_status_code(self.status.to_string());
let mut data = protocol::TypedData::new();
data.set_http(self.data);
data
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_is_empty_by_default() {
let response = HttpResponse::new();
assert_eq!(response.status(), Status::Ok);
assert!(matches!(response.body(), Body::Empty));
}
#[test]
fn it_is_empty_from_a_builder() {
let response: HttpResponse = HttpResponse::build().into();
assert_eq!(response.status(), Status::Ok);
assert!(matches!(response.body(), Body::Empty));
}
#[test]
fn it_builds_with_a_status() {
let response: HttpResponse = HttpResponse::build().status(Status::Continue).into();
assert_eq!(response.status(), Status::Continue);
}
#[test]
fn it_builds_with_a_string_body() {
const BODY: &'static str = "test body";
let response: HttpResponse = HttpResponse::build().body(BODY).into();
assert_eq!(
response.headers().get("Content-Type").unwrap(),
"text/plain"
);
assert_eq!(response.body().as_str().unwrap(), BODY);
}
#[test]
fn it_builds_with_a_json_body() {
#[derive(Serialize, Deserialize)]
struct Data {
message: String,
};
const MESSAGE: &'static str = "test";
let data = Data {
message: MESSAGE.to_string(),
};
let response: HttpResponse = HttpResponse::build()
.body(::serde_json::to_value(data).unwrap())
.into();
assert_eq!(
response.headers().get("Content-Type").unwrap(),
"application/json"
);
assert_eq!(response.body().as_json::<Data>().unwrap().message, MESSAGE);
}
#[test]
fn it_builds_with_a_bytes_body() {
const BODY: &'static [u8] = &[1, 2, 3];
let response: HttpResponse = HttpResponse::build().body(BODY).into();
assert_eq!(
response.headers().get("Content-Type").unwrap(),
"application/octet-stream"
);
assert_eq!(response.body().as_bytes(), BODY);
}
#[test]
fn it_builds_with_headers() {
let response: HttpResponse = HttpResponse::build()
.header("header1", "value1")
.header("header2", "value2")
.header("header3", "value3")
.into();
assert_eq!(response.headers().get("header1").unwrap(), "value1");
assert_eq!(response.headers().get("header2").unwrap(), "value2");
assert_eq!(response.headers().get("header3").unwrap(), "value3");
}
#[test]
fn it_converts_to_typed_data() {
let response: HttpResponse = HttpResponse::build()
.status(Status::BadRequest)
.header("header", "value")
.body("body")
.into();
let data: protocol::TypedData = response.into();
assert!(data.has_http());
let http = data.get_http();
assert_eq!(http.get_status_code(), "400");
assert_eq!(http.get_headers().get("header").unwrap(), "value");
assert!(http.get_body().has_string());
assert_eq!(http.get_body().get_string(), "body");
}
}