手把手教你把三方支付接口打包成 TypeScript SDK

在日常开发中,调用第三方开放平台接口时,直接对接往往需要处理繁琐的参数校验、签名加密、环境切换等问题。本文就以拉卡拉开放平台为例,手把手教你开发一个 TypeScript SDK 包,从项目初始化到发布上线,每一步都详细讲解,让你轻松掌握 SDK 开发技巧。

一、 准备工作

1、 环境搭建

首先,确保你的开发环境中已经安装了 Node.js 和 npm。可以通过以下命令检查版本:

复制代码
node -v
npm -v

2、 初始化项目

创建一个项目文件夹,比如lkl-zf-bs-laop-ts-sdk,然后进入文件夹初始化项目:

bash 复制代码
mkdir lkl-zf-bs-laop-ts-sdk
cd lkl-zf-bs-laop-ts-sdk
npm init -y

执行后会生成一个package.json文件,包含了项目的基本信息

3、 安装依赖

sql 复制代码
npm install typescript eslint prettier @types/node --save-dev
# 安装接口请求库axios
npm install axios --save

4、 配置TypeScript

在项目根目录下创建tsconfig.json文件,配置 TypeScript 编译选项:

json 复制代码
{
    "compilerOptions": {
        "target": "ES6",
        "module": "commonjs",
        "outDir": "./dist",
        "rootDir": "./src",
        "strict": true,
        "esModuleInterop": true,
        "skipLibCheck": true,
        "forceConsistentCasingInFileNames": true,
        "declaration": true
    }
}

这里declaration设为true,会自动生成类型声明文件,方便其他开发者使用时获得类型提示。

5、 配置 ESLint 和 Prettier

ESLint 用于代码检查,Prettier 用于代码格式化,让代码风格保持一致。

初始化 ESLint 配置:

csharp 复制代码
npx eslint --init 

按照提示选择合适的配置,比如选择 Node.js 环境、TypeScript 语言等。 然后创建.prettierrc文件:

json 复制代码
{ 
    "singleQuote": true, 
    "trailingComma": "es5", 
    "printWidth": 80, 
    "tabWidth": 2 
} 

二、 项目结构设计

参考拉卡拉开放平台 PHP SDK的结构,我设计 TypeScript SDK 的目录结构如下:

scss 复制代码
lkl-zf-bs-laop-ts-sdk/
├── src/
│   ├── v3/
│   │   ├── src/
│   │   │   ├── Configuration.ts  // 配置处理
│   │   │   ├── LakalaApi.ts      // API调用核心
│   │   │   └── utils/            // 工具函数
│   │   └── test/                 // 测试代码
│   └── index.ts                  // 入口文件
├── dist/                         // 编译输出目录
├── .eslintrc.js
├── .prettierrc
├── tsconfig.json
└── package.json

三、 核心功能实现

1、 配置类实现

拉卡拉开放平台 SDK 需要一些配置信息,如 appId、密钥路径等。我们创建Configuration类来管理这些配置。 在src/v3/src/Configuration.ts中:

ini 复制代码
export class Configuration {
    appDebug: boolean;
    appId: string;
    serialNo: string;
    hostPro: string;
    hostTest: string;
    sm4Key: string;
    merchantPrivateKeyPath: string;
    lklCertificatePath: string;

    /**
     * 初始化配置
     * @param config 配置对象
     */
    constructor(config?: Partial<Configuration>) {
        // 默认配置
        this.appDebug = false;
        this.appId = '';
        this.serialNo = '';
        this.hostPro = 'https://s2.lakala.com';
        this.hostTest = 'https://test.wsmsd.cn/sit';
        this.sm4Key = '';
        this.merchantPrivateKeyPath = '';
        this.lklCertificatePath = '';

        // 合并用户配置
        if (config) {
            Object.assign(this, config);
        }
    }
    /**
     * 获取当前环境的主机地址
     */
    getHost(): string {
        return this.appDebug ? this.hostTest : this.hostPro;
    }
}

2、 API调用核心类

创建LakalaApi类,封装接口调用的逻辑,包括请求发送、参数处理等。 在src/v3/src/LakalaApi.ts中:

typescript 复制代码
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
import { Configuration } from './Configuration';

export class LakalaApi {
    private config: Configuration;
    private axiosInstance: AxiosInstance;

    constructor(config: Configuration) {
        this.config = config;
        this.axiosInstance = axios.create({
            timeout: 5000,
            headers: {
                'Content-Type': 'application/json',
                'User-Agent': 'lkl-zf-bs-laop-ts-sdk/1.0.0'
            }
        });
    }

    /**
     * 发送带body的POST请求
     * @param path 接口路径
     * @param body 请求体
     * @returns 响应结果
     */
    async apiWithBody<T = any>(path: string, body: any): Promise<AxiosResponse<T>> {
        const url = `${this.config.getHost()}${path}`;
        
        try {
            const response = await this.axiosInstance.post<T>(url, body);
            return response;
        } catch (error) {
            console.error('API请求失败:', error);
            throw error;
        }
    }
}

3、 工具函数

在src/v3/src/utils/index.ts中,我们可以添加一些常用的工具函数,比如时间格式化:

scss 复制代码
/**
 * 生成当前时间戳,格式YYYYMMDDHHmmss
 */
export function getCurrentTime(): string {
    const date = new Date();
    return date.getFullYear().toString() +
        padZero(date.getMonth() + 1) +
        padZero(date.getDate()) +
        padZero(date.getHours()) +
        padZero(date.getMinutes()) +
        padZero(date.getSeconds());
}
/**
 * 数字补零
 * @param num 数字
 * @returns 补零后的字符串
 */
function padZero(num: number): string {
    return num < 10 ? `0${num}` : num.toString();
}

四、 测试用例编写

为了保证 SDK 的正确性,我们编写测试用例。这里使用 Jest 作为测试框架。

1、 安装Jest

sql 复制代码
npm install jest @types/jest ts-jest --save-dev

在package.json中添加测试脚本:

json 复制代码
"scripts": {
    "test": "jest",
    "test:watch": "jest --watch"
}

创建jest.config.js:

java 复制代码
module.exports = {
    preset: 'ts-jest',
    testEnvironment: 'node',
    testMatch: ['**/src/**/*.test.ts']
};

2、 编写查询交易测试用例

在src/v3/test/tradeQuery.test.ts中:

javascript 复制代码
import { Configuration } from '../src/Configuration';
import { LakalaApi } from '../src/LakalaApi';
import { getCurrentTime } from '../src/utils';

describe('交易查询接口测试', () => {
    let api: LakalaApi;

    beforeAll(() => {
        // 初始化配置,实际使用时替换为你的配置
        const config = new Configuration({
            appDebug: true, // 测试环境
            appId: '你的appId',
            serialNo: '你的serialNo'
        });
        api = new LakalaApi(config);
    });

    it('应该成功查询交易', async () => {
        const body = {
            req_time: getCurrentTime(),
            version: '3.0',
            req_data: {
                merchant_no: '822290070111135',
                term_no: '29034705',
                out_trade_no: `TEST${getCurrentTime()}`,
                trade_no: ''
            }
        };

        const response = await api.apiWithBody('/api/v3/labs/query/tradequery', body);
        expect(response.status).toBe(200);
        console.log('查询结果:', response.data);
    });
});

五、 编译与运行

  1. 编译代码

在package.json中添加编译脚本:

json 复制代码
"scripts": { 
    "build": "tsc", 
    "test": "jest", 
    "test:watch": "jest --watch" 
} 

执行编译:

arduino 复制代码
npm run build 

编译后的代码会输出到dist目录。

  1. 运行测试
bash 复制代码
npm test 

如果一切正常,会看到测试通过的结果,并输出查询到的交易信息。

六、 使用示例

其他开发者安装 SDK 后,可以这样使用:

javascript 复制代码
import { Configuration, LakalaApi, getCurrentTime } from 'lkl-zf-bs-laop-ts-sdk';

// 初始化配置
const config = new Configuration({
    appId: '你的appId',
    serialNo: '你的serialNo',
    appDebug: false // 生产环境
});

const api = new LakalaApi(config);

// 调用接口
async function queryTrade() {
    try {
        const body = {
            req_time: getCurrentTime(),
            version: '3.0',
            req_data: {
                merchant_no: '商户号',
                out_trade_no: '订单号'
            }
        };

        const response = await api.apiWithBody('/api/v3/labs/query/tradequery', body);
        console.log('交易信息:', response.data);
    } catch (error) {
        console.error('查询失败:', error);
    }
}

queryTrade();

总结

本文详细介绍了如何将拉卡拉开放平台的支付接口包装成 TypeScript SDK 的开发全过程,从环境搭建到核心功能实现,再到测试。通过这个过程,你不仅能得到一个可用的 SDK,还能掌握 TypeScript SDK 开发的通用方法。

在实际开发中,还可以根据拉卡拉开放平台的其他接口,扩展 SDK 的功能,比如退款、订单创建等。同时,要注意处理加密、签名等安全相关的逻辑,确保接口调用的安全性。

希望这篇教程对你有帮助,如果你在开发过程中遇到问题,可以参考拉卡拉开放平台官方文档或留言讨论。

相关推荐
叶 落9 小时前
Component cannot be used as a JSX component
typescript·react
OLong1 天前
第二章 - 抽象语法树(AST)概述
前端·typescript
Enheng9_91 天前
vue3项目开发细节记录
前端·vue.js·typescript
小宁爱Python2 天前
TypeScript 泛型详解:从基础到实战应用
前端·javascript·typescript
归于尽2 天前
从JS到TS:我们放弃了自由,却赢得了整个世界
前端·typescript
今晚一定早睡2 天前
new操作符
前端·javascript·typescript
pe7er2 天前
深入理解 TypeScript 的模板字面量类型 - 从 ms 库的类型定义说起
前端·typescript
kiramario3 天前
Electron Forge + React + Typescript + Webpack适配tailwindCSS-邪修版
react.js·typescript·electron
土豆12503 天前
TypeScript导出机制与类型扩展完全指南:提升代码架构与类型安全
typescript