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
29 changes: 6 additions & 23 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Rust
on:
push:
branches: [ "main", "master" ]
branches: ["main", "master"]
env:
CARGO_TERM_COLOR: always
PAYSTACK_API_KEY: ${{secrets.PAYSTACK_API_KEY}}
Expand All @@ -12,25 +12,8 @@ jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build
run: cargo build --verbose
- name: Run tests
run: cargo test --verbose
coverage:
runs-on: ubuntu-latest
env:
CARGO_TERM_COLOR: always
steps:
- uses: actions/checkout@v4
- name: Install Rust
run: rustup update stable
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@cargo-llvm-cov
- name: Generate code coverage
run: cargo llvm-cov --all-features --workspace --lcov --output-path lcov.info
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
files: lcov.info
fail_ci_if_error: true
- uses: actions/checkout@v3
- name: Build
run: cargo build --verbose
- name: Run tests
run: cargo test --verbose
43 changes: 36 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
[![paystack-rs on docs.rs](https://docs.rs/paystack-rs/badge.svg)](https://docs.rs/paystack-rs)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

>*NB: a core rewrite of the project is being carried out, the goal is to make the crate easier to maintain,
improve the performance, abstract certain features to improve flexibility, and support for both blocking and non-blocking
operations.*
> _NB: a core rewrite of the project is being carried out, the goal is to make the crate easier to maintain,
> improve the performance, abstract certain features to improve flexibility, and support for both blocking and non-blocking
> operations._

Convenient Rust bindings and types for the [Paystack](https://paystack.com) HTTP API aiming to support the entire API surface. Not the case? Please open an issue. I update the definitions on a weekly basis.

Expand Down Expand Up @@ -68,7 +68,7 @@ async fn main() -> Result<(), PaystackAPIError> {
let api_key = env::var("PAYSTACK_API_KEY").unwrap();
let client = PaystackClient<ReqwestClient>::new(api_key);


let email = "email@example.com".to_string();
let amount ="10_000".to_string();
let body = TransactionRequestBuilder::default()
Expand All @@ -94,8 +94,8 @@ async fn main() -> Result<(), PaystackAPIError> {
```

### Examples
We provide some examples of use cases for the Paystack-rs crate. The examples are located in the [examples](examples) folder.

We provide some examples of use cases for the Paystack-rs crate. The examples are located in the [examples](examples) folder.

## Contributing

Expand All @@ -105,12 +105,41 @@ We use Github actions to conduct CI/CD for the crate. It ensure that code is for
as proper linting using `cargo clippy`, and finally run all the integration and unit test using `cargo test`.

### Crate module schematic diagram

A conceptual overview of the crate is illustrated below. This is to help improve the understanding of how the different
parts of the crate interact with each other to work efficiently. The `PaystackClient` module is the central module of
the crate and the best entry point to explore the different parts of the crate.

![Crate Schematic](docs/images/paystack-rs.png)

```mermaid
---
config:
layout: dagre
theme: default
---
flowchart TD
subgraph subGraph0["HTTP Layer"]
HTTPClient["&lt;Trait&gt; HTTPClient"]
ReqwestClient["ReqwestClient"]
OtherClients["OtherClients"]
end
subgraph Core["Core"]
Models["Models"]
APIEndpoints["APIEndpoints"]
Macros["Macros"]
end
subgraph Types["Types"]
Response["Response"]
Request["Request"]
Error["Error"]
end
ReqwestClient --> HTTPClient
OtherClients --> HTTPClient
HTTPClient --> PaystackClient["PaystackClient"]
PaystackClient --> APIEndpoints
APIEndpoints --> Models
Macros --> Models & APIEndpoints
Models --> Response & Request & Error
```

## License

Expand Down
Binary file removed docs/images/paystack-rs.png
Binary file not shown.
72 changes: 0 additions & 72 deletions docs/uml/paystack-rs.drawio

This file was deleted.

8 changes: 7 additions & 1 deletion src/client.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
//! Client
//! =========
//! This file contains the Paystack API client, and it associated endpoints.
use crate::{HttpClient, SubaccountEndpoints, TransactionEndpoints, TransactionSplitEndpoints};
use crate::{
HttpClient, SubaccountEndpoints, TerminalEndpoints, TransactionEndpoints,
TransactionSplitEndpoints,
};
use std::sync::Arc;

/// This is the entry level struct for the paystack API.
Expand All @@ -13,6 +16,8 @@ pub struct PaystackClient<T: HttpClient + Default> {
pub transaction_split: TransactionSplitEndpoints<T>,
/// Subaccount API route
pub subaccount: SubaccountEndpoints<T>,
/// Terminal API route
pub terminal: TerminalEndpoints<T>,
}

impl<T: HttpClient + Default> PaystackClient<T> {
Expand All @@ -23,6 +28,7 @@ impl<T: HttpClient + Default> PaystackClient<T> {
transaction: TransactionEndpoints::new(api_key.clone(), Arc::clone(&http)),
transaction_split: TransactionSplitEndpoints::new(api_key.clone(), Arc::clone(&http)),
subaccount: SubaccountEndpoints::new(api_key.clone(), Arc::clone(&http)),
terminal: TerminalEndpoints::new(api_key.clone(), Arc::clone(&http)),
}
}
}
2 changes: 2 additions & 0 deletions src/endpoints/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
pub mod subaccount;
pub mod terminal;
pub mod transaction;
pub mod transaction_split;

// public re-export
pub use subaccount::*;
pub use terminal::*;
pub use transaction::*;
pub use transaction_split::*;
2 changes: 1 addition & 1 deletion src/endpoints/subaccount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub struct SubaccountEndpoints<T: HttpClient + Default> {
}

impl<T: HttpClient + Default> SubaccountEndpoints<T> {
/// Constructor for the Subaccount object
/// Constructor
pub fn new(key: String, http: Arc<T>) -> SubaccountEndpoints<T> {
let base_url = String::from("https://api.paystack.co/subaccount");
SubaccountEndpoints {
Expand Down
40 changes: 40 additions & 0 deletions src/endpoints/terminal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//! Terminal
//! ========
//! The Terminal API allows you to build delightful in-person payment experiences.

use std::sync::Arc;

use crate::{EventRequest, HttpClient, PaystackResult, SendEventResponseData};

/// A struct to hold all the functions of the terminal API endpoint
#[derive(Debug, Clone)]
pub struct TerminalEndpoints<T: HttpClient + Default> {
key: String,
base_url: String,
http: Arc<T>,
}

impl<T: HttpClient + Default> TerminalEndpoints<T> {
/// Constructor
pub fn new(key: String, http: Arc<T>) -> TerminalEndpoints<T> {
let base_url = String::from("https://api.paystack.co/terminal");
TerminalEndpoints {
key,
base_url,
http,
}
}

/// Send an event from your application to the Paystack Terminal
///
/// Takes in the following:
/// - `terminal_id`: The ID of the Terminal the event should be sent to.
/// - `EventRequest`: A struct containing the information of the event to send to the terminal. It is created with the `EventRequestBuilder`.
pub fn send_event(
&self,
terminal_id: String,
event_request: EventRequest,
) -> PaystackResult<SendEventResponseData> {
todo!()
}
}
2 changes: 1 addition & 1 deletion src/endpoints/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub struct TransactionEndpoints<T: HttpClient + Default> {
}

impl<T: HttpClient + Default> TransactionEndpoints<T> {
/// Constructor for the transaction object
/// Constructor
pub fn new(key: String, http: Arc<T>) -> TransactionEndpoints<T> {
let base_url = String::from("https://api.paystack.co/transaction");
TransactionEndpoints {
Expand Down
2 changes: 1 addition & 1 deletion src/endpoints/transaction_split.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub struct TransactionSplitEndpoints<T: HttpClient + Default> {
}

impl<T: HttpClient + Default> TransactionSplitEndpoints<T> {
/// Constructor for the transaction object
/// Constructor
pub fn new(key: String, http: Arc<T>) -> TransactionSplitEndpoints<T> {
let base_url = String::from("https://api.paystack.co/split");
TransactionSplitEndpoints {
Expand Down
1 change: 0 additions & 1 deletion src/http/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ pub type Query<'a> = Vec<(&'a str, &'a str)>;
/// with their preferred HTTP client.
/// To be as generic as possible, the U generic stands for the HTTP response.
/// Ideally, it should be bounded to specific traits common in all response.
/// TODO: Bound the U generic to the appropriate traits.

#[async_trait]
pub trait HttpClient: Debug + Default + Clone + Send {
Expand Down
2 changes: 2 additions & 0 deletions src/models/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub mod response;
pub mod split;
pub mod status;
pub mod subaccount_model;
pub mod terminal_model;
pub mod transaction_model;
pub mod transaction_split_model;

Expand All @@ -20,5 +21,6 @@ pub use response::*;
pub use split::*;
pub use status::*;
pub use subaccount_model::*;
pub use terminal_model::*;
pub use transaction_model::*;
pub use transaction_split_model::*;
74 changes: 74 additions & 0 deletions src/models/terminal_model.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
//! Terminal
//! ==========
//! This file contains the models and options for the Terminal endpoint of the Paystack

use derive_builder::Builder;
use serde::{Deserialize, Serialize};
use std::fmt;

/// The request body to send an event from your application to the Paystack Terminal
#[derive(Debug, Clone, Builder, Serialize, Deserialize)]
pub struct EventRequest {
#[serde(rename = "type")]
pub event_type: EventType,
pub action: TerminalAction,
pub data: EventRequestData,
}

/// The paramters needed to perform the specified action.
///
/// For the invoice type, you need to pass the invoice id and offline reference: {id: invoice_id, reference: offline_reference}.
///
/// For the transaction type, you can pass the transaction id: {id: transaction_id}, reference field can be `None`
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct EventRequestData {
pub id: String,
pub reference: Option<String>,
}

/// The type of event to push.
/// Paystack currently support `invoice` and `transaction`
#[derive(Debug, Serialize, Deserialize, Clone)]
pub enum EventType {
Invoice,
Transaction,
}

/// The action the Terminal needs to perform.
///
/// - For the `Invoice` type, the action can either be `Process` or `View`.
///
/// - For the `Transaction` type, the action can either be `Process` or `Print`.
#[derive(Debug, Serialize, Deserialize, Clone)]
pub enum TerminalAction {
Process,
View,
Print,
}

impl fmt::Display for TerminalAction {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let action = match self {
TerminalAction::Process => "process",
TerminalAction::Print => "print",
TerminalAction::View => "view",
};
write!(f, "{}", action)
}
}

impl fmt::Display for EventType {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let event = match self {
EventType::Invoice => "invoice",
EventType::Transaction => "transaction",
};
write!(f, "{}", event)
}
}

/// Contains response data for the send event route in the terminal endpoint.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct SendEventResponseData {
pub id: String,
}
Loading