feat(docs): add multiple examples support and webhook schema (#1864)

This commit is contained in:
Narayan Bhat
2023-08-09 11:25:56 +05:30
committed by GitHub
parent 27692fda85
commit f8ef52c645
6 changed files with 317 additions and 12 deletions

View File

@ -1,6 +1,7 @@
use common_utils::custom_serde;
use serde::{Deserialize, Serialize};
use time::PrimitiveDateTime;
use utoipa::ToSchema;
use crate::{disputes, enums as api_enums, payments, refunds};
@ -81,20 +82,33 @@ pub struct IncomingWebhookDetails {
pub resource_object: Vec<u8>,
}
#[derive(Debug, Clone, Serialize)]
#[derive(Debug, Clone, Serialize, ToSchema)]
pub struct OutgoingWebhook {
/// The merchant id of the merchant
pub merchant_id: String,
/// The unique event id for each webhook
pub event_id: String,
/// The type of event this webhook corresponds to.
#[schema(value_type = EventType)]
pub event_type: api_enums::EventType,
/// This is specific to the flow, for ex: it will be `PaymentsResponse` for payments flow
pub content: OutgoingWebhookContent,
#[serde(default, with = "custom_serde::iso8601")]
/// The time at which webhook was sent
pub timestamp: PrimitiveDateTime,
}
#[derive(Debug, Clone, Serialize)]
#[derive(Debug, Clone, Serialize, ToSchema)]
#[serde(tag = "type", content = "object", rename_all = "snake_case")]
pub enum OutgoingWebhookContent {
#[schema(value_type = PaymentsResponse)]
PaymentDetails(payments::PaymentsResponse),
#[schema(value_type = RefundResponse)]
RefundDetails(refunds::RefundResponse),
#[schema(value_type = DisputeResponse)]
DisputeDetails(Box<disputes::DisputeResponse>),
}

View File

@ -736,6 +736,7 @@ impl Currency {
serde::Serialize,
strum::Display,
strum::EnumString,
ToSchema,
)]
#[router_derive::diesel_enum(storage_type = "pg_enum")]
#[serde(rename_all = "snake_case")]

View File

@ -17,7 +17,6 @@ pub mod routes;
pub mod scheduler;
pub mod middleware;
#[cfg(feature = "openapi")]
pub mod openapi;
pub mod services;
pub mod types;

View File

@ -1,3 +1,4 @@
#[cfg(feature = "openapi")]
#[derive(utoipa::OpenApi)]
#[openapi(
info(
@ -318,6 +319,9 @@ Never share your secret api keys. Keep them guarded and secure.
api_models::enums::PayoutStatus,
api_models::enums::PayoutType,
api_models::payments::FrmMessage,
api_models::webhooks::OutgoingWebhook,
api_models::webhooks::OutgoingWebhookContent,
api_models::enums::EventType,
crate::types::api::admin::MerchantAccountResponse,
crate::types::api::admin::MerchantConnectorId,
crate::types::api::admin::MerchantDetails,
@ -377,3 +381,107 @@ impl utoipa::Modify for SecurityAddon {
}
}
}
pub mod examples {
/// Creating the payment with minimal fields
pub const PAYMENTS_CREATE_MINIMUM_FIELDS: &str = r#"{
"amount": 6540,
"currency": "USD",
}"#;
/// Creating a manual capture payment
pub const PAYMENTS_CREATE_WITH_MANUAL_CAPTURE: &str = r#"{
"amount": 6540,
"currency": "USD",
"capture_method":"manual"
}"#;
/// Creating a payment with billing and shipping address
pub const PAYMENTS_CREATE_WITH_ADDRESS: &str = r#"{
"amount": 6540,
"currency": "USD",
"customer": {
"id" : "cus_abcdefgh"
},
"billing": {
"address": {
"line1": "1467",
"line2": "Harrison Street",
"line3": "Harrison Street",
"city": "San Fransico",
"state": "California",
"zip": "94122",
"country": "US",
"first_name": "joseph",
"last_name": "Doe"
},
"phone": {
"number": "8056594427",
"country_code": "+91"
}
}
}"#;
/// Creating a payment with customer details
pub const PAYMENTS_CREATE_WITH_CUSTOMER_DATA: &str = r#"{
"amount": 6540,
"currency": "USD",
"customer": {
"id":"cus_abcdefgh",
"name":"John Dough",
"phone":"9999999999",
"email":"john@example.com"
}
}"#;
/// 3DS force payment
pub const PAYMENTS_CREATE_WITH_FORCED_3DS: &str = r#"{
"amount": 6540,
"currency": "USD",
"authentication_type" : "three_ds"
}"#;
/// A payment with other fields
pub const PAYMENTS_CREATE: &str = r#"{
"amount": 6540,
"currency": "USD",
"payment_id": "abcdefghijklmnopqrstuvwxyz",
"customer": {
"id":"cus_abcdefgh",
"name":"John Dough",
"phone":"9999999999",
"email":"john@example.com"
},
"description": "Its my first payment request",
"statement_descriptor_name": "joseph",
"statement_descriptor_suffix": "JS",
"metadata": {
"udf1": "some-value",
"udf2": "some-value"
}
}"#;
/// Creating the payment with order details
pub const PAYMENTS_CREATE_WITH_ORDER_DETAILS: &str = r#"{
"amount": 6540,
"currency": "USD",
"order_details": [
{
"product_name": "Apple iPhone 15",
"quantity": 1,
"amount" : 6540
}
]
}"#;
/// Creating the payment with connector metadata for noon
pub const PAYMENTS_CREATE_WITH_NOON_ORDER_CATETORY: &str = r#"{
"amount": 6540,
"currency": "USD",
"connector_metadata": {
"noon": {
"order_category":"shoes"
}
}
}"#;
}

View File

@ -10,6 +10,12 @@ use crate::{
errors::http_not_implemented,
payments::{self, PaymentRedirectFlow},
},
openapi::examples::{
PAYMENTS_CREATE, PAYMENTS_CREATE_MINIMUM_FIELDS, PAYMENTS_CREATE_WITH_ADDRESS,
PAYMENTS_CREATE_WITH_CUSTOMER_DATA, PAYMENTS_CREATE_WITH_FORCED_3DS,
PAYMENTS_CREATE_WITH_MANUAL_CAPTURE, PAYMENTS_CREATE_WITH_NOON_ORDER_CATETORY,
PAYMENTS_CREATE_WITH_ORDER_DETAILS,
},
services::{api, authentication as auth},
types::{
api::{self as api_types, enums as api_enums, payments as payment_types},
@ -23,17 +29,59 @@ use crate::{
#[utoipa::path(
post,
path = "/payments",
request_body=PaymentsCreateRequest,
request_body(
content = PaymentsCreateRequest,
examples(
(
"Create a payment with minimul fields" = (
value = json!(PAYMENTS_CREATE_MINIMUM_FIELDS)
)
),
(
"Create a manual capture payment" = (
value = json!(PAYMENTS_CREATE_WITH_MANUAL_CAPTURE)
)
),
(
"Create a payment with address" = (
value = json!(PAYMENTS_CREATE_WITH_ADDRESS)
)
),
(
"Create a payment with customer details" = (
value = json!(PAYMENTS_CREATE_WITH_CUSTOMER_DATA)
)
),
(
"Create a 3DS payment" = (
value = json!(PAYMENTS_CREATE_WITH_FORCED_3DS)
)
),
(
"Create a payment" = (
value = json!(PAYMENTS_CREATE)
)
),
(
"Create a payment with order details" = (
value = json!(PAYMENTS_CREATE_WITH_ORDER_DETAILS)
)
),
(
"Create a payment with order category for noon" = (
value = json!(PAYMENTS_CREATE_WITH_NOON_ORDER_CATETORY)
)
),
)),
responses(
(status = 200, description = "Payment created", body = PaymentsResponse),
(status = 400, description = "Missing Mandatory fields")
),
tag = "Payments",
operation_id = "Create a Payment",
security(("api_key" = []))
security(("api_key" = [])),
)]
#[instrument(skip_all, fields(flow = ?Flow::PaymentsCreate))]
// #[post("")]
pub async fn payments_create(
state: web::Data<app::AppState>,
req: actix_web::HttpRequest,

View File

@ -976,6 +976,32 @@
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaymentsCreateRequest"
},
"examples": {
"Create a 3DS payment": {
"value": "{\n \"amount\": 6540,\n \"currency\": \"USD\",\n \"authentication_type\" : \"three_ds\"\n }"
},
"Create a manual capture payment": {
"value": "{\n \"amount\": 6540,\n \"currency\": \"USD\",\n \"capture_method\":\"manual\"\n }"
},
"Create a payment": {
"value": "{\n \"amount\": 6540,\n \"currency\": \"USD\",\n \"payment_id\": \"abcdefghijklmnopqrstuvwxyz\",\n \"customer\": {\n \"id\":\"cus_abcdefgh\",\n \"name\":\"John Dough\",\n \"phone\":\"9999999999\",\n \"email\":\"john@example.com\"\n },\n \"description\": \"Its my first payment request\",\n \"statement_descriptor_name\": \"joseph\",\n \"statement_descriptor_suffix\": \"JS\",\n \"metadata\": {\n \"udf1\": \"some-value\",\n \"udf2\": \"some-value\"\n }\n }"
},
"Create a payment with address": {
"value": "{\n \"amount\": 6540,\n \"currency\": \"USD\",\n \"customer\": {\n \"id\" : \"cus_abcdefgh\"\n },\n \"billing\": {\n \"address\": {\n \"line1\": \"1467\",\n \"line2\": \"Harrison Street\",\n \"line3\": \"Harrison Street\",\n \"city\": \"San Fransico\",\n \"state\": \"California\",\n \"zip\": \"94122\",\n \"country\": \"US\",\n \"first_name\": \"joseph\",\n \"last_name\": \"Doe\"\n },\n \"phone\": {\n \"number\": \"8056594427\",\n \"country_code\": \"+91\"\n }\n }\n }"
},
"Create a payment with customer details": {
"value": "{\n \"amount\": 6540,\n \"currency\": \"USD\",\n \"customer\": {\n \"id\":\"cus_abcdefgh\",\n \"name\":\"John Dough\",\n \"phone\":\"9999999999\",\n \"email\":\"john@example.com\"\n }\n }"
},
"Create a payment with minimul fields": {
"value": "{\n \"amount\": 6540,\n \"currency\": \"USD\",\n }"
},
"Create a payment with order category for noon": {
"value": "{\n \"amount\": 6540,\n \"currency\": \"USD\",\n \"connector_metadata\": {\n \"noon\": {\n \"order_category\":\"shoes\"\n }\n }\n }"
},
"Create a payment with order details": {
"value": "{\n \"amount\": 6540,\n \"currency\": \"USD\",\n \"order_details\": [\n {\n \"product_name\": \"Apple iPhone 15\",\n \"quantity\": 1,\n \"amount\" : 6540\n }\n ]\n }"
}
}
}
},
@ -4853,6 +4879,24 @@
}
}
},
"EventType": {
"type": "string",
"enum": [
"payment_succeeded",
"payment_failed",
"payment_processing",
"action_required",
"refund_succeeded",
"refund_failed",
"dispute_opened",
"dispute_expired",
"dispute_accepted",
"dispute_cancelled",
"dispute_challenged",
"dispute_won",
"dispute_lost"
]
},
"FeatureMetadata": {
"type": "object",
"properties": {
@ -6986,6 +7030,97 @@
}
}
},
"OutgoingWebhook": {
"type": "object",
"required": [
"merchant_id",
"event_id",
"event_type",
"content"
],
"properties": {
"merchant_id": {
"type": "string",
"description": "The merchant id of the merchant"
},
"event_id": {
"type": "string",
"description": "The unique event id for each webhook"
},
"event_type": {
"$ref": "#/components/schemas/EventType"
},
"content": {
"$ref": "#/components/schemas/OutgoingWebhookContent"
},
"timestamp": {
"type": "string",
"format": "date-time",
"description": "The time at which webhook was sent"
}
}
},
"OutgoingWebhookContent": {
"oneOf": [
{
"type": "object",
"required": [
"type",
"object"
],
"properties": {
"type": {
"type": "string",
"enum": [
"payment_details"
]
},
"object": {
"$ref": "#/components/schemas/PaymentsResponse"
}
}
},
{
"type": "object",
"required": [
"type",
"object"
],
"properties": {
"type": {
"type": "string",
"enum": [
"refund_details"
]
},
"object": {
"$ref": "#/components/schemas/RefundResponse"
}
}
},
{
"type": "object",
"required": [
"type",
"object"
],
"properties": {
"type": {
"type": "string",
"enum": [
"dispute_details"
]
},
"object": {
"$ref": "#/components/schemas/DisputeResponse"
}
}
}
],
"discriminator": {
"propertyName": "type"
}
},
"PayLaterData": {
"oneOf": [
{