http: configure method, headers, etc.

This commit is contained in:
Brian Carroll 2022-07-23 08:52:35 +01:00
parent f8771ebeb2
commit b5edd03554
No known key found for this signature in database
GPG Key ID: 5C7B2EC4101703C0
4 changed files with 209 additions and 169 deletions

View File

@ -86,7 +86,7 @@ stringBody = \mimeType, str ->
handleStringResponse : Response -> Result Str Error
handleStringResponse = \response ->
when response is
BadUrl url -> Err (BadUrl url)
BadRequest err -> Err (BadRequest err)
Timeout -> Err Timeout
NetworkError -> Err NetworkError
BadStatus metadata _ -> Err (BadStatus metadata.statusCode)
@ -101,7 +101,7 @@ handleStringResponse = \response ->
errorToString : Error -> Str
errorToString = \err ->
when err is
BadUrl url -> "\(url) is not a valid URL"
BadRequest e -> "Invalid Request: \(e)"
Timeout -> "Request timed out"
NetworkError -> "Network error"
BadStatus code -> Str.concat "Request failed with status " (Num.toStr code)

View File

@ -29,7 +29,7 @@ Body : [
]
Response : [
BadUrl Str,
BadRequest Str,
Timeout,
NetworkError,
BadStatus Metadata (List U8),
@ -44,7 +44,7 @@ Metadata : {
}
Error : [
BadUrl Str,
BadRequest Str,
Timeout,
NetworkError,
BadStatus U16,

View File

@ -18,8 +18,8 @@
#[repr(u8)]
pub enum discriminant_Error {
BadBody = 0,
BadStatus = 1,
BadUrl = 2,
BadRequest = 1,
BadStatus = 2,
NetworkError = 3,
Timeout = 4,
}
@ -28,8 +28,8 @@ impl core::fmt::Debug for discriminant_Error {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::BadBody => f.write_str("discriminant_Error::BadBody"),
Self::BadRequest => f.write_str("discriminant_Error::BadRequest"),
Self::BadStatus => f.write_str("discriminant_Error::BadStatus"),
Self::BadUrl => f.write_str("discriminant_Error::BadUrl"),
Self::NetworkError => f.write_str("discriminant_Error::NetworkError"),
Self::Timeout => f.write_str("discriminant_Error::Timeout"),
}
@ -40,8 +40,8 @@ impl core::fmt::Debug for discriminant_Error {
#[repr(C)]
pub union Error {
BadBody: core::mem::ManuallyDrop<roc_std::RocStr>,
BadRequest: core::mem::ManuallyDrop<roc_std::RocStr>,
BadStatus: u16,
BadUrl: core::mem::ManuallyDrop<roc_std::RocStr>,
_sizer: [u8; 16],
}
@ -184,8 +184,8 @@ pub union U2 {
#[derive(Clone, Copy, Eq, Ord, Hash, PartialEq, PartialOrd)]
#[repr(u8)]
pub enum discriminant_Response {
BadStatus = 0,
BadUrl = 1,
BadRequest = 0,
BadStatus = 1,
GoodStatus = 2,
NetworkError = 3,
Timeout = 4,
@ -194,8 +194,8 @@ pub enum discriminant_Response {
impl core::fmt::Debug for discriminant_Response {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::BadRequest => f.write_str("discriminant_Response::BadRequest"),
Self::BadStatus => f.write_str("discriminant_Response::BadStatus"),
Self::BadUrl => f.write_str("discriminant_Response::BadUrl"),
Self::GoodStatus => f.write_str("discriminant_Response::GoodStatus"),
Self::NetworkError => f.write_str("discriminant_Response::NetworkError"),
Self::Timeout => f.write_str("discriminant_Response::Timeout"),
@ -206,8 +206,8 @@ impl core::fmt::Debug for discriminant_Response {
#[cfg(any(target_arch = "arm", target_arch = "wasm32", target_arch = "x86"))]
#[repr(C)]
pub union Response {
BadRequest: core::mem::ManuallyDrop<roc_std::RocStr>,
BadStatus: core::mem::ManuallyDrop<Response_BadStatus>,
BadUrl: core::mem::ManuallyDrop<roc_std::RocStr>,
GoodStatus: core::mem::ManuallyDrop<Response_GoodStatus>,
_sizer: [u8; 56],
}
@ -574,8 +574,8 @@ pub union TimeoutConfig {
#[repr(C)]
pub union Error {
BadBody: core::mem::ManuallyDrop<roc_std::RocStr>,
BadRequest: core::mem::ManuallyDrop<roc_std::RocStr>,
BadStatus: u16,
BadUrl: core::mem::ManuallyDrop<roc_std::RocStr>,
_sizer: [u8; 32],
}
@ -589,8 +589,8 @@ pub union Body {
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
#[repr(C)]
pub union Response {
BadRequest: core::mem::ManuallyDrop<roc_std::RocStr>,
BadStatus: core::mem::ManuallyDrop<Response_BadStatus>,
BadUrl: core::mem::ManuallyDrop<roc_std::RocStr>,
GoodStatus: core::mem::ManuallyDrop<Response_GoodStatus>,
_sizer: [u8; 112],
}
@ -697,6 +697,60 @@ impl Error {
&payload
}
#[cfg(any(
target_arch = "arm",
target_arch = "aarch64",
target_arch = "wasm32",
target_arch = "x86",
target_arch = "x86_64"
))]
/// Construct a tag named `BadRequest`, with the appropriate payload
pub fn BadRequest(arg: roc_std::RocStr) -> Self {
let mut answer = Self {
BadRequest: core::mem::ManuallyDrop::new(arg),
};
answer.set_discriminant(discriminant_Error::BadRequest);
answer
}
#[cfg(any(
target_arch = "arm",
target_arch = "aarch64",
target_arch = "wasm32",
target_arch = "x86",
target_arch = "x86_64"
))]
/// Unsafely assume the given `Error` has a `.discriminant()` of `BadRequest` and convert it to `BadRequest`'s payload.
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `BadRequest`.
pub unsafe fn into_BadRequest(mut self) -> roc_std::RocStr {
debug_assert_eq!(self.discriminant(), discriminant_Error::BadRequest);
let payload = core::mem::ManuallyDrop::take(&mut self.BadRequest);
payload
}
#[cfg(any(
target_arch = "arm",
target_arch = "aarch64",
target_arch = "wasm32",
target_arch = "x86",
target_arch = "x86_64"
))]
/// Unsafely assume the given `Error` has a `.discriminant()` of `BadRequest` and return its payload.
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `BadRequest`.
pub unsafe fn as_BadRequest(&self) -> &roc_std::RocStr {
debug_assert_eq!(self.discriminant(), discriminant_Error::BadRequest);
let payload = &self.BadRequest;
&payload
}
#[cfg(any(
target_arch = "arm",
target_arch = "aarch64",
@ -749,60 +803,6 @@ impl Error {
&payload
}
#[cfg(any(
target_arch = "arm",
target_arch = "aarch64",
target_arch = "wasm32",
target_arch = "x86",
target_arch = "x86_64"
))]
/// Construct a tag named `BadUrl`, with the appropriate payload
pub fn BadUrl(arg: roc_std::RocStr) -> Self {
let mut answer = Self {
BadUrl: core::mem::ManuallyDrop::new(arg),
};
answer.set_discriminant(discriminant_Error::BadUrl);
answer
}
#[cfg(any(
target_arch = "arm",
target_arch = "aarch64",
target_arch = "wasm32",
target_arch = "x86",
target_arch = "x86_64"
))]
/// Unsafely assume the given `Error` has a `.discriminant()` of `BadUrl` and convert it to `BadUrl`'s payload.
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `BadUrl`.
pub unsafe fn into_BadUrl(mut self) -> roc_std::RocStr {
debug_assert_eq!(self.discriminant(), discriminant_Error::BadUrl);
let payload = core::mem::ManuallyDrop::take(&mut self.BadUrl);
payload
}
#[cfg(any(
target_arch = "arm",
target_arch = "aarch64",
target_arch = "wasm32",
target_arch = "x86",
target_arch = "x86_64"
))]
/// Unsafely assume the given `Error` has a `.discriminant()` of `BadUrl` and return its payload.
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `BadUrl`.
pub unsafe fn as_BadUrl(&self) -> &roc_std::RocStr {
debug_assert_eq!(self.discriminant(), discriminant_Error::BadUrl);
let payload = &self.BadUrl;
&payload
}
#[cfg(any(target_arch = "arm", target_arch = "wasm32", target_arch = "x86"))]
/// A tag named NetworkError, which has no payload.
pub const NetworkError: Self = unsafe {
@ -930,10 +930,10 @@ impl Drop for Error {
discriminant_Error::BadBody => unsafe {
core::mem::ManuallyDrop::drop(&mut self.BadBody)
},
discriminant_Error::BadStatus => {}
discriminant_Error::BadUrl => unsafe {
core::mem::ManuallyDrop::drop(&mut self.BadUrl)
discriminant_Error::BadRequest => unsafe {
core::mem::ManuallyDrop::drop(&mut self.BadRequest)
},
discriminant_Error::BadStatus => {}
discriminant_Error::NetworkError => {}
discriminant_Error::Timeout => {}
}
@ -958,8 +958,8 @@ impl PartialEq for Error {
unsafe {
match self.discriminant() {
discriminant_Error::BadBody => self.BadBody == other.BadBody,
discriminant_Error::BadRequest => self.BadRequest == other.BadRequest,
discriminant_Error::BadStatus => self.BadStatus == other.BadStatus,
discriminant_Error::BadUrl => self.BadUrl == other.BadUrl,
discriminant_Error::NetworkError => true,
discriminant_Error::Timeout => true,
}
@ -984,8 +984,8 @@ impl PartialOrd for Error {
unsafe {
match self.discriminant() {
discriminant_Error::BadBody => self.BadBody.partial_cmp(&other.BadBody),
discriminant_Error::BadRequest => self.BadRequest.partial_cmp(&other.BadRequest),
discriminant_Error::BadStatus => self.BadStatus.partial_cmp(&other.BadStatus),
discriminant_Error::BadUrl => self.BadUrl.partial_cmp(&other.BadUrl),
discriminant_Error::NetworkError => Some(core::cmp::Ordering::Equal),
discriminant_Error::Timeout => Some(core::cmp::Ordering::Equal),
}
@ -1010,8 +1010,8 @@ impl Ord for Error {
unsafe {
match self.discriminant() {
discriminant_Error::BadBody => self.BadBody.cmp(&other.BadBody),
discriminant_Error::BadRequest => self.BadRequest.cmp(&other.BadRequest),
discriminant_Error::BadStatus => self.BadStatus.cmp(&other.BadStatus),
discriminant_Error::BadUrl => self.BadUrl.cmp(&other.BadUrl),
discriminant_Error::NetworkError => core::cmp::Ordering::Equal,
discriminant_Error::Timeout => core::cmp::Ordering::Equal,
}
@ -1033,12 +1033,12 @@ impl Clone for Error {
discriminant_Error::BadBody => Self {
BadBody: self.BadBody.clone(),
},
discriminant_Error::BadRequest => Self {
BadRequest: self.BadRequest.clone(),
},
discriminant_Error::BadStatus => Self {
BadStatus: self.BadStatus.clone(),
},
discriminant_Error::BadUrl => Self {
BadUrl: self.BadUrl.clone(),
},
discriminant_Error::NetworkError => {
core::mem::transmute::<core::mem::MaybeUninit<Error>, Error>(
core::mem::MaybeUninit::uninit(),
@ -1071,14 +1071,14 @@ impl core::hash::Hash for Error {
discriminant_Error::BadBody.hash(state);
self.BadBody.hash(state);
},
discriminant_Error::BadRequest => unsafe {
discriminant_Error::BadRequest.hash(state);
self.BadRequest.hash(state);
},
discriminant_Error::BadStatus => unsafe {
discriminant_Error::BadStatus.hash(state);
self.BadStatus.hash(state);
},
discriminant_Error::BadUrl => unsafe {
discriminant_Error::BadUrl.hash(state);
self.BadUrl.hash(state);
},
discriminant_Error::NetworkError => discriminant_Error::NetworkError.hash(state),
discriminant_Error::Timeout => discriminant_Error::Timeout.hash(state),
}
@ -1101,10 +1101,13 @@ impl core::fmt::Debug for Error {
discriminant_Error::BadBody => {
f.debug_tuple("BadBody").field(&*self.BadBody).finish()
}
discriminant_Error::BadRequest => f
.debug_tuple("BadRequest")
.field(&*self.BadRequest)
.finish(),
discriminant_Error::BadStatus => {
f.debug_tuple("BadStatus").field(&self.BadStatus).finish()
}
discriminant_Error::BadUrl => f.debug_tuple("BadUrl").field(&*self.BadUrl).finish(),
discriminant_Error::NetworkError => f.write_str("NetworkError"),
discriminant_Error::Timeout => f.write_str("Timeout"),
}
@ -2163,6 +2166,60 @@ impl Response {
}
}
#[cfg(any(
target_arch = "arm",
target_arch = "aarch64",
target_arch = "wasm32",
target_arch = "x86",
target_arch = "x86_64"
))]
/// Construct a tag named `BadRequest`, with the appropriate payload
pub fn BadRequest(arg: roc_std::RocStr) -> Self {
let mut answer = Self {
BadRequest: core::mem::ManuallyDrop::new(arg),
};
answer.set_discriminant(discriminant_Response::BadRequest);
answer
}
#[cfg(any(
target_arch = "arm",
target_arch = "aarch64",
target_arch = "wasm32",
target_arch = "x86",
target_arch = "x86_64"
))]
/// Unsafely assume the given `Response` has a `.discriminant()` of `BadRequest` and convert it to `BadRequest`'s payload.
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `BadRequest`.
pub unsafe fn into_BadRequest(mut self) -> roc_std::RocStr {
debug_assert_eq!(self.discriminant(), discriminant_Response::BadRequest);
let payload = core::mem::ManuallyDrop::take(&mut self.BadRequest);
payload
}
#[cfg(any(
target_arch = "arm",
target_arch = "aarch64",
target_arch = "wasm32",
target_arch = "x86",
target_arch = "x86_64"
))]
/// Unsafely assume the given `Response` has a `.discriminant()` of `BadRequest` and return its payload.
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `BadRequest`.
pub unsafe fn as_BadRequest(&self) -> &roc_std::RocStr {
debug_assert_eq!(self.discriminant(), discriminant_Response::BadRequest);
let payload = &self.BadRequest;
&payload
}
#[cfg(any(
target_arch = "arm",
target_arch = "aarch64",
@ -2217,60 +2274,6 @@ impl Response {
(&payload.f0, &payload.f1)
}
#[cfg(any(
target_arch = "arm",
target_arch = "aarch64",
target_arch = "wasm32",
target_arch = "x86",
target_arch = "x86_64"
))]
/// Construct a tag named `BadUrl`, with the appropriate payload
pub fn BadUrl(arg: roc_std::RocStr) -> Self {
let mut answer = Self {
BadUrl: core::mem::ManuallyDrop::new(arg),
};
answer.set_discriminant(discriminant_Response::BadUrl);
answer
}
#[cfg(any(
target_arch = "arm",
target_arch = "aarch64",
target_arch = "wasm32",
target_arch = "x86",
target_arch = "x86_64"
))]
/// Unsafely assume the given `Response` has a `.discriminant()` of `BadUrl` and convert it to `BadUrl`'s payload.
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `BadUrl`.
pub unsafe fn into_BadUrl(mut self) -> roc_std::RocStr {
debug_assert_eq!(self.discriminant(), discriminant_Response::BadUrl);
let payload = core::mem::ManuallyDrop::take(&mut self.BadUrl);
payload
}
#[cfg(any(
target_arch = "arm",
target_arch = "aarch64",
target_arch = "wasm32",
target_arch = "x86",
target_arch = "x86_64"
))]
/// Unsafely assume the given `Response` has a `.discriminant()` of `BadUrl` and return its payload.
/// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `BadUrl`.
pub unsafe fn as_BadUrl(&self) -> &roc_std::RocStr {
debug_assert_eq!(self.discriminant(), discriminant_Response::BadUrl);
let payload = &self.BadUrl;
&payload
}
#[cfg(any(
target_arch = "arm",
target_arch = "aarch64",
@ -2449,12 +2452,12 @@ impl Drop for Response {
fn drop(&mut self) {
// Drop the payloads
match self.discriminant() {
discriminant_Response::BadRequest => unsafe {
core::mem::ManuallyDrop::drop(&mut self.BadRequest)
},
discriminant_Response::BadStatus => unsafe {
core::mem::ManuallyDrop::drop(&mut self.BadStatus)
},
discriminant_Response::BadUrl => unsafe {
core::mem::ManuallyDrop::drop(&mut self.BadUrl)
},
discriminant_Response::GoodStatus => unsafe {
core::mem::ManuallyDrop::drop(&mut self.GoodStatus)
},
@ -2481,8 +2484,8 @@ impl PartialEq for Response {
unsafe {
match self.discriminant() {
discriminant_Response::BadRequest => self.BadRequest == other.BadRequest,
discriminant_Response::BadStatus => self.BadStatus == other.BadStatus,
discriminant_Response::BadUrl => self.BadUrl == other.BadUrl,
discriminant_Response::GoodStatus => self.GoodStatus == other.GoodStatus,
discriminant_Response::NetworkError => true,
discriminant_Response::Timeout => true,
@ -2507,8 +2510,8 @@ impl PartialOrd for Response {
unsafe {
match self.discriminant() {
discriminant_Response::BadRequest => self.BadRequest.partial_cmp(&other.BadRequest),
discriminant_Response::BadStatus => self.BadStatus.partial_cmp(&other.BadStatus),
discriminant_Response::BadUrl => self.BadUrl.partial_cmp(&other.BadUrl),
discriminant_Response::GoodStatus => self.GoodStatus.partial_cmp(&other.GoodStatus),
discriminant_Response::NetworkError => Some(core::cmp::Ordering::Equal),
discriminant_Response::Timeout => Some(core::cmp::Ordering::Equal),
@ -2533,8 +2536,8 @@ impl Ord for Response {
unsafe {
match self.discriminant() {
discriminant_Response::BadRequest => self.BadRequest.cmp(&other.BadRequest),
discriminant_Response::BadStatus => self.BadStatus.cmp(&other.BadStatus),
discriminant_Response::BadUrl => self.BadUrl.cmp(&other.BadUrl),
discriminant_Response::GoodStatus => self.GoodStatus.cmp(&other.GoodStatus),
discriminant_Response::NetworkError => core::cmp::Ordering::Equal,
discriminant_Response::Timeout => core::cmp::Ordering::Equal,
@ -2554,12 +2557,12 @@ impl Clone for Response {
fn clone(&self) -> Self {
let mut answer = unsafe {
match self.discriminant() {
discriminant_Response::BadRequest => Self {
BadRequest: self.BadRequest.clone(),
},
discriminant_Response::BadStatus => Self {
BadStatus: self.BadStatus.clone(),
},
discriminant_Response::BadUrl => Self {
BadUrl: self.BadUrl.clone(),
},
discriminant_Response::GoodStatus => Self {
GoodStatus: self.GoodStatus.clone(),
},
@ -2592,14 +2595,14 @@ impl core::hash::Hash for Response {
))]
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
match self.discriminant() {
discriminant_Response::BadRequest => unsafe {
discriminant_Response::BadRequest.hash(state);
self.BadRequest.hash(state);
},
discriminant_Response::BadStatus => unsafe {
discriminant_Response::BadStatus.hash(state);
self.BadStatus.hash(state);
},
discriminant_Response::BadUrl => unsafe {
discriminant_Response::BadUrl.hash(state);
self.BadUrl.hash(state);
},
discriminant_Response::GoodStatus => unsafe {
discriminant_Response::GoodStatus.hash(state);
self.GoodStatus.hash(state);
@ -2623,14 +2626,15 @@ impl core::fmt::Debug for Response {
unsafe {
match self.discriminant() {
discriminant_Response::BadRequest => f
.debug_tuple("BadRequest")
.field(&*self.BadRequest)
.finish(),
discriminant_Response::BadStatus => f
.debug_tuple("BadStatus")
.field(&(&*self.BadStatus).f0)
.field(&(&*self.BadStatus).f1)
.finish(),
discriminant_Response::BadUrl => {
f.debug_tuple("BadUrl").field(&*self.BadUrl).finish()
}
discriminant_Response::GoodStatus => f
.debug_tuple("GoodStatus")
.field(&(&*self.GoodStatus).f0)

View File

@ -137,37 +137,73 @@ pub extern "C" fn roc_fx_sendRequest(roc_request: &glue::Request) -> glue::Respo
builder = builder.timeout(Duration::from_millis(*ms));
}
let url = roc_request.url.as_str();
match reqwest::blocking::get(url) {
Ok(response) => {
let bytes = response.bytes().unwrap_or_default();
let body: RocList<u8> = RocList::from_iter(bytes.into_iter());
let client = match builder.build() {
Ok(c) => c,
Err(_) => {
return glue::Response::NetworkError; // TLS backend cannot be initialized
}
};
let method = match roc_request.method {
glue::Method::Connect => reqwest::Method::CONNECT,
glue::Method::Delete => reqwest::Method::DELETE,
glue::Method::Get => reqwest::Method::GET,
glue::Method::Head => reqwest::Method::HEAD,
glue::Method::Options => reqwest::Method::OPTIONS,
glue::Method::Patch => reqwest::Method::PATCH,
glue::Method::Post => reqwest::Method::POST,
glue::Method::Put => reqwest::Method::PUT,
glue::Method::Trace => reqwest::Method::TRACE,
};
let url = roc_request.url.as_str();
let mut req_builder = client.request(method, url);
for header in roc_request.headers.iter() {
let (key, value) = unsafe { header.as_Header() };
req_builder = req_builder.header(key.as_str(), value.as_str());
}
if roc_request.body.discriminant() == glue::discriminant_Body::Body {
let (mime_type_tag, body_byte_list) = unsafe { roc_request.body.as_Body() };
let mime_type_str: &RocStr = unsafe { mime_type_tag.as_MimeType() };
req_builder = req_builder.header("Content-Type", mime_type_str.as_str());
req_builder = req_builder.body(body_byte_list.as_slice().to_vec());
}
let request = match req_builder.build() {
Ok(req) => req,
Err(err) => {
return glue::Response::BadRequest(RocStr::from(err.to_string().as_str()));
}
};
match client.execute(request) {
Ok(response) => {
let status = response.status();
let status_str = status.canonical_reason().unwrap_or_else(|| status.as_str());
let metadata = Metadata {
headers: RocList::empty(), // TODO
statusText: RocStr::from(status_str),
url: RocStr::from(url),
statusCode: status.as_u16(),
};
glue::Response::GoodStatus(metadata, body)
let bytes = response.bytes().unwrap_or_default();
let body: RocList<u8> = RocList::from_iter(bytes.into_iter());
if status.is_success() {
glue::Response::GoodStatus(metadata, body)
} else {
glue::Response::BadStatus(metadata, body)
}
}
Err(err) => {
if err.is_timeout() {
glue::Response::Timeout
} else if let Some(status) = err.status() {
let body = RocList::empty(); // TODO
let status_str = status.canonical_reason().unwrap_or_else(|| status.as_str());
let metadata = Metadata {
headers: RocList::empty(), // TODO
statusText: RocStr::from(status_str),
url: RocStr::from(url),
statusCode: status.as_u16(),
};
glue::Response::BadStatus(metadata, body)
} else if err.is_request() {
glue::Response::BadUrl(RocStr::from(url))
glue::Response::BadRequest(RocStr::from(err.to_string().as_str()))
} else {
glue::Response::NetworkError
}