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
10 changes: 6 additions & 4 deletions wp_api/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#![allow(dead_code, unused_variables)]

use request::{endpoint::ApiEndpoint, RequestMethod, WPNetworkRequest, WPNetworkResponse};
use request::{
endpoint::{ApiEndpoint, ApiEndpointUrl},
RequestMethod, WPNetworkRequest, WPNetworkResponse,
};
use std::collections::HashMap;
use url::Url;

Expand All @@ -23,7 +26,6 @@ const CONTENT_TYPE_JSON: &str = "application/json";
#[derive(Debug, uniffi::Object)]
pub struct WPApiHelper {
api_endpoint: ApiEndpoint,
site_url: Url,
authentication: WPAuthentication,
}

Expand All @@ -45,15 +47,15 @@ impl WPApiHelper {

Self {
api_endpoint,
site_url: url,
authentication,
}
}

// TODO: Remove this because we want to build all requests within the crate
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I agree with this – I'd be happy to have a failable initializer that won't let you make an invalid WPNetworkRequest, but I'd expect that some app developer will have a need to construct their own and use the underlying library plumbing to execute it?

WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are discussing this a bit on Slack. If we decide to remove it, I'll do so as part of another PR.

pub fn raw_request(&self, url: String) -> WPNetworkRequest {
WPNetworkRequest {
method: RequestMethod::GET,
url: Url::parse(url.as_str()).unwrap().into(),
url: ApiEndpointUrl::new(Url::parse(url.as_str()).unwrap()).into(),
header_map: self.header_map(),
body: None,
}
Expand Down
8 changes: 5 additions & 3 deletions wp_api/src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ use url::Url;

use crate::WPApiError;

use self::endpoint::WpEndpointUrl;

pub mod endpoint;

// Has custom `Debug` trait implementation
#[derive(uniffi::Record)]
pub struct WPNetworkRequest {
pub method: RequestMethod,
pub url: String,
pub url: WpEndpointUrl,
// TODO: We probably want to implement a specific type for these headers instead of using a
// regular HashMap.
//
Expand All @@ -33,7 +35,7 @@ impl Debug for WPNetworkRequest {
indoc::indoc! {"
WPNetworkRequest {{
method: '{:?}',
url: '{}',
url: '{:?}',
header_map: '{:?}',
body: '{:?}'
}}
Expand Down Expand Up @@ -137,7 +139,7 @@ impl Debug for WPNetworkResponse {
}
}

#[derive(Debug, uniffi::Enum)]
#[derive(Debug, Clone, uniffi::Enum)]
pub enum RequestMethod {
GET,
POST,
Expand Down
41 changes: 38 additions & 3 deletions wp_api/src/request/endpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,43 @@ mod users_endpoint;

const WP_JSON_PATH_SEGMENTS: [&str; 3] = ["wp-json", "wp", "v2"];

uniffi::custom_newtype!(WpEndpointUrl, String);
#[derive(Debug)]
pub struct WpEndpointUrl(pub String);

#[derive(Debug)]
pub(crate) struct ApiEndpointUrl {
url: Url,
}

impl ApiEndpointUrl {
pub fn new(url: Url) -> Self {
Self { url }
}

fn url(&self) -> &Url {
&self.url
}

pub fn as_str(&self) -> &str {
self.url.as_str()
}
}

impl From<Url> for ApiEndpointUrl {
fn from(url: Url) -> Self {
Self::new(url)
}
}

impl From<ApiEndpointUrl> for WpEndpointUrl {
fn from(url: ApiEndpointUrl) -> Self {
Self(url.as_str().to_string())
}
}

#[derive(Debug, Clone)]
pub struct ApiBaseUrl {
pub(crate) struct ApiBaseUrl {
url: Url,
}

Expand Down Expand Up @@ -49,7 +84,7 @@ impl ApiBaseUrl {
}

#[derive(Debug)]
pub struct ApiEndpoint {
pub(crate) struct ApiEndpoint {
pub base_url: ApiBaseUrl,
pub users: UsersEndpoint,
pub plugins: PluginsEndpoint,
Expand Down Expand Up @@ -167,7 +202,7 @@ mod tests {
ApiBaseUrl::new("https://example.com").unwrap()
}

pub fn validate_endpoint(endpoint_url: Url, path: &str) {
pub fn validate_endpoint(endpoint_url: ApiEndpointUrl, path: &str) {
assert_eq!(
endpoint_url.as_str(),
format!("{}{}", fixture_api_base_url().as_str(), path)
Expand Down
38 changes: 22 additions & 16 deletions wp_api/src/request/endpoint/plugins_endpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ use url::Url;

use crate::{plugins::PluginListParams, PluginSlug, SparsePluginField, WPContext};

use super::{ApiBaseUrl, UrlExtension};
use super::{ApiBaseUrl, ApiEndpointUrl, UrlExtension};

#[derive(Debug)]
pub struct PluginsEndpoint {
pub(crate) struct PluginsEndpoint {
api_base_url: ApiBaseUrl,
}

Expand All @@ -14,51 +14,57 @@ impl PluginsEndpoint {
Self { api_base_url }
}

pub fn create(&self) -> Url {
self.plugins_base_url()
pub fn create(&self) -> ApiEndpointUrl {
self.plugins_base_url().into()
}

pub fn delete(&self, plugin: &PluginSlug) -> Url {
self.plugins_url_with_slug(plugin)
pub fn delete(&self, plugin: &PluginSlug) -> ApiEndpointUrl {
self.plugins_url_with_slug(plugin).into()
}

pub fn list(&self, context: WPContext, params: Option<&PluginListParams>) -> Url {
pub fn list(&self, context: WPContext, params: Option<&PluginListParams>) -> ApiEndpointUrl {
let mut url = self.plugins_base_url();
url.query_pairs_mut()
.append_pair("context", context.as_str());
if let Some(params) = params {
url.query_pairs_mut().extend_pairs(params.query_pairs());
}
url
url.into()
}

pub fn filter_list(
&self,
context: WPContext,
params: Option<&PluginListParams>,
fields: &[SparsePluginField],
) -> Url {
self.list(context, params).append_filter_fields(fields)
) -> ApiEndpointUrl {
self.list(context, params)
.url
.append_filter_fields(fields)
.into()
}

pub fn retrieve(&self, context: WPContext, plugin: &PluginSlug) -> Url {
pub fn retrieve(&self, context: WPContext, plugin: &PluginSlug) -> ApiEndpointUrl {
let mut url = self.plugins_url_with_slug(plugin);
url.query_pairs_mut()
.append_pair("context", context.as_str());
url
url.into()
}

pub fn filter_retrieve(
&self,
context: WPContext,
plugin: &PluginSlug,
fields: &[SparsePluginField],
) -> Url {
self.retrieve(context, plugin).append_filter_fields(fields)
) -> ApiEndpointUrl {
self.retrieve(context, plugin)
.url
.append_filter_fields(fields)
.into()
}

pub fn update(&self, plugin: &PluginSlug) -> Url {
self.plugins_url_with_slug(plugin)
pub fn update(&self, plugin: &PluginSlug) -> ApiEndpointUrl {
self.plugins_url_with_slug(plugin).into()
}

fn plugins_base_url(&self) -> Url {
Expand Down
62 changes: 37 additions & 25 deletions wp_api/src/request/endpoint/users_endpoint.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
use url::Url;

use crate::{SparseUserField, UserDeleteParams, UserId, UserListParams, WPContext};

use super::{ApiBaseUrl, UrlExtension};
use super::{ApiBaseUrl, ApiEndpointUrl, UrlExtension};

#[derive(Debug)]
pub struct UsersEndpoint {
pub(crate) struct UsersEndpoint {
api_base_url: ApiBaseUrl,
}

Expand All @@ -14,79 +12,93 @@ impl UsersEndpoint {
Self { api_base_url }
}

pub fn create(&self) -> Url {
self.api_base_url.by_appending("users")
pub fn create(&self) -> ApiEndpointUrl {
self.api_base_url.by_appending("users").into()
}

pub fn delete(&self, user_id: UserId, params: &UserDeleteParams) -> Url {
pub fn delete(&self, user_id: UserId, params: &UserDeleteParams) -> ApiEndpointUrl {
let mut url = self
.api_base_url
.by_extending(["users", &user_id.to_string()]);
url.query_pairs_mut().extend_pairs(params.query_pairs());
url
url.into()
}

pub fn delete_me(&self, params: &UserDeleteParams) -> Url {
pub fn delete_me(&self, params: &UserDeleteParams) -> ApiEndpointUrl {
let mut url = self.api_base_url.by_extending(["users", "me"]);
url.query_pairs_mut().extend_pairs(params.query_pairs());
url
url.into()
}

pub fn list(&self, context: WPContext, params: Option<&UserListParams>) -> Url {
pub fn list(&self, context: WPContext, params: Option<&UserListParams>) -> ApiEndpointUrl {
let mut url = self.api_base_url.by_appending("users");
url.query_pairs_mut()
.append_pair("context", context.as_str());
if let Some(params) = params {
url.query_pairs_mut().extend_pairs(params.query_pairs());
}
url
url.into()
}

pub fn filter_list(
&self,
context: WPContext,
params: Option<&UserListParams>,
fields: &[SparseUserField],
) -> Url {
self.list(context, params).append_filter_fields(fields)
) -> ApiEndpointUrl {
self.list(context, params)
.url
.append_filter_fields(fields)
.into()
}

pub fn retrieve(&self, user_id: UserId, context: WPContext) -> Url {
pub fn retrieve(&self, user_id: UserId, context: WPContext) -> ApiEndpointUrl {
let mut url = self
.api_base_url
.by_extending(["users", &user_id.to_string()]);
url.query_pairs_mut()
.append_pair("context", context.as_str());
url
url.into()
}

pub fn filter_retrieve(
&self,
user_id: UserId,
context: WPContext,
fields: &[SparseUserField],
) -> Url {
self.retrieve(user_id, context).append_filter_fields(fields)
) -> ApiEndpointUrl {
self.retrieve(user_id, context)
.url
.append_filter_fields(fields)
.into()
}

pub fn retrieve_me(&self, context: WPContext) -> Url {
pub fn retrieve_me(&self, context: WPContext) -> ApiEndpointUrl {
let mut url = self.api_base_url.by_extending(["users", "me"]);
url.query_pairs_mut()
.append_pair("context", context.as_str());
url
url.into()
}

pub fn filter_retrieve_me(&self, context: WPContext, fields: &[SparseUserField]) -> Url {
self.retrieve_me(context).append_filter_fields(fields)
pub fn filter_retrieve_me(
&self,
context: WPContext,
fields: &[SparseUserField],
) -> ApiEndpointUrl {
self.retrieve_me(context)
.url
.append_filter_fields(fields)
.into()
}

pub fn update(&self, user_id: UserId) -> Url {
pub fn update(&self, user_id: UserId) -> ApiEndpointUrl {
self.api_base_url
.by_extending(["users", &user_id.to_string()])
.into()
}

pub fn update_me(&self) -> Url {
self.api_base_url.by_extending(["users", "me"])
pub fn update_me(&self) -> ApiEndpointUrl {
self.api_base_url.by_extending(["users", "me"]).into()
}
}

Expand Down
2 changes: 1 addition & 1 deletion wp_api/tests/integration_test_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ impl AsyncWPNetworking {

let mut request = self
.client
.request(Self::request_method(wp_request.method), wp_request.url)
.request(Self::request_method(wp_request.method), wp_request.url.0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we implement ToString on WpEndpointUrl to avoid the need for the .0?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ToString doesn't work unfortunately. We'd have to implement IntoUrl which is part of reqwest and only available as a dev dependency. We'll likely have a cargo feature to add reqwest at which time we can do this, but until then, I think we can keep this as is.

.headers(request_headers);
if let Some(body) = wp_request.body {
request = request.body(body);
Expand Down
5 changes: 3 additions & 2 deletions wp_api/tests/test_users_err.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use integration_test_common::SECOND_USER_EMAIL;
use wp_api::{
request::endpoint::WpEndpointUrl,
users::{
UserCreateParams, UserDeleteParams, UserId, UserListParams, UserUpdateParams,
WPApiParamUsersOrderBy, WPApiParamUsersWho,
Expand Down Expand Up @@ -317,7 +318,7 @@ async fn update_user_err_user_invalid_slug() {
#[tokio::test]
async fn create_user_err_user_exists() {
let mut request = api().create_user_request(&valid_user_create_params());
request.url.push_str("?id=1");
request.url.0.push_str("?id=1");
request
.execute()
.await
Expand All @@ -334,7 +335,7 @@ async fn delete_user_err_trash_not_supported() {
reassign: SECOND_USER_ID,
},
);
request.url = request.url.replace("&force=true", "");
request.url = WpEndpointUrl(request.url.0.replace("&force=true", ""));
request
.execute()
.await
Expand Down