You need to enable JavaScript to run this app. 如何将curl格式的Plaid API请求转换为SwiftUI适用的Swift代码
优惠活动
大模型
产品
解决方案
定价
更多

如何将curl格式的Plaid API请求转换为SwiftUI适用的Swift代码

这套实现不用绕弯子调用系统shell执行curl命令,直接用Apple原生的URLSession发起和curl示例参数完全一致的请求,同时适配SwiftUI的状态驱动逻辑,和现有SwiftUI项目的技术栈天然兼容。

实现步骤

1. 定义与接口匹配的数据模型

按照Plaid接口的字段要求,定义可编码/解码的Swift结构体,完全对应curl示例中请求体、响应体的嵌套结构,避免手动拼接JSON字符串带来的格式错误:

import Foundation

// 嵌套结构:用户唯一标识
struct PlaidUser: Encodable {
    let client_user_id: String
}

// 嵌套结构:账户过滤规则
struct AccountFilter: Encodable {
    let account_subtypes: [String]
}

struct PlaidAccountFilters: Encodable {
    let depository: AccountFilter
}

// 完整的Link Token创建请求体
struct LinkTokenCreateRequest: Encodable {
    let client_id: String
    let secret: String
    let user: PlaidUser
    let client_name: String
    let products: [String]
    let country_codes: [String]
    let language: String
    let webhook: String
    let account_filters: PlaidAccountFilters
}

// 接口返回的响应结构
struct LinkTokenCreateResponse: Decodable {
    let link_token: String
    let request_id: String
}

2. 封装适配SwiftUI的状态化网络服务

基于ObservableObject构建网络服务类,把请求过程中的加载状态、返回结果、错误信息通过@Published属性暴露给SwiftUI视图订阅,用async/await语法简化嵌套回调的逻辑:

import Combine

@MainActor
class PlaidTokenService: ObservableObject {
    // 供视图直接订阅的状态
    @Published var isLoading: Bool = false
    @Published var generatedLinkToken: String?
    @Published var errorMessage: String?

    // 注意:生产环境绝对不要把client_id和secret硬编码在客户端
    // 这类敏感凭证需要由自有后端代理请求,避免被逆向提取
    private let clientID = "替换为你的实际CLIENT_ID"
    private let secret = "替换为你的实际SECRET"
    private let requestURL = URL(string: "https://sandbox.plaid.com/link/token/create")!

    func createLinkToken() async {
        isLoading = true
        errorMessage = nil
        defer { isLoading = false }

        // 构造和curl示例完全匹配的请求参数
        let requestBody = LinkTokenCreateRequest(
            client_id: clientID,
            secret: secret,
            user: PlaidUser(client_user_id: "当前登录用户的唯一持久标识"),
            client_name: "Plaid App",
            products: ["auth"],
            country_codes: ["GB"],
            language: "en",
            webhook: "https://sample-web-hook.com",
            account_filters: PlaidAccountFilters(
                depository: AccountFilter(account_subtypes: ["checking"])
            )
        )

        do {
            // 把模型编码为符合接口要求的JSON
            let jsonData = try JSONEncoder().encode(requestBody)

            // 构造和curl配置完全一致的请求
            var request = URLRequest(url: requestURL)
            request.httpMethod = "POST"
            request.setValue("application/json", forHTTPHeaderField: "Content-Type")
            request.httpBody = jsonData

            // 发起原生网络请求
            let (data, response) = try await URLSession.shared.data(for: request)

            // 校验响应状态
            guard let httpResp = response as? HTTPURLResponse,
                  httpResp.statusCode == 200 else {
                errorMessage = "接口请求失败,状态码异常"
                return
            }

            // 解析返回结果
            let decoded = try JSONDecoder().decode(LinkTokenCreateResponse.self, from: data)
            generatedLinkToken = decoded.link_token
        } catch {
            errorMessage = "请求出错:\(error.localizedDescription)"
        }
    }
}

3. 在SwiftUI视图中集成调用

用@StateObject管理服务实例,根据返回的状态渲染不同的UI内容,在需要触发请求时通过Task发起异步调用:

import SwiftUI

struct PlaidLinkDemoView: View {
    @StateObject private var plaidService = PlaidTokenService()

    var body: some View {
        VStack(spacing: 20) {
            if plaidService.isLoading {
                ProgressView("正在生成Link Token...")
            } else if let token = plaidService.generatedLinkToken {
                Text("成功生成Token:\(token.prefix(20))...")
                Button("发起银行账户授权") {
                    // 拿到token后即可唤起Plaid Link SDK的授权流程
                }
            } else if let error = plaidService.errorMessage {
                Text(error)
                    .foregroundColor(.red)
                Button("重新请求") {
                    Task {
                        await plaidService.createLinkToken()
                    }
                }
            } else {
                Button("开始生成Link Token") {
                    Task {
                        await plaidService.createLinkToken()
                    }
                }
            }
        }
        .padding()
    }
}

关键注意事项

  • 敏感凭证不能硬编码在客户端:client_id、secret属于服务端密钥,一旦打包进App会被逆向提取,生产环境应当由自有后端代理Plaid接口请求,客户端仅从自有后端获取最终生成的link_token
  • 原curl示例的JSON存在语法瑕疵:user对象末尾多了一个无效逗号,直接复用该JSON片段会触发解析错误,上述代码模型已自动规避该问题
  • 这套实现零第三方依赖,完全基于系统原生框架,不需要通过Process组件调用系统的curl可执行文件。

内容的提问来源于stack exchange,提问作者user14861389

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.06 09:54:00