use reqwest::{
header::{ACCEPT, AUTHORIZATION, CACHE_CONTROL, CONTENT_TYPE},
Client,
};
use rust_decimal::Decimal;
use rust_decimal_macros::dec;
use serde::{Deserialize, Serialize};
use thiserror::Error;
use url::Url;
#[derive(Clone, Debug)]
pub struct RustPaystack {
api_key: String,
client: Client,
base_url: Url,
}
#[derive(Serialize)]
pub struct InitializeTransactionRequest<'a> {
email: &'a str,
amount: Decimal,
}
#[derive(Deserialize, Debug)]
pub struct InitializeTransactionResponse {
status: bool,
message: String,
data: TransactionData,
}
#[derive(Deserialize, Debug)]
pub struct TransactionData {
authorization_url: String,
access_code: String,
reference: String,
}
#[derive(Deserialize, Debug)]
pub struct VerifyTransactionResponse {
status: bool,
message: String,
data: Option<serde_json::Value>,
}
impl RustPaystack {
pub fn new(api_key: String) -> RustPaystack {
let client = reqwest::Client::new();
let base_url = Url::parse("https://api.paystack.co").unwrap();
return RustPaystack {
api_key: api_key,
client: client,
base_url: base_url,
};
}
pub async fn initialize_transaction(
&self,
email: &str,
amount: Decimal,
) -> Result<InitializeTransactionResponse, RustPaystackError> {
let final_amount = amount * dec!(100.0);
let req_url = self.base_url.join("/transaction/initialize")?;
let postdata = InitializeTransactionRequest {
email: &email,
amount: final_amount,
};
let response = self
.client
.post(req_url)
.header(AUTHORIZATION, format!("Bearer {}", &self.api_key))
.header(ACCEPT, "application/json")
.header(CONTENT_TYPE, "application/json")
.header(CACHE_CONTROL, "no-cache")
.json(&postdata)
.send()
.await?
.json::<InitializeTransactionResponse>()
.await?;
Ok(response)
}
pub async fn verify_payment(
&self,
reference: &str,
) -> Result<VerifyTransactionResponse, RustPaystackError> {
let req_url = self
.base_url
.join(&format!("/transaction/verify/{}", reference))?;
let response = self
.client
.get(req_url.to_string())
.header(AUTHORIZATION, format!("Bearer {}", &self.api_key))
.header(ACCEPT, "application/json")
.header(CONTENT_TYPE, "application/json")
.header(CACHE_CONTROL, "no-cache")
.send()
.await?
.json::<VerifyTransactionResponse>()
.await?;
Ok(response)
}
}
#[derive(Debug, Error)]
pub enum RustPaystackError {
#[error("Request failed: {0}")]
RequestError(#[from] reqwest::Error),
#[error("Invalid URL error: {0}")]
UrlParseError(#[from] url::ParseError),
#[error("Paystack API error: {0}")]
PaystackError(String), }