ITADN
vapor-community/stripe-kit
vapor-community/stripe-kit · 文件 下载 ZIP
文件最后提交记录最后更新时间
README.md
以下内容由 AI 翻译,如有问题请点此提交 issue 反馈

StripeKit

Test

StripeKit 是一个用于与 Stripe API 通信的 Swift 包,适用于服务端 Swift 应用。

版本支持

Stripe API 版本 2022-11-15 -> StripeKit: 22.0.0

安装

要开始使用 StripeKit,请在您的 Package.swift 中添加以下内容

.package(url: "https://github.com/vapor-community/stripe-kit.git", from: "22.0.0")

使用 API

初始化 StripeClient

let httpClient = HTTPClient(..)
let stripe = StripeClient(httpClient: httpClient, apiKey: "sk_12345")

现在你可以通过 stripe 访问 API。

你可用的 API 对应于已实现的功能。

例如,要使用 charges API,stripeclient 有一个属性,可通过路由访问该 API。

do {
    let charge = try await stripe.charges.create(amount: 2500,
                                                 currency: .usd,
                                                 description: "A server written in swift.",
                                                 source: "tok_visa")
    if charge.status == .succeeded {
        print("New swift servers are on the way 🚀")
    } else {
        print("Sorry you have to use Node.js 🤢")
    }
} catch {
    // Handle error
}

可展开对象

StripeKit 支持通过 3 个属性包装器实现 可展开对象

@Expandable@DynamicExpandable@ExpandableCollection

所有可以返回展开对象的 API 路由都有一个额外参数 expand: [String]?,用于指定要展开哪些对象。

@Expandable 配合使用:

  1. 展开单个字段。
// Expanding a customer from creating a `PaymentIntent`.
let paymentIntent = try await stripeclient.paymentIntents.create(amount: 2500, currency: .usd, expand: ["customer"])
// Accessing the expanded `Customer` object
paymentIntent.$customer.email
  1. 展开多个字段。
// Expanding a customer and payment method from creating a `PaymentIntent`.
let paymentIntent = try await stripeclient.paymentIntents.create(amount: 2500, currency: .usd, expand: ["customer", "paymentMethod"])
// Accessing the expanded `StripeCustomer` object   
 paymentIntent.$customer?.email // "stripe@example.com"
// Accessing the expanded `StripePaymentMethod` object
 paymentIntent.$paymentMethod?.card?.last4 // "1234"
  1. 展开嵌套字段。
// Expanding a payment method and its nested customer from creating a `PaymentIntent`.
let paymentIntent = try await stripeclient.paymentIntents.create(amount: 2500, currency: .usd, expand: ["paymentMethod.customer"])
// Accessing the expanded `PaymentMethod` object
 paymentIntent.$paymentMethod?.card?.last4 // "1234"
// Accessing the nested expanded `Customer` object   
 paymentIntent.$paymentMethod?.$customer?.email // "stripe@example.com"
  1. 与 list all 配合使用。

注意:对于 list 操作,展开的字段必须以 data

// Expanding a customer from listing all `PaymentIntent`s.
let list = try await stripeclient.paymentIntents.listAll(filter: ["expand": ["data.customer"...]])
// Accessing the first `StripePaymentIntent`'s expanded `Customer` property
list.data?.first?.$customer?.email // "stripe@example.com"

``` 开头

### 与 `@DynamicExpandable` 配合使用:

Stripe 中的某些对象可以展开为不同的对象
例如:

一个 `ApplicationFee` 具有一个 `originatingTransaction` 属性,它可以扩展为一个 [电荷或一个转移](https://stripe.com/docs/api/application_fees/object#application_fee_object-originating_transaction)。

在展开时,您可以通过执行以下操作来指定预期的对象:

```swift
let applicationfee = try await stripeclient.applicationFees.retrieve(fee: "fee_1234", expand: ["originatingTransaction"])
// Access the originatingTransaction as a Charge
applicationfee.$originatingTransaction(as: Charge.self)?.amount // 2500
...
// Access the originatingTransaction as a Transfer
applicationfee.$originatingTransaction(as: Transfer.self)?.destination // acc_1234

@ExpandableCollection 配合使用:

  1. 展开 id 数组
let invoice = try await stripeClient.retrieve(invoice: "in_12345", expand: ["discounts"])

// Access the discounts array as `String`s
invoice.discounts.map { print($0) } // "","","",..

// Access the array of `Discount`s
invoice.$discounts.compactMap(\.id).map { print($0) } // "di_1","di_2","di_3",...  

参数与类型安全的细微之处

Stripe 习惯于更改 API,并且其许多 API 具有动态参数。 为了适应这些更改,某些接受 hashDictionaries 作为参数的路由,由 Swift 字典 [String: Any] 表示。

例如,考虑 Connect 账户 API。

// We define a custom dictionary to represent the paramaters stripe requires.
// This allows us to avoid having to add updates to the library when a paramater or structure changes.
let individual: [String: Any] = ["address": ["city": "New York",
					     "country": "US",
                                             "line1": "1551 Broadway",
                                             "postal_code": "10036",
	                  	             "state": "NY"],
				 "first_name": "Taylor",
			         "last_name": "Swift",
                                 "ssn_last_4": "0000",
				 "dob": ["day": "13",
					 "month": "12",
					 "year": "1989"]] 
												 
let businessSettings: [String: Any] = ["payouts": ["statement_descriptor": "SWIFTFORALL"]]

let tosDictionary: [String: Any] = ["date": Int(Date().timeIntervalSince1970), "ip": "127.0.0.1"]

let connectAccount = try await stripe.connectAccounts.create(type: .custom,									
                                  country: "US",
				  email: "a@example.com",
				  businessType: .individual,
			          defaultCurrency: .usd,
				  externalAccount: "bank_token",
			          individual: individual,
				  requestedCapabilities: ["platform_payments"],
				  settings: businessSettings,
				  tosAcceptance: tosDictionary)
print("New Stripe Connect account ID: \(connectAccount.id)")

通过 Stripe-Account 请求头进行身份验证

首选的身份验证方式是使用您的(平台账户的)密钥,并传递一个 Stripe-Account 请求头,以标识正在为其发起请求的已连接账户。示例请求使用构建器风格的 API,代表已连接账户对一笔 费用执行退款:

   stripe.refunds
    .addHeaders(["Stripe-Account": "acc_12345",
             "Authorization": "Bearer different_api_key",
             "Stripe-Version": "older-api-version"])
    .create(charge: "ch_12345", reason: .requestedByCustomer)

注意: 如果持有对 StripeClient 的引用,修改后的请求头将保留在该路由实例(本例中为 refunds)上。如果您在函数作用域内访问 StripeClient,则请求头不会被保留。

幂等请求

与账户请求头类似,您可以使用相同的构建器风格 API 将幂等性密钥附加到您的请求中。

    let key = UUID().uuidString
    stripe.refunds
    .addHeaders(["Idempotency-Key": key])
    .create(charge: "ch_12345", reason: .requestedByCustomer)

Webhooks

webhooks API 可以以类型安全的方式使用,以提取实体。以下是监听支付意图 webhook 的示例。

func handleStripeWebhooks(req: Request) async throws -> HTTPResponse {

    let signature = req.headers["Stripe-Signature"]

    try StripeClient.verifySignature(payload: req.body, header: signature, secret: "whsec_1234") 
    // Stripe dates come back from the Stripe API as epoch and the StripeModels convert these into swift `Date` types.
    // Use a date and key decoding strategy to successfully parse out the `created` property and snake case strpe properties. 
    let decoder = JSONDecoder()
    decoder.dateDecodingStrategy = .secondsSince1970
    decoder.keyDecodingStrategy = .convertFromSnakeCase
    
    let event = try decoder.decode(StripeEvent.self, from: req.bodyData)
    
    switch (event.type, event.data?.object) {
    case (.paymentIntentSucceeded, .paymentIntent(let paymentIntent)):
        print("Payment capture method: \(paymentIntent.captureMethod?.rawValue)")
        return HTTPResponse(status: .ok)
        
    default: return HTTPResponse(status: .ok)
    }
}

与 Vapor 配合使用

StripeKit 相当易于使用,但为了更好地与 Vapor 集成,以下是一些有用的扩展

import Vapor
import StripeKit

extension Application {
    public var stripe: StripeClient {
        guard let stripeKey = Environment.get("STRIPE_API_KEY") else {
            fatalError("STRIPE_API_KEY env var required")
        }
        return .init(httpClient: self.http.client.shared, apiKey: stripeKey)
    }
}

extension Request {
    private struct StripeKey: StorageKey {
        typealias Value = StripeClient
    }
    
    public var stripe: StripeClient {
        if let existing = application.storage[StripeKey.self] {
            return existing
        } else {
            guard let stripeKey = Environment.get("STRIPE_API_KEY") else {
                fatalError("STRIPE_API_KEY env var required")
            }
            let new = StripeClient(httpClient: self.application.http.client.shared, apiKey: stripeKey)
            self.application.storage[StripeKey.self] = new
            return new
        }
    }
}

extension StripeClient {
    /// Verifies a Stripe signature for a given `Request`. This automatically looks for the header in the headers of the request and the body.
    /// - Parameters:
    ///     - req: The `Request` object to check header and body for
    ///     - secret: The webhook secret used to verify the signature
    ///     - tolerance: In seconds the time difference tolerance to prevent replay attacks: Default 300 seconds
    /// - Throws: `StripeSignatureError`
    public static func verifySignature(for req: Request, secret: String, tolerance: Double = 300) throws {
        guard let header = req.headers.first(name: "Stripe-Signature") else {
            throw StripeSignatureError.unableToParseHeader
        }
        
        guard let data = req.body.data else {
            throw StripeSignatureError.noMatchingSignatureFound
        }
        
        try StripeClient.verifySignature(payload: Data(data.readableBytesView), header: header, secret: secret, tolerance: tolerance)
    }
}

extension StripeSignatureError: AbortError {
    public var reason: String {
        switch self {
        case .noMatchingSignatureFound:
            return "No matching signature was found"
        case .timestampNotTolerated:
            return "Timestamp was not tolerated"
        case .unableToParseHeader:
            return "Unable to parse Stripe-Signature header"
        }
    }
    
    public var status: HTTPResponseStatus {
        .badRequest
    }
}

已实现的功能

核心资源

  • 余额
  • 余额交易
  • 扣款
  • 客户
  • 争议
  • 事件
  • 文件
  • 文件链接
  • 授权指令
  • PaymentIntents
  • SetupIntents
  • SetupAttempts
  • 付款
  • 退款
  • 令牌
  • EphemeralKeys

支付方式

  • 支付方式
  • 银行账户
  • 现金余额
  • 银行卡
  • 资金来源

产品

  • 产品
  • 价格
  • 优惠券
  • 促销码
  • 折扣
  • 税码
  • 税率
  • 运费

结账

  • 会话

支付链接

  • 支付链接

计费

  • 贷记单
  • 客户余额交易
  • 客户门户
  • 客户税号
  • 发票
  • 发票项目
  • 计划
  • 报价单
  • 报价单行项目
  • 订阅
  • 订阅项目
  • 订阅计划
  • 测试时钟
  • 用量记录

Connect

  • 账户
  • 账户链接
  • 账户会话
  • 应用费用
  • 应用费用退款
  • 功能
  • 国家规范
  • 外部账户
  • 人员
  • 充值
  • 转账
  • 转账冲正
  • 密钥管理

欺诈

  • 早期欺诈警告
  • 审查
  • 值列表
  • 值列表项

发卡

  • 授权
  • 持卡人
  • 银行卡
  • 争议
  • 资金指令
  • 交易

终端

  • 连接令牌

  • 位置

  • 读者

  • 硬件订单

  • 硬件产品

  • 硬件 SKU

  • 硬件运输方式

  • 配置


Sigma

  • 计划查询

报告

  • 报告运行
  • 报告类型

身份

  • VerificationSessions
  • VerificationReports

Webhooks

  • Webhook 端点
  • 签名验证

幂等请求

许可证

StripeKit 在 MIT 许可证下提供。有关更多信息,请参阅 LICENSE 文件。