diff --git a/native/swift/Sources/wordpress-api/Login/API+Login.swift b/native/swift/Sources/wordpress-api/Login/API+Login.swift index b09a3ce20..cded264e3 100644 --- a/native/swift/Sources/wordpress-api/Login/API+Login.swift +++ b/native/swift/Sources/wordpress-api/Login/API+Login.swift @@ -18,6 +18,6 @@ public extension WordPressAPI { func getRestAPICapabilities(forApiRoot url: URL, using session: URLSession) async throws -> WpApiDetails { let wpResponse = try await self.perform(request: WpNetworkRequest(method: .get, url: url, headerMap: [:])) - return try wpResponse.parseApiDetailsResponse() + return try parseApiDetailsResponse(response: wpResponse) } } diff --git a/wp_api/src/lib.rs b/wp_api/src/lib.rs index 7e2806e81..78bdb1dd5 100644 --- a/wp_api/src/lib.rs +++ b/wp_api/src/lib.rs @@ -178,6 +178,17 @@ impl WpApiParamOrder { } } +#[uniffi::export] +pub fn parse_api_details_response(response: WpNetworkResponse) -> Result { + let api_details = + serde_json::from_slice(&response.body).map_err(|err| WpApiError::ParsingError { + reason: err.to_string(), + response: response.body_as_string(), + })?; + + Ok(api_details) +} + #[uniffi::export] pub fn get_link_header(response: &WpNetworkResponse, name: &str) -> Option { if let Some(url) = response.get_link_header(name) { diff --git a/wp_api/src/request.rs b/wp_api/src/request.rs index 1b20d2f51..f99518c7d 100644 --- a/wp_api/src/request.rs +++ b/wp_api/src/request.rs @@ -1,10 +1,8 @@ use std::{collections::HashMap, fmt::Debug}; -use http::HeaderMap; use serde::Deserialize; use url::Url; -use crate::login::WpApiDetails; use crate::WpApiError; use self::endpoint::WpEndpointUrl; @@ -57,45 +55,23 @@ impl Debug for WpNetworkRequest { } // Has custom `Debug` trait implementation -#[derive(uniffi::Object)] +#[derive(uniffi::Record)] pub struct WpNetworkResponse { - body: Vec, - status_code: u16, - header_map: HeaderMap, -} - -#[uniffi::export] -impl WpNetworkResponse { - #[uniffi::constructor] - pub fn new( - body: Vec, - status_code: u16, - header_map: Option>, - ) -> Self { - let header_map: HeaderMap = header_map - .and_then(|m| (&m).try_into().ok()) - .unwrap_or_default(); - - Self { - body, - status_code, - header_map, - } - } - - pub fn parse_api_details_response(&self) -> Result { - serde_json::from_slice(&self.body).map_err(|err| WpApiError::ParsingError { - reason: err.to_string(), - response: self.body_as_string(), - }) - } + pub body: Vec, + pub status_code: u16, + // TODO: We probably want to implement a specific type for these headers instead of using a + // regular HashMap. + // + // It could be something similar to `reqwest`'s [`header`](https://docs.rs/reqwest/latest/reqwest/header/index.html) + // module. + pub header_map: Option>, } impl WpNetworkResponse { pub fn get_link_header(&self, name: &str) -> Option { self.header_map - .get(LINK_HEADER_KEY) - .and_then(|v| v.to_str().ok()) + .as_ref() + .map(|h_map| h_map.get(LINK_HEADER_KEY))? .and_then(|link_header| parse_link_header::parse_with_rel(link_header).ok()) .and_then(|link_map| { link_map @@ -211,11 +187,11 @@ mod tests { #[case] expected_prev_link_header: Option<&str>, #[case] expected_next_link_header: Option<&str>, ) { - let response = WpNetworkResponse::new( - Vec::with_capacity(0), - 200, - Some([("Link".to_string(), link.to_string())].into()), - ); + let response = WpNetworkResponse { + body: Vec::with_capacity(0), + status_code: 200, + header_map: Some([("Link".to_string(), link.to_string())].into()), + }; assert_eq!( expected_prev_link_header.and_then(|s| Url::parse(s).ok()), @@ -226,49 +202,4 @@ mod tests { response.get_link_header("next") ); } - - #[test] - fn test_headers_case_insentive() { - let headers: HashMap = [ - ("server".to_string(), "nginx".to_string()), - ("x-nananana".to_string(), "Batcache-Hit".to_string()), - ( - "date".to_string(), - "Thu, 30 May 2024 23:52:17 GMT".to_string(), - ), - ( - "content-type".to_string(), - "text/html; charset=UTF-8".to_string(), - ), - ( - "strict-transport-security".to_string(), - "max-age=31536000".to_string(), - ), - ("vary".to_string(), "Accept-Encoding".to_string()), - ( - "Link".to_string(), - "; rel=\"next\"".to_string(), - ), - ] - .into(); - let response = WpNetworkResponse::new(Vec::with_capacity(0), 200, Some(headers)); - - assert_eq!(response.header_map.get("Server").unwrap(), "nginx"); - assert_eq!( - response.header_map.get("X-Nananana").unwrap(), - "Batcache-Hit" - ); - assert_eq!( - response.header_map.get("Date").unwrap(), - "Thu, 30 May 2024 23:52:17 GMT" - ); - assert_eq!( - response.header_map.get("Content-Type").unwrap(), - "text/html; charset=UTF-8" - ); - assert_eq!( - response.header_map.get("link").unwrap(), - "; rel=\"next\"" - ); - } } diff --git a/wp_api/tests/integration_test_common.rs b/wp_api/tests/integration_test_common.rs index 3773d06b6..12d80b5f8 100644 --- a/wp_api/tests/integration_test_common.rs +++ b/wp_api/tests/integration_test_common.rs @@ -194,12 +194,12 @@ impl AsyncWpNetworking { request = request.body(body); } let response = request.send().await?; - let status_code = response.status().as_u16(); - Ok(WpNetworkResponse::new( - response.bytes().await.unwrap().to_vec(), - status_code, - None, // TODO: Properly read the headers - )) + + Ok(WpNetworkResponse { + status_code: response.status().as_u16(), + body: response.bytes().await.unwrap().to_vec(), + header_map: None, // TODO: Properly read the headers + }) } fn request_method(method: RequestMethod) -> http::Method {