Thrift-HTTP 映射的 IDL 规范

日期版本作者变更内容
2022-05-22v1.0王景佩第一版 Thrift-HTTP 映射的 IDL 规范

本规范是 ThriftHTTP 接口映射的 IDL 定义标准,包括服务、接口以及请求 requestresponse 参数定义规范和错误码定义规范。Kitex 部分实现了该规范,注解说明有标注支持情况。

规范说明

(1)本规范采用注解方式来描述接口信息,包括接口的 method, path 以及接口请求参数,返回参数位置(如 headercookie )、名称等信息

(2)本规范所述注解采用 api.{key}={value} 的形式,其中key通常用于指定该字段出现的位置如(headercookiequerybody 等), value 用于指定该字段在对应位置的实际名称, 一些功能性注解(如api.none, api.js_conv, api.http_code) 除外

(3)本规范中定义的IDL注解如 api.get, api.header 等,只支持小写,不支持大写或者大小写混用如api.GET, api.Header

文件整体规范

  • 一个服务 service 对应一个 thrift 主文件,主文件里的 method 都是针对当前服务对应接口,主文件可以引用其它 thrift 文件定义
  • 每个 Method 原则上对应一个 RequestResponse 定义
  • 原则上不建议 Request 复用,可以复用 Response

Request 规范

约束

  1. 接口请求字段需要使用注解关联到 HTTP 的某类参数和参数名称。如果无注解,GET 方法接口关联query 参数, POST 方法关联 body 参数, 字段名对应参数key
  2. 如果 HTTP 请求是采用 GET 方式的,那么 request 定义中出现的 api.body 注解无效,只有api.query, api.path, api.cookie 有效。
  3. 如果 HTTP 请求是采用 POST 方式且序列化方式是 form 的,那么 request 的字段不能有复杂结构如mapobject,否则该字段无效。Kitex 目前暂未支持 form 格式,只支持 json 格式。

注解说明

注解说明字段约束Kitex 支持情况
api.queryapi.query 对应 HTTP 请求的 url query 参数只支持基本类型(object, map 以外)和逗号分隔的 list支持
api.pathapi.path 对应 HTTP 请求的 url path 参数支持基本类型支持
api.headerapi.header 对应 HTTP 请求的 header 参数只支持基本类型和逗号分隔的list支持
api.cookieapi.cookie 对应 HTTP 的 cookie 参数支持基本类型支持
api.bodyapi.body 对应 HTTP 的 body 参数
支持 body 为 jsonform 两种格式
在未指定接口序列化方式下默认json格式,也可以在method注解中使用api.serializer来指定json/form支持,但目前仅支持 JSON 格式
api.raw_bodyapi.raw_body HTTP 原始 body,少数接口 body 加密了,可以拿到原始的 body(二进制数组)支持
api.vd参数校验,使用了HTTPs://github.com/bytedance/go-tagexpr/tree/master/validator库,检验表达式语法参见包内readme文件暂未支持
api.js_convapi.js_conv 标识该字段传入参数需要进行 string to int64 转换,来解决前端 js 不支持 int64 的场景value通常写true,其它情况与不写该注解等价支持
api.raw_uriapi.raw_uri 用于 HTTP to RPC 协议转换,RPC 服务获取 HTTP接口对应的原始 uri只支持 string 类型暂未支持

举例

struct Item{
    1: optional i64 id(go.tag = 'json:"id"') // 对于嵌套结构体,如果要设置序列化key,使用gotag 如 `json:"id"`
    2: optional string text
}
typedef string JsonDict
struct BizRequest {
    1: optional i64 v_int64(api.query = 'v_int64') // 对应HTTP query中的v_int64, 且值范围为(0,200)
    2: optional string text(api.body = 'text') // 对应序列化key = text
    3: optional i32 token(api.header = 'token') // 对应HTTP header中的token
    4: optional JsonDict json_header(api.header = 'json_header')
    5: optional Item some(api.body = 'some') // 对应一级key = some
    6: optional list<ReqItem> req_items(api.query = 'req_items')
    // api.query仅支持逗号相隔的list,其他复杂类型不支持
    7: optional i32 api_version(api.path = 'action') // 对应uri的path参数
    8: optional i64 uid(api.path = 'biz') // 对应uri的path参数
    9: optional list<i64> cids(api.query = 'cids')
    // 对应query里面逗号隔开的数字, 如 cids=1,2,3,4仅支持list<i64>、list<i32>
    10: optional list<string> vids(api.query = 'vids')
}

Response 规范

约束

  • header 不支持除逗号相隔并且 value 为基本类型的 list 以外的复杂类型
  • 直接按照业务自己定义的 response。默认 json 序列化到 bodykey为字段名,注解可为空

注解说明

注解说明字段约束Kitex 支持情况
api.headerapi.header 设置HTTP 请求回复中的header只支持基本类型和逗号分隔的list支持
api.http_codeapi.http_code 对应HTTP 回复中的status code,200/500等value通常写true,其它情况与不写该注解等价支持
api.bodyapi.body 对应HTTP 回复中的body参数支持
api.none标识该字段在 response中将会被忽略value通常写true,其它情况与不写该注解等价支持
api.js_conv兼容js int64问题,response时需要将int64表示为stringvalue通常写true,其它情况与不写该注解等价支持
api.raw_bodyapi.raw_body 设置该字段content作为HTTP response的完整body支持
api.cookieapi.cookie 设置HTTP 回复中的cookie (string类型,后端自行拼接)支持

举例

// 最终将把BizResponse json序列化之后作为给客户端的返包
struct RspItem{
    1: optional i64 item_id // 默认被以字段名作key序列化,等价于使用gotag `json:"item_id"`
    2: optional string text
}
struct BizResponse {
    1: optional string T  (api.header= 'T')
    // 该字段将填入给客户端返回的header中
    2: optional map<i64, RspItem> rsp_items  (api.body='rsp_items')
    // 一级key = 'rsp_items'
    3: optional i32 v_enum  (api.none = 'true') // 该注解value通常写true,其它情况与不写该注解等价
    4: optional list<RspItem> rsp_item_list  (api.body = 'rsp_item_list')
    // 业务自己指定了HTTPCode,  如果没有指定, baseResp.StatusCode=0 -> HTTPCode=200,  其他 HTTPCode=500
    5: optional i32 http_code  (api.http_code = 'true')    //对应 response HTTP Code
    6: optional list<i64> item_count (api.header = 'item_count') // 当设置header时以逗号相隔的列表
    7: optional string token (api.cookie = 'token') // 对应 response Cookie 字段
}

Method 规范

约束

  • 如果是GET请求,api.serializer定义的序列化方式是无效的
  • 每个URI对应IDL的一个method,通过注解关联,注解不可为空

注解说明

注解类型说明举例Kitex 支持情况
api.getstringget请求,值为HTTP path,uri的语法与gin一致(参考 httprouter)例如 api.get = '/life/client/favorite/collect'支持
api.poststringpost请求,值为HTTP path,uri的语法与gin一致(参考 httprouter)例如 api.post='/life/client/favorite/collect'支持
api.putstringput请求,值为HTTP path,uri的语法与gin一致(参考 httprouter)例如
api.put='/life/client/favorite/collect'
支持
api.deletestringdelete请求,值为HTTP path,uri的语法与gin一致(参考 httprouter)api.delete='/life/client/favorite/collect'支持
api.patchstringdelete请求,值为HTTP path,uri的语法与gin一致(参考 httprouter)api.patch='/life/client/favorite/collect'支持
api.serializerstring客户端请求体序列化方式form, json, thrift, pb暂未支持

举例

service BizService{
    // 例子1: get请求
    BizResponse BizMethod1(1: biz.BizRequest req)(
        api.get = '/life/client/:action/:biz',
        api.baseurl = 'ib.snssdk.com',
        api.param = 'true',
        api.category = 'demo'
    )

    // 例子2:   post请求
    BizResponse BizMethod2(1: biz.BizRequest req)(
        api.post = '/life/client/:action/:biz',
        api.baseurl = 'ib.snssdk.com',
        api.param = 'true',
        api.serializer = 'form'
    )

    // 例子3:   delete请求
    BizResponse BizMethod3(1: biz.BizRequest req)(
        api.post = '/life/client/:action/:biz',
        api.baseurl = 'ib.snssdk.com',
        api.param = 'true',
        api.serializer = 'json'
    )
}