initial commit

This commit is contained in:
Edgar 2020-06-08 22:30:45 +02:00
parent 62c582ab72
commit 620e449f18
No known key found for this signature in database
GPG Key ID: 8731E6C0166EAA85
6 changed files with 140 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/target
Cargo.lock
.env

17
Cargo.toml Normal file
View File

@ -0,0 +1,17 @@
[package]
name = "paypal-rs"
version = "0.0.1"
authors = ["Edgar <git@edgarluque.com>"]
description = "A library that wraps the paypal api asynchronously."
keywords = ["paypal", "api", "async"]
categories = ["api-bindings", "asynchronous"]
readme = "README.md"
edition = "2018"
[dependencies]
reqwest = { version = "0.10", features = ["json"] }
tokio = { version = "0.2", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
log = "0.4"
dotenv = "0.15.0"

5
README.md Normal file
View File

@ -0,0 +1,5 @@
# paypal-rs
A rust library that wraps the [paypal api](https://developer.paypal.com/docs/api) asynchronously.
Currently in early development.

13
src/errors.rs Normal file
View File

@ -0,0 +1,13 @@
use std::fmt;
use std::error::Error;
#[derive(Debug, Clone)]
pub struct GetAccessTokenError;
impl fmt::Display for GetAccessTokenError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "error getting access token")
}
}
impl Error for GetAccessTokenError {}

83
src/lib.rs Normal file
View File

@ -0,0 +1,83 @@
#[cfg(test)]
mod tests;
pub mod errors;
use serde::Deserialize;
use std::time::{Duration, Instant};
pub const LIVE_ENDPOINT: &str = "https://api.paypal.com";
pub const SANDBOX_ENDPOINT: &str = "https://api.sandbox.paypal.com";
#[derive(Debug, Deserialize)]
pub struct AccessToken {
pub scope: String,
pub access_token: String,
pub token_type: String,
pub app_id: String,
pub expires_in: u64,
pub nonce: String,
}
#[derive(Debug)]
pub struct Auth<'a> {
pub client_id: &'a str,
pub secret: &'a str,
pub access_token: Option<AccessToken>,
pub expires: Option<Instant>,
}
#[derive(Debug)]
pub struct Client<'a> {
pub client: reqwest::Client,
pub sandbox: bool,
pub auth: Auth<'a>,
}
impl<'a> Client<'a> {
pub fn new(client_id: &'a str, secret: &'a str, sandbox: bool) -> Client<'a> {
Client {
client: reqwest::Client::new(),
sandbox,
auth: Auth {
client_id,
secret,
access_token: None,
expires: None,
},
}
}
fn endpoint(&self) -> &str {
if self.sandbox {
SANDBOX_ENDPOINT
} else {
LIVE_ENDPOINT
}
}
pub async fn get_access_token(&mut self) -> Result<(), Box<dyn std::error::Error>> {
let res = self
.client
.post(format!("{}/v1/oauth2/token", self.endpoint()).as_str())
.basic_auth(self.auth.client_id, Some(self.auth.secret))
.header("Content-Type", "x-www-form-urlencoded")
.header("Accept", "application/json")
.body("grant_type=client_credentials")
.send()
.await?;
if res.status().is_success() {
let token = res.json::<AccessToken>().await?;
self.auth.expires = Some(Instant::now() + Duration::new(token.expires_in, 0));
self.auth.access_token = Some(token);
println!("{:#?}", self.auth);
} else {
println!("status = {:#?}", res.status());
println!("res = {:#?}", res);
return Err(Box::new(errors::GetAccessTokenError));
}
Ok(())
}
}

19
src/tests.rs Normal file
View File

@ -0,0 +1,19 @@
use crate::*;
use dotenv::dotenv;
use std::env;
#[tokio::test]
async fn it_works() {
dotenv().ok();
let clientid = env::var("PAYPAL_CLIENTID").unwrap();
let secret = env::var("PAYPAL_SECRET").unwrap();
let mut client = Client::new(
clientid.as_str(),
secret.as_str(),
true,
);
assert_eq!(client.get_access_token().await.is_err(), false, "should not error");
println!("{:#?}", client);
}