Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion native/swift/Sources/wordpress-api/Login/API+Login.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
11 changes: 11 additions & 0 deletions wp_api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,17 @@ impl WpApiParamOrder {
}
}

#[uniffi::export]
pub fn parse_api_details_response(response: WpNetworkResponse) -> Result<WpApiDetails, WpApiError> {
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<WpRestApiUrl> {
if let Some(url) = response.get_link_header(name) {
Expand Down
101 changes: 16 additions & 85 deletions wp_api/src/request.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -57,45 +55,23 @@ impl Debug for WpNetworkRequest {
}

// Has custom `Debug` trait implementation
#[derive(uniffi::Object)]
#[derive(uniffi::Record)]
pub struct WpNetworkResponse {
body: Vec<u8>,
status_code: u16,
header_map: HeaderMap,
}

#[uniffi::export]
impl WpNetworkResponse {
#[uniffi::constructor]
pub fn new(
body: Vec<u8>,
status_code: u16,
header_map: Option<HashMap<String, String>>,
) -> 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<WpApiDetails, WpApiError> {
serde_json::from_slice(&self.body).map_err(|err| WpApiError::ParsingError {
reason: err.to_string(),
response: self.body_as_string(),
})
}
pub body: Vec<u8>,
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<HashMap<String, String>>,
}

impl WpNetworkResponse {
pub fn get_link_header(&self, name: &str) -> Option<Url> {
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
Expand Down Expand Up @@ -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()),
Expand All @@ -226,49 +202,4 @@ mod tests {
response.get_link_header("next")
);
}

#[test]
fn test_headers_case_insentive() {
let headers: HashMap<String, String> = [
("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(),
"<http://localhost/wp-json/wp/v2/posts?page=2>; 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(),
"<http://localhost/wp-json/wp/v2/posts?page=2>; rel=\"next\""
);
}
}
12 changes: 6 additions & 6 deletions wp_api/tests/integration_test_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down