wasmcloud_interface_httpserver/
lib.rsmod httpserver;
pub use httpserver::*;
use serde::Serialize;
use std::string::ToString;
use wasmbus_rpc::error::RpcError;
impl Default for HttpResponse {
fn default() -> HttpResponse {
HttpResponse {
status_code: 200,
body: Vec::default(),
header: HeaderMap::default(),
}
}
}
impl HttpResponse {
pub fn json<T>(payload: T, status_code: u16) -> Result<HttpResponse, RpcError>
where
T: Serialize,
{
let body = serde_json::to_string(&payload)
.map_err(|e| RpcError::Ser(e.to_string()))?
.into_bytes();
let mut header = HeaderMap::new();
header.insert(
"content-type".to_string(),
vec!["application/json".to_string()],
);
Ok(HttpResponse {
body,
status_code,
header,
})
}
pub fn ok<S: Into<Vec<u8>>>(response: S) -> HttpResponse {
HttpResponse {
body: response.into(),
..Default::default()
}
}
pub fn json_with_headers<T>(
payload: T,
status_code: u16,
headers: std::collections::HashMap<String, Vec<String>>,
) -> Result<HttpResponse, RpcError>
where
T: Serialize,
{
let body = serde_json::to_string(&payload)
.map_err(|e| RpcError::Ser(e.to_string()))?
.into_bytes();
let mut fixed_header: HeaderMap = HeaderMap::from_iter(
headers
.iter()
.map(|(k, v)| (k.to_lowercase(), v.to_owned())),
);
if !fixed_header.contains_key("content-type") {
fixed_header.insert(
"content-type".to_string(),
vec!["application/json".to_string()],
);
}
Ok(HttpResponse {
body,
status_code,
header: fixed_header,
})
}
pub fn not_found() -> HttpResponse {
HttpResponse {
status_code: 404,
..Default::default()
}
}
pub fn internal_server_error<T: ToString>(msg: T) -> HttpResponse {
HttpResponse {
status_code: 500,
body: msg.to_string().as_bytes().into(),
..Default::default()
}
}
pub fn bad_request<T: ToString>(msg: T) -> HttpResponse {
HttpResponse {
status_code: 400,
body: msg.to_string().as_bytes().into(),
..Default::default()
}
}
}
#[cfg(test)]
mod test {
use super::HttpResponse;
use serde::{Serialize, Serializer};
#[test]
fn http_response_constructors() {
let r = HttpResponse::default();
assert_eq!(r.status_code, 200);
assert_eq!(r.body.len(), 0usize);
let r = HttpResponse::bad_request("Bad");
assert_eq!(r.status_code, 400);
assert_eq!(&r.body, b"Bad");
let r = HttpResponse::internal_server_error("Oops!");
assert_eq!(r.status_code, 500);
assert_eq!(&r.body, b"Oops!");
let r = HttpResponse::not_found();
assert_eq!(r.status_code, 404);
assert_eq!(r.body.len(), 0usize);
let mut obj: std::collections::HashMap<&str, Vec<u16>> = std::collections::HashMap::new();
obj.insert("list", vec![1, 2, 3]);
let r = HttpResponse::json(&obj, 201);
assert!(r.is_ok());
let r = r.unwrap();
assert_eq!(r.status_code, 201);
assert_eq!(&r.body, br#"{"list":[1,2,3]}"#);
let content_type = &r.header.get("content-type").unwrap();
assert_eq!(**content_type, vec!("application/json".to_string()));
let mut header: std::collections::HashMap<String, Vec<String>> =
std::collections::HashMap::new();
header.insert("x-something-one".to_owned(), vec!["foo".to_owned()]);
header.insert("X-Something-Two".to_owned(), vec!["bar".to_owned()]);
let r = HttpResponse::json_with_headers(&obj, 200, header.clone());
assert!(r.is_ok());
let r = r.unwrap();
assert_eq!(
*r.header.get("x-something-one").unwrap(),
vec!("foo".to_owned())
);
assert_eq!(
*r.header.get("x-something-two").unwrap(),
vec!("bar".to_owned())
);
assert_eq!(
*r.header.get("content-type").unwrap(),
vec!("application/json".to_owned())
);
header.insert(
"Content-Type".to_owned(),
vec!["application/text".to_owned()],
);
let r = HttpResponse::json_with_headers(&obj, 200, header).unwrap();
assert_eq!(
*r.header.get("content-type").unwrap(),
vec!("application/text")
);
}
struct Thing {
value: i32,
}
impl Serialize for Thing {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self.value {
13 => Err(serde::ser::Error::custom("you choose poorly")),
_ => serializer.serialize_i32(self.value),
}
}
}
#[test]
fn json_err() {
let r = HttpResponse::json(&{ Thing { value: 0 } }, 200);
assert!(r.is_ok());
let r = HttpResponse::json(&{ Thing { value: 13 } }, 200);
assert!(r.is_err());
}
}