如何高效的给后端系统发起http请求,快速构建基于restful api风格的api sdk

在开发中不同的的客户端请求服务器的方式因为平台和语言的差异提供的能力不同而多种多样,如浏览器的ajax和fetch,android使用java高度封装的HttpClient或OkHttp,IOS也有自己相关的工具(最近很火的flutter,官方也有提供一个http相关的库,在github可以搜索到 )。然而我们抛开语言平台等差异可以发现对于结构请求是有很多共性的 ,比如数据是已表单的形式提交还是以json的形式提交, 提交到哪里(目标地址),提交的方式(GET、POST), 返回什么类型(结构)的数据,以及鉴权(token)等统一处理(拦截器,或过滤器)。
  所以我们可以屡一下思路,对于客户端来说接口请求的流程可以参考下图(画的太烂):客户端请求接口的流程示意
  我们可以发现对于接口请求来说前四步是变化的,不同的接口可能都不一样,如果是小项目接口不多,每个接口独立写一个方法还能勉强接受,如果是复杂的项目动辄上百个接口就很痛疼了,特别是开发阶段,接口不稳定时候,接口参数和接口响应都有肯变化,前后端开发人员需要不停的沟通,对文档,效率极低,甚至会出现相互甩锅的问题。
  当然开源社区也有提供许多解决方法,比如自动生成文档的swagger(java),可以动态生成问题,及时更新,保证了接口的时效性和准确性,前端更是有各种各样的客户端请求工具,如浏览器的axios等,android的okHttp等。但是我觉得这些这些工具都还够,比如:开发人员还是得对着文档填写请求url,请求方式,接口参数(还有时间类型的处理),这些都是比较繁琐和容易出错的。当然社区依旧有解决方法,swagger有一个在线生成api sdk的工具(有一点学习成本)。
  自然这篇文章不是为了给社区打广告,我研究过swagger的代码生成后感觉不太满足需求,而且改不动(水平有限),就自己撸一个,请求工具包含2块,一个是前端请求的工具,一个是根据服务端代码生成(基于java源代码)api sdk的代码生成器(文末会提供github地址)。
  前端工具我叫它feign(思路借鉴于spring cloud的 open feign,目前实现了js版本,使用typescript 实现),实现思路:

      1: http adpater
           不同的平台的的http请求工具

      2: http client
           屏蔽了平台的差异化


      3: rest template
           (1):固化了一系列的请求相关的内容 例如 超时时间定定义,统一拦截,统一异常处理
           (2):支持多个模块的路由

      4 feign prroxy

           以接口代理的形式屏蔽远程调用的感知,调用时就如同使用本地方法一样

      5  annation(注解、装饰器)

          
            Feign:标记一个类为Feign代理

            RequestMapping相关注解:标记在上方法

            //接口签名注解,可以加入一些安全策略
            Signature: 可以标记那些参数需要加入签名

            //接口重试
            FetchRetry


            注解除了RequestMapping 外 还可以增加 CachePut, Task等 来管理本地缓存以及定时作业
            还可以考虑增加注解直接把请求下来的数据加入状态管理器中 例如redux

下面是一个feign代理类的例子

/**
 * 测试服务
 * @author wxup
 * @create 2018-11-03 9:34
 **/
@Feign({
    // apiModule: "member",   //接口对于的模块,如果对于复杂的项目需要请求不同入口模块的接口可以根据这个进行请求路由
    value: "test"
})
export default class TestService {


    queryList: (evt: any, options?: FetchOptions) => Promise<any> = undefined;


    @Signature({fields: []})
    @RequestMapping({
        value: "testQuery",
        method: RequestMethod.POST,
        headers:{}
    })
    @FetchRetry({
        retries: 5,
        maxTimeout: 25 * 1000
    })
    testQuery: (evt: any, options?: FetchOptions) => Promise<any>;

    @Signature({fields: ["userName"]})
    @PostMapping({headers: {myHeader: "tk_{memberId}"}})
    findMember: (
        request: {
            userName: string,
            memberId: number,
        },
        options?: FetchOptions) => Promise<any>;

    @Signature({fields: ["memberId"]})
    @DeleteMapping({value: "delete_member/{memberId}"})
    deleteMember: (
        request: {
            memberId: number,
        },
        options?: FetchOptions) => Promise<number>;
}

从上面的例子我们可以看到这个类的声明是非常简单明了的,在调用的时候就如同调用本地的方法一样,有明确的请求参数和响应结果,可以标记字段的类型,以及是否必填,参数验证规则等。当然也有统一处理(拦截器),以及统一异常处理(这里的异常是指http的请求的异常,比如500等错误),具体的可以参考源码中的例子。
  当然上面这个看起来很不错,但是又有了额外的工作量,要写一堆的DTO(数据传输对象),项目时间有很紧,怎么来得及?所以这个时候需要代码生成工具,根据服务端的代码生成客户端的api sdk,这样既保证了准确性,又减少了工作量。

  • typescript common_fetch
  • common-codegen 基于java的代码生成工具,目前仅支持源码生成,可以根据swagger的注解生成,也可以自定义生成的规则,后续会加入基于swagger open api 的规范,通过文档生成。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值