use crate::v1::{Client, error, BASE_URL, standard};
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Debug)]
pub struct ListWebhooksResponse {
pub data : Vec<WebhookResource>,
pub links : ResponseLinks,
}
#[derive(Deserialize, Debug)]
pub struct GetWebhookResponse {
pub data : WebhookResource,
}
#[derive(Deserialize, Debug)]
pub struct CreateWebhookResponse {
pub data : WebhookResource,
}
#[derive(Deserialize, Debug)]
pub struct WebhookResource {
pub r#type : String,
pub id : String,
pub attributes : Attributes,
pub relationships : Relationships,
pub links : WebhookResourceLinks,
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Attributes {
pub url : String,
pub description : Option<String>,
pub secret_key : Option<String>,
pub created_at : String,
}
#[derive(Deserialize, Debug)]
pub struct Relationships {
pub logs : Logs,
}
#[derive(Deserialize, Debug)]
pub struct Logs {
pub links : Option<LogsLinks>,
}
#[derive(Deserialize, Debug)]
pub struct LogsLinks {
pub related : String,
}
#[derive(Deserialize, Debug)]
pub struct WebhookResourceLinks {
#[serde(rename = "self")]
pub this : String,
}
#[derive(Deserialize, Debug)]
pub struct ResponseLinks {
pub prev : Option<String>,
pub next : Option<String>,
}
#[derive(Deserialize, Debug)]
pub struct PingWebhookResponse {
pub data : WebhookEventResource,
}
#[derive(Deserialize, Debug)]
pub struct WebhookEventResource {
pub r#type : String,
pub id : String,
pub attributes : EventAttributes,
pub relationships : EventRelationships,
}
#[derive(Deserialize, Debug)]
pub struct EventRelationships {
pub webhook : Webhook,
pub transaction : Option<Transaction>,
}
#[derive(Deserialize, Debug)]
pub struct Transaction {
pub data : TransactionData,
pub links : Option<TransactionLinks>,
}
#[derive(Deserialize, Debug)]
pub struct Webhook {
pub data : WebhookData,
pub links : Option<WebhookLinks>,
}
#[derive(Deserialize, Debug)]
pub struct WebhookData {
pub r#type : String,
pub id : String,
}
#[derive(Deserialize, Debug)]
pub struct WebhookLinks {
pub related : String,
}
#[derive(Deserialize, Debug)]
pub struct TransactionData {
pub r#type : String,
pub id : String,
}
#[derive(Deserialize, Debug)]
pub struct TransactionLinks {
pub related : String,
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct EventAttributes {
pub event_type : standard::WebhookEventTypeEnum,
pub created_at : String,
}
#[derive(Deserialize, Debug)]
pub struct ListWebhookLogsResponse {
pub data : Vec<WebhookDeliveryLogResource>,
pub links : LogsResponseLinks,
}
#[derive(Deserialize, Debug)]
pub struct WebhookDeliveryLogResource {
pub r#type : String,
pub id : String,
pub attributes : DeliveryLogAttributes,
pub relationships : DeliveryLogRelationships,
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct DeliveryLogRelationships {
pub webhook_event : WebhookEvent,
}
#[derive(Deserialize, Debug)]
pub struct WebhookEvent {
pub data : WebhookEventData
}
#[derive(Deserialize, Debug)]
pub struct WebhookEventData {
pub r#type : String,
pub id : String,
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct DeliveryLogAttributes {
pub request : Request,
pub response : Option<Response>,
pub delivery_status : standard::WebhookDeliveryStatusEnum,
pub created_at : String,
}
#[derive(Deserialize, Debug)]
pub struct Request {
pub body : String,
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Response {
pub status_code : i64,
pub body : String,
}
#[derive(Deserialize, Debug)]
pub struct LogsResponseLinks {
pub prev : Option<String>,
pub next : Option<String>,
}
#[derive(Default)]
pub struct ListWebhooksOptions {
page_size : Option<u8>,
}
impl ListWebhooksOptions {
pub fn page_size(&mut self, value : u8) {
self.page_size = Some(value);
}
fn add_params(&self, url : &mut reqwest::Url) {
let mut query = String::new();
if let Some(value) = &self.page_size {
if !query.is_empty() {
query.push('&');
}
query.push_str(&format!("page[size]={}", value));
}
if !query.is_empty() {
url.set_query(Some(&query));
}
}
}
#[derive(Default)]
pub struct ListWebhookLogsOptions {
page_size : Option<u8>,
}
impl ListWebhookLogsOptions {
pub fn page_size(&mut self, value : u8) {
self.page_size = Some(value);
}
fn add_params(&self, url : &mut reqwest::Url) {
let mut query = String::new();
if let Some(value) = &self.page_size {
if !query.is_empty() {
query.push('&');
}
query.push_str(&format!("page[size]={}", value));
}
if !query.is_empty() {
url.set_query(Some(&query));
}
}
}
#[derive(Serialize)]
pub struct CreateWebhookRequest {
pub data : WebhookInputResource,
}
#[derive(Serialize)]
pub struct WebhookInputResource {
pub attributes : InputAttributes,
}
#[derive(Serialize)]
pub struct InputAttributes {
pub url : String,
pub description : Option<String>,
}
impl Client {
pub async fn list_webhooks(&self, options : &ListWebhooksOptions) -> Result<ListWebhooksResponse, error::Error> {
let mut url = reqwest::Url::parse(&format!("{}/webhooks", BASE_URL)).map_err(error::Error::UrlParse)?;
options.add_params(&mut url);
let res = reqwest::Client::new()
.get(url)
.header("Authorization", self.auth_header())
.send()
.await
.map_err(error::Error::Request)?;
match res.status() {
reqwest::StatusCode::OK => {
let body = res.text().await.map_err(error::Error::BodyRead)?;
let webhook_response : ListWebhooksResponse = serde_json::from_str(&body).map_err(error::Error::Json)?;
Ok(webhook_response)
},
_ => {
let body = res.text().await.map_err(error::Error::BodyRead)?;
let error : error::ErrorResponse = serde_json::from_str(&body).map_err(error::Error::Json)?;
Err(error::Error::Api(error))
}
}
}
pub async fn get_webhook(&self, id : &str) -> Result<GetWebhookResponse, error::Error> {
if id.is_empty() {
panic!("The provided webhook ID must not be empty.");
}
let url = reqwest::Url::parse(&format!("{}/webhooks/{}", BASE_URL, id)).map_err(error::Error::UrlParse)?;
let res = reqwest::Client::new()
.get(url)
.header("Authorization", self.auth_header())
.send()
.await
.map_err(error::Error::Request)?;
match res.status() {
reqwest::StatusCode::OK => {
let body = res.text().await.map_err(error::Error::BodyRead)?;
let webhook_response : GetWebhookResponse = serde_json::from_str(&body).map_err(error::Error::Json)?;
Ok(webhook_response)
},
_ => {
let body = res.text().await.map_err(error::Error::BodyRead)?;
let error : error::ErrorResponse = serde_json::from_str(&body).map_err(error::Error::Json)?;
Err(error::Error::Api(error))
}
}
}
pub async fn create_webhook(&self, webhook_url : &str, description : Option<String>) -> Result<CreateWebhookResponse, error::Error> {
let url = reqwest::Url::parse(&format!("{}/webhooks", BASE_URL)).map_err(error::Error::UrlParse)?;
let body = CreateWebhookRequest {
data : WebhookInputResource {
attributes : InputAttributes { url : String::from(webhook_url), description }
}
};
let body = serde_json::to_string(&body).map_err(error::Error::Serialize)?;
let res = reqwest::Client::new()
.post(url)
.header("Authorization", self.auth_header())
.header("Content-Type", "application/json")
.body(body)
.send()
.await
.map_err(error::Error::Request)?;
match res.status() {
reqwest::StatusCode::CREATED => {
let body = res.text().await.map_err(error::Error::BodyRead)?;
let webhook_response : CreateWebhookResponse = serde_json::from_str(&body).map_err(error::Error::Json)?;
Ok(webhook_response)
},
_ => {
let body = res.text().await.map_err(error::Error::BodyRead)?;
let error : error::ErrorResponse = serde_json::from_str(&body).map_err(error::Error::Json)?;
Err(error::Error::Api(error))
}
}
}
pub async fn delete_webhook(&self, id : &str) -> Result<(), error::Error> {
let url = reqwest::Url::parse(&format!("{}/webhooks/{}", BASE_URL, id)).map_err(error::Error::UrlParse)?;
let res = reqwest::Client::new()
.delete(url)
.header("Authorization", self.auth_header())
.send()
.await
.map_err(error::Error::Request)?;
match res.status() {
reqwest::StatusCode::NO_CONTENT => {
Ok(())
},
_ => {
let body = res.text().await.map_err(error::Error::BodyRead)?;
let error : error::ErrorResponse = serde_json::from_str(&body).map_err(error::Error::Json)?;
Err(error::Error::Api(error))
}
}
}
pub async fn ping_webhook(&self, id : &str) -> Result<PingWebhookResponse, error::Error> {
let url = reqwest::Url::parse(&format!("{}/webhooks/{}/ping", BASE_URL, id)).map_err(error::Error::UrlParse)?;
let res = reqwest::Client::new()
.post(url)
.header("Authorization", self.auth_header())
.header("Content-Type", "application/json")
.header("Content-Length", "0")
.send()
.await
.map_err(error::Error::Request)?;
match res.status() {
reqwest::StatusCode::CREATED => {
let body = res.text().await.map_err(error::Error::BodyRead)?;
let webhook_response : PingWebhookResponse = serde_json::from_str(&body).map_err(error::Error::Json)?;
Ok(webhook_response)
},
_ => {
let body = res.text().await.map_err(error::Error::BodyRead)?;
let error : error::ErrorResponse = serde_json::from_str(&body).map_err(error::Error::Json)?;
Err(error::Error::Api(error))
}
}
}
pub async fn list_webhook_logs(&self, id : &str, options : &ListWebhookLogsOptions) -> Result<ListWebhookLogsResponse, error::Error> {
let mut url = reqwest::Url::parse(&format!("{}/webhooks/{}/logs", BASE_URL, id)).map_err(error::Error::UrlParse)?;
options.add_params(&mut url);
let res = reqwest::Client::new()
.get(url)
.header("Authorization", self.auth_header())
.send()
.await
.map_err(error::Error::Request)?;
match res.status() {
reqwest::StatusCode::OK => {
let body = res.text().await.map_err(error::Error::BodyRead)?;
let webhook_response : ListWebhookLogsResponse = serde_json::from_str(&body).map_err(error::Error::Json)?;
Ok(webhook_response)
},
_ => {
let body = res.text().await.map_err(error::Error::BodyRead)?;
let error : error::ErrorResponse = serde_json::from_str(&body).map_err(error::Error::Json)?;
Err(error::Error::Api(error))
}
}
}
}
implement_pagination_v1!(ListWebhooksResponse);