use custom_debug_derive::Debug;
use linera_witty::{WitLoad, WitStore, WitType};
use serde::{Deserialize, Serialize};
use crate::hex_debug;
#[derive(Clone, Debug, Eq, PartialEq, WitLoad, WitStore, WitType)]
#[witty(name = "http-request")]
pub struct Request {
pub method: Method,
pub url: String,
pub headers: Vec<Header>,
#[debug(with = "hex_debug")]
pub body: Vec<u8>,
}
impl Request {
pub fn get(url: impl Into<String>) -> Self {
Request {
method: Method::Get,
url: url.into(),
headers: vec![],
body: vec![],
}
}
pub fn post(url: impl Into<String>, payload: impl Into<Vec<u8>>) -> Self {
Request {
method: Method::Post,
url: url.into(),
headers: vec![],
body: payload.into(),
}
}
pub fn post_json(
url: impl Into<String>,
payload: &impl Serialize,
) -> Result<Self, serde_json::Error> {
Ok(Request {
method: Method::Post,
url: url.into(),
headers: vec![Header::new("Content-Type", b"application/json")],
body: serde_json::to_vec(payload)?,
})
}
pub fn with_header(mut self, name: impl Into<String>, value: impl Into<Vec<u8>>) -> Self {
self.headers.push(Header::new(name, value));
self
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, WitLoad, WitStore, WitType)]
#[witty(name = "http-method")]
pub enum Method {
Get,
Post,
Put,
Delete,
Head,
Options,
Connect,
Patch,
Trace,
}
#[cfg(with_reqwest)]
impl From<Method> for reqwest::Method {
fn from(method: Method) -> Self {
match method {
Method::Get => reqwest::Method::GET,
Method::Post => reqwest::Method::POST,
Method::Put => reqwest::Method::PUT,
Method::Delete => reqwest::Method::DELETE,
Method::Head => reqwest::Method::HEAD,
Method::Options => reqwest::Method::OPTIONS,
Method::Connect => reqwest::Method::CONNECT,
Method::Patch => reqwest::Method::PATCH,
Method::Trace => reqwest::Method::TRACE,
}
}
}
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, WitLoad, WitStore, WitType)]
#[witty(name = "http-response")]
pub struct Response {
pub status: u16,
pub headers: Vec<Header>,
#[debug(with = "hex_debug")]
#[serde(with = "serde_bytes")]
pub body: Vec<u8>,
}
impl Response {
pub fn new(status_code: u16) -> Self {
Response {
status: status_code,
headers: vec![],
body: vec![],
}
}
pub fn ok(body: impl Into<Vec<u8>>) -> Self {
Response {
status: 200,
headers: vec![],
body: body.into(),
}
}
pub fn unauthorized() -> Self {
Response {
status: 401,
headers: vec![],
body: vec![],
}
}
pub fn with_header(mut self, name: impl Into<String>, value: impl Into<Vec<u8>>) -> Self {
self.headers.push(Header::new(name, value));
self
}
}
#[cfg(with_reqwest)]
impl Response {
pub async fn from_reqwest(response: reqwest::Response) -> reqwest::Result<Self> {
let headers = response
.headers()
.into_iter()
.map(|(name, value)| Header::new(name.to_string(), value.as_bytes()))
.collect();
Ok(Response {
status: response.status().as_u16(),
headers,
body: response.bytes().await?.to_vec(),
})
}
}
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, WitLoad, WitStore, WitType)]
#[witty(name = "http-header")]
pub struct Header {
pub name: String,
#[debug(with = "hex_debug")]
#[serde(with = "serde_bytes")]
pub value: Vec<u8>,
}
impl Header {
pub fn new(name: impl Into<String>, value: impl Into<Vec<u8>>) -> Self {
Header {
name: name.into(),
value: value.into(),
}
}
}