diff --git a/src/api/invoice.rs b/src/api/invoice.rs
index 61e0616..87fa668 100644
--- a/src/api/invoice.rs
+++ b/src/api/invoice.rs
@@ -4,7 +4,7 @@
//! Customers with a PayPal account can log in and pay the invoice with PayPal. Alternatively,
//! customers can pay as a guest with a debit card or credit card. For more information, see the Invoicing Overview and the Invoicing Integration Guide.
//!
-//! Reference: https://developer.paypal.com/docs/api/invoicing/v2/
+//! Reference:
use std::borrow::Cow;
@@ -53,8 +53,8 @@ impl Endpoint for GenerateInvoiceNumber {
reqwest::Method::POST
}
- fn body(&self) -> Option<&Self::Body> {
- Some(&self.invoice_number)
+ fn body(&self) -> Option {
+ Some(self.invoice_number.clone())
}
}
@@ -88,8 +88,8 @@ impl Endpoint for CreateDraftInvoice {
reqwest::Method::POST
}
- fn body(&self) -> Option<&Self::Body> {
- Some(&self.invoice)
+ fn body(&self) -> Option {
+ Some(self.invoice.clone())
}
}
@@ -153,8 +153,8 @@ impl Endpoint for ListInvoices {
reqwest::Method::GET
}
- fn query(&self) -> Option<&Self::Query> {
- Some(&self.query)
+ fn query(&self) -> Option {
+ Some(self.query.clone())
}
}
@@ -234,12 +234,12 @@ impl Endpoint for UpdateInvoice {
reqwest::Method::PUT
}
- fn body(&self) -> Option<&Self::Body> {
- Some(&self.invoice)
+ fn body(&self) -> Option {
+ Some(self.invoice.clone())
}
- fn query(&self) -> Option<&Self::Query> {
- Some(&self.query)
+ fn query(&self) -> Option {
+ Some(self.query.clone())
}
}
@@ -274,8 +274,8 @@ impl Endpoint for CancelInvoice {
reqwest::Method::POST
}
- fn body(&self) -> Option<&Self::Body> {
- Some(&self.reason)
+ fn body(&self) -> Option {
+ Some(self.reason.clone())
}
}
@@ -383,7 +383,7 @@ mod tests {
let invoice = CreateDraftInvoice::new(payload);
- let res = client.execute(&invoice).await?;
+ let _res = client.execute(&invoice).await?;
Ok(())
}
}
diff --git a/src/api/mod.rs b/src/api/mod.rs
index dff5ee0..54be66e 100644
--- a/src/api/mod.rs
+++ b/src/api/mod.rs
@@ -2,4 +2,4 @@
pub mod invoice;
pub mod orders;
-pub mod payments;
+pub mod payments;
\ No newline at end of file
diff --git a/src/api/orders.rs b/src/api/orders.rs
index 63f8b0d..7793d0d 100644
--- a/src/api/orders.rs
+++ b/src/api/orders.rs
@@ -1,6 +1,6 @@
//! An order represents a payment between two or more parties. Use the Orders API to create, update, retrieve, authorize, and capture orders.
//!
-//! https://developer.paypal.com/docs/api/orders/v2/
+//!
use std::borrow::Cow;
@@ -41,8 +41,8 @@ impl Endpoint for CreateOrder {
reqwest::Method::POST
}
- fn body(&self) -> Option<&Self::Body> {
- Some(&self.order)
+ fn body(&self) -> Option {
+ Some(self.order.clone())
}
}
@@ -97,10 +97,11 @@ pub struct PaymentSource {
}
/// The capture order endpoint body.
-#[derive(Debug, Serialize, Clone)]
+#[derive(Debug, Serialize, Clone, Default)]
pub struct PaymentSourceBody {
/// The payment source definition.
- pub payment_source: PaymentSource,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub payment_source: Option,
}
/// Captures payment for an order. To successfully capture payment for an order,
@@ -111,7 +112,7 @@ pub struct CaptureOrder {
/// The id of the order.
pub order_id: String,
/// The endpoint body.
- pub body: Option,
+ pub body: PaymentSourceBody,
}
impl CaptureOrder {
@@ -119,7 +120,7 @@ impl CaptureOrder {
pub fn new(order_id: &str) -> Self {
Self {
order_id: order_id.to_string(),
- body: None,
+ body: PaymentSourceBody::default(),
}
}
}
@@ -139,8 +140,8 @@ impl Endpoint for CaptureOrder {
reqwest::Method::POST
}
- fn body(&self) -> Option<&Self::Body> {
- self.body.as_ref()
+ fn body(&self) -> Option {
+ Some(self.body.clone())
}
}
@@ -152,7 +153,7 @@ pub struct AuthorizeOrder {
/// The order id.
order_id: String,
/// The endpoint body.
- pub body: Option,
+ pub body: PaymentSourceBody,
}
impl AuthorizeOrder {
@@ -160,7 +161,7 @@ impl AuthorizeOrder {
pub fn new(order_id: &str) -> Self {
Self {
order_id: order_id.to_string(),
- body: None,
+ body: PaymentSourceBody::default(),
}
}
}
@@ -180,8 +181,8 @@ impl Endpoint for AuthorizeOrder {
reqwest::Method::POST
}
- fn body(&self) -> Option<&Self::Body> {
- self.body.as_ref()
+ fn body(&self) -> Option {
+ Some(self.body.clone())
}
}
@@ -194,7 +195,7 @@ mod tests {
#[tokio::test]
async fn test_order() -> anyhow::Result<()> {
let mut client = create_client().await;
- client.get_access_token().await?;
+ client.get_access_token().await.expect("get access token error");
let order = OrderPayloadBuilder::default()
.intent(Intent::Authorize)
@@ -219,7 +220,11 @@ mod tests {
..Default::default()
},
)
- .await?;
+ .await;
+
+ assert!(order_created.is_ok());
+
+ let order_created = order_created?;
assert_ne!(order_created.id, "");
assert_eq!(order_created.status, OrderStatus::Created);
@@ -235,14 +240,19 @@ mod tests {
..Default::default()
},
)
- .await?;
+ .await;
+
+ assert!(show_order_result.is_ok());
+
+ let show_order_result = show_order_result?;
assert_eq!(order_created.id, show_order_result.id);
assert_eq!(order_created.status, show_order_result.status);
- let capture_order = CaptureOrder::new(&show_order_result.id);
+ let authorize_order = AuthorizeOrder::new(&show_order_result.id);
- let _res = client.execute(&capture_order).await?;
+ let res = client.execute(&authorize_order).await;
+ assert!(res.is_err()); // Fails with ORDER_NOT_APPROVED
Ok(())
}
diff --git a/src/api/payments.rs b/src/api/payments.rs
index 55d070e..8e1b05b 100644
--- a/src/api/payments.rs
+++ b/src/api/payments.rs
@@ -1,6 +1,6 @@
//! Call the Payments API to authorize payments, capture authorized payments, refund payments that have already been captured, and show payment information.
//!
-//! Reference: https://developer.paypal.com/docs/api/payments/v2/
+//! Reference:
use std::borrow::Cow;
@@ -42,8 +42,4 @@ impl Endpoint for GetAuthorizedPayment {
fn method(&self) -> reqwest::Method {
reqwest::Method::GET
}
-
- fn body(&self) -> Option<&Self::Body> {
- None
- }
}
diff --git a/src/client.rs b/src/client.rs
index 8f32d78..b864132 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -13,7 +13,7 @@ use crate::{
/// Represents the access token returned by the OAuth2 authentication.
///
-/// https://developer.paypal.com/docs/api/get-an-access-token-postman/
+///
#[derive(Debug, Deserialize)]
pub struct AccessToken {
/// The OAuth2 scopes.
@@ -196,7 +196,7 @@ impl Client {
let mut url = endpoint.full_path(self.sandbox);
if let Some(query) = endpoint.query() {
- let query_string = serde_qs::to_string(query).expect("serialize the query correctly");
+ let query_string = serde_qs::to_string(&query).expect("serialize the query correctly");
url.push_str(&query_string);
}
@@ -204,7 +204,7 @@ impl Client {
request = self.setup_headers(request, headers).await?;
if let Some(body) = endpoint.body() {
- request = request.json(body);
+ request = request.json(&body);
}
let res = request.send().await?;
@@ -225,7 +225,7 @@ impl Client {
/// Executes the given endpoints with the default headers.
///
- /// You must remember to call `get_access_token` first or this may fail due to not being authed.
+ /// You must remember to call [Client::get_access_token] first or this may fail due to not being authed.
pub async fn execute(&self, endpoint: &E) -> Result
where
E: Endpoint,
diff --git a/src/countries.rs b/src/countries.rs
index 8629d34..0d243ee 100644
--- a/src/countries.rs
+++ b/src/countries.rs
@@ -1,4 +1,4 @@
-//! Generated using https://github.com/edg-l/payhelper
+//! Generated using
use crate::errors::InvalidCountryError;
use serde::{Deserialize, Serialize};
diff --git a/src/data/common.rs b/src/data/common.rs
index a1e33c7..73848bf 100644
--- a/src/data/common.rs
+++ b/src/data/common.rs
@@ -8,7 +8,7 @@ use std::str::FromStr;
/// The phone type.
///
-/// https://developer.paypal.com/docs/api/orders/v2/#definition-phone_with_type
+///
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Copy, Clone)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
#[allow(missing_docs)]
diff --git a/src/data/invoice.rs b/src/data/invoice.rs
index 675bee2..f0839e0 100644
--- a/src/data/invoice.rs
+++ b/src/data/invoice.rs
@@ -569,7 +569,7 @@ pub struct InvoicePayload {
pub refunds: Option,
}
-/// Definition: https://developer.paypal.com/docs/api/invoicing/v2/#invoices_get
+/// Definition:
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Builder)]
#[builder(setter(strip_option, into))]
diff --git a/src/data/orders.rs b/src/data/orders.rs
index 30350f4..5c97cf2 100644
--- a/src/data/orders.rs
+++ b/src/data/orders.rs
@@ -27,7 +27,7 @@ impl Default for Intent {
/// Represents a payer name.
///
-/// https://developer.paypal.com/docs/api/orders/v2/#definition-payer.name
+///
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)]
pub struct PayerName {
/// When the party is a person, the party's given, or first, name.
@@ -80,7 +80,7 @@ pub struct TaxInfo {
/// The customer who approves and pays for the order. The customer is also known as the payer.
///
-/// https://developer.paypal.com/docs/api/orders/v2/#definition-payer
+///
#[skip_serializing_none]
#[derive(Debug, Default, Serialize, Deserialize, Clone, Builder)]
pub struct Payer {
@@ -428,7 +428,7 @@ pub struct PurchaseUnit {
pub id: Option,
/// The soft descriptor is the dynamic text used to construct the statement descriptor that appears on a payer's card statement.
///
- /// More info here: https://developer.paypal.com/docs/api/orders/v2/#definition-purchase_unit_request
+ /// More info here:
pub soft_descriptor: Option,
/// An array of items that the customer purchases from the merchant.
pub items: Option>,
diff --git a/src/endpoint.rs b/src/endpoint.rs
index c6b8f1c..2684598 100644
--- a/src/endpoint.rs
+++ b/src/endpoint.rs
@@ -20,12 +20,12 @@ pub trait Endpoint {
fn method(&self) -> reqwest::Method;
/// The query to be used when calling this endpoint.
- fn query(&self) -> Option<&Self::Query> {
+ fn query(&self) -> Option {
None
}
/// The body to be used when calling this endpoint.
- fn body(&self) -> Option<&Self::Body> {
+ fn body(&self) -> Option {
None
}
@@ -33,10 +33,14 @@ pub trait Endpoint {
///
/// Automatically implemented.
fn full_path(&self, is_sandbox: bool) -> String {
+ let relative_path = self.relative_path();
+
+ assert!(relative_path.starts_with('/'), "relative path must start with '/'");
+
if is_sandbox {
- format!("{}{}", SANDBOX_ENDPOINT, self.relative_path())
+ format!("{}{}", SANDBOX_ENDPOINT, relative_path)
} else {
- format!("{}{}", LIVE_ENDPOINT, self.relative_path())
+ format!("{}{}", LIVE_ENDPOINT, relative_path)
}
}
}
diff --git a/src/lib.rs b/src/lib.rs
index c363cfa..d30b9a6 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -6,6 +6,8 @@
//! [![Docs](https://docs.rs/paypal-rs/badge.svg)](https://docs.rs/paypal-rs)
//!
//! A rust library that wraps the [paypal api](https://developer.paypal.com/docs/api) asynchronously in a strongly typed manner.
+//!
+//! If there is a missing endpoint that you need, you may try to implement the [Endpoint](endpoint::Endpoint) and pass it to [Client::execute](client::Client::execute)
//!
//! Currently in early development.
//!
@@ -91,7 +93,7 @@ pub const LIVE_ENDPOINT: &str = "https://api-m.paypal.com";
pub const SANDBOX_ENDPOINT: &str = "https://api-m.sandbox.paypal.com";
/// Represents the query used in most GET api requests.
///
-/// Reference: https://developer.paypal.com/docs/api/reference/api-requests/#query-parameters
+/// Reference:
///
/// Note: You can avoid most fields by the Default impl like so:
/// ```
@@ -130,7 +132,7 @@ pub struct Query {
/// Represents the optional header values used on paypal requests.
///
-/// https://developer.paypal.com/docs/api/reference/api-requests/#paypal-auth-assertion
+///
#[derive(Debug, Default, Builder, Clone)]
pub struct HeaderParams {
/// The merchant payer id used on PayPal-Auth-Assertion