DSL - Wire 实现-ApiHug101

  🤗 ApiHug × {Postman|Swagger|Api...} = 快↑ 准√ 省↓

  1. GitHub - apihug/apihug.com: All abou the Apihug   
  2. apihug.com: 有爱,有温度,有质量,有信任
  3. ApiHug - API design Copilot - IntelliJ IDEs Plugin | Marketplace

docs/handbook/004_dsl_implement_wire.md · dearxuecom/apihug.com - Gitee.comicon-default.png?t=N7T8https://gitee.com/dearxuecom/apihug.com/blob/master/docs/handbook/004_dsl_implement_wire.md#api

API

Service 概念对应 GRPC 中 Service 供应方。 方法对应具体服务, 对应 OAS中的Paths Object

Service

hope.swagger.svc 定义服务元信息扩展:

extend google.protobuf.ServiceOptions {

    ServiceSchema svc = 1044;
}

message ServiceSchema {
    //The tag of this service
    Tag tag = 1;

    //The base path of this service
    string path = 2;

    // Description of this Service
    string description = 1044;
}
名词用途说明
tag服务标签对象Tag
path服务基础前缀,默认/string
description服务描述string

Method

hope.swagger.operation 定义方法元信息扩展:

extend google.protobuf.MethodOptions {
    Operation operation = 1042;
}

MethodOptions operation 描述, Operation 对象

字段类型说明
request_name输入参数命名单 input 对象在函数中的命名,如果有parameter说明这个不需要,否则会自动推算 _0(1,2,3) 这样子比较丑,帮助代码生成器用
priorityPriority 枚举devops 流程控制,参考
pageable是否支持pageable入参有PageRequest, 结果自动分页包装 参考
raw是否原始值如非原始包装,会统一Result 风格封装
request是否带原始的request比如servlet 协议手动处理
response是否带原始的response比如servlet协议手动处理
session是否带session视具体框架实现
input_plural输入是数组输入对象数组包装 List, 避免proto 对象定义爆炸
out_plural输出是数组输出对象数组包装 List, 避免proto 对象定义爆炸
patternget/put/post/delete/patch目前只支持者几个对象 oneof, http action 语义
parameters参数对象是一个 Parameter 数组对象
Priority 枚举类型

开发流程审批规范:

字段类型说明
LOW重要度低开发者交叉审批
MIDDLE重要度中等开发组长审批
HIGH重要度高项目管理者审批
CRITICAL重要度很高总监审批
FATAL重要度致命CTO审批
Parameter 参数对象

⚠️ 0.2.6-RELEASE 以后版本: 如果是 GET 类型

  1. 禁止 input type 定义非引用对象, 复杂对象一律通过引用对象定义
  2. 预定义对象(number/string/date 等)可以通过 parameters 定义

否则在 wire 阶段会报错:

proto illegal define @service.proto  TestService#GetUserInfo

It is a GET action, only support [google.protobuf.Empty] input or an reference Object while we got: google.protobuf.IntValue

all primitive types(int,long,date etc) please define in the [parameters] part, otherwise may mess the parameter judge!

因为在 input 定义, 然后又在 parameters 定义(没有语法错误), 导致难判断, 到底用那个?

在非 post 传递, 非 body 对象时候使用,

  1. RPC 定义 input 最好是个 Empty, 所有参数都在 hope.swagger.operation#parameters 中定义(⚠️最标准做法⚠️)
  2. 如果是 Message 这个 Message 也会被当做 parameter 而非 RequestBody!
  3. 可以承接多个对象,
    1. 可以是原始对象: int/string/date/uuid 等,
    2. 或者是封装对象 MessageEnum
rpc DeleteOrder (google.protobuf.Empty) returns (google.protobuf.StringValue) {
        option (hope.swagger.operation) = {
            post: "/delete-order";
            description: "删除订单",
            tags: "order";
            priority: CRITICAL;
            parameters: {
                parameter: {
                    name: "order-id";
                    in: QUERY;
                    scheme: {
                        type: STRING;
                        empty: {
                            value: false;
                        }
                        field_configuration: {
                            path_param_name: "orderId"
                        }
                    }
                }
            }
        };

};
字段类型说明
name参数名词写标准点, 转换成方法字段会自动推理, 比如 hello-world --> helloWorld
in参数类型参考下面枚举
schemeJSONSchemaJSONSchema
plural是否列表boolean
IN 参数

类型 OAS 参数对象

字段类型说明
QUERYparameterpath/arg1=123, arg1 参数
HEADERHTTP 协议头比如JWT, 或者扩展字段
PATH路径/path/{arg}/helloarg 记得必须是 {}, 目前没有强制校验
COOKIE来自cookie 参数视底层框架
SESSION来自session 参数视底层框架

Resource

Message

hope.swagger.schema 为 MessageOptions 用来描述类型对象: OAS Schema对象

extend google.protobuf.MessageOptions {
    Schema schema = 1042;
}
message QueryTenantRoleRequest {
  option (hope.swagger.schema) = {
    json_schema: {
      description: "查询角色列表";
    };
  };
}

消息整体的描述, 侧重消息的基本描述 descriptionexamplediscriminator,read_onlyexternal_docs 当前未做解析 ⚠️。

JSONSchema

字段描述 hope.swagger.field 为 FieldOptions, 扩展 JSONSchema 上面:

extend google.protobuf.FieldOptions {
    JSONSchema field = 1042;
}

扩展字段:

字段类型说明
descriptionstring描述
defaultstring默认值
examplestring示例
multiple_ofgoogle.protobuf.DoubleValue倍数
maximumgoogle.protobuf.DoubleValue最大值
exclusive_maximumgoogle.protobuf.BoolValue区间是否包含最大值
minimumgoogle.protobuf.DoubleValue最小值
exclusive_minimumgoogle.protobuf.BoolValue区间是否包含最小值
max_lengthgoogle.protobuf.UInt64Value最大长度,string类型
min_lengthgoogle.protobuf.UInt64Value最小长度,string类型
max_itemsgoogle.protobuf.UInt64Valuerepeated 集合类型字段,最多元素数目
min_itemsgoogle.protobuf.UInt64Valuerepeated 集合类型字段,最多元素数目
unique_itemsgoogle.protobuf.BoolValuerepeated 集合类型字段,元素是否唯一,List vs Set
typeJSONSchemaTypeHint😢
formatstringJSONSchemaFormat
field_configurationFieldConfiguration✋ 参考
emptygoogle.protobuf.BoolValue是否可以为空-校验
patternstringvalidation 扩展:正值表达式验证 javax.validation.constraints.Pattern("^A-z$")
assertgoogle.protobuf.BoolValuevalidation 扩展: javax.validation.constraints.AssertTrue\AssertFalse
decimal_maxstringvalidation 扩展:javax.validation.constraints.DecimalMax(value = "0.0", inclusive = false)
decimal_minstringvalidation 扩展:javax.validation.constraints.DecimalMin(value = "0.0", inclusive = false)
digits_integergoogle.protobuf.Int32Valuevalidation 扩展:javax.validation.constraints.Digits(integer=3, fraction=2)
digits_fractiongoogle.protobuf.Int32Valuevalidation 扩展:javax.validation.constraints.Digits(integer=3, fraction=2)
emailgoogle.protobuf.BoolValuevalidation 扩展:javax.validation.constraints.Email
time_constraint_typeTimeConstraintTypevalidation 扩展:枚举参考下面 TimeConstraintType
date_formatDateFormat日期format: 日期枚举类型参考下面 DateFormat
customized_date_formatstring定制日期类型:符合标准日期定义规范(未强校验)
mockMockMock规则 🏗️
read_onlybool未用 🚧
extensionsmap<string, google.protobuf.Value>未用 🚧,扩展说明
enumrepeated string未用 🚧
requiredrepeated string未用 🚧, 范围选择,通过枚举对象实现
arrayrepeated string未用 🚧, 列表元素可选范围,通过枚举对象实现
refstring未用 🚧, 外部对象引用,需全路径指定 parameter配置时,如引用 Enum 对象
titlestring未用 🚧, 标题, 字段名称替代
max_propertiesgoogle.protobuf.UInt64Value未用 🚧,Map元素最多key?
min_propertiesgoogle.protobuf.UInt64Value未用 🚧,Map元素最多key?

⚠️ 由于框架层引入常量设计机制, 所以很多需要通过 enumrequiredarray 控制的,通过枚举控制均都可弱化和替代掉。

FieldConfiguration
message FieldConfiguration {
        string path_param_name = 47;
}

Parameter 参数对象 中定义灵活对象时, 在路径参数上对象和宿主语言命名有时候有冲突; 比如 参数 {user-id} 在java 中无法使用 user-id 命名参数, 中划线 - 为字段命名非法字符,如果不设定,会隐式的转换成 userId, 但是同时也可以自己定义:

field_configuration: {
    path_param_name: "orderIdAnother"
}
JSONSchemaFormat

为避免复杂度, JSONSchemaTypeHint 自 0.3.3.RELEASE 被合并到 format

和 format 合并了OpenApi format (OpenAPI Specification v3.1.0,2023-12) + 部分自有扩展。

一般 Message 字段定义已经包含 显式 类型定义: 内置类型或者引用类型, 但是在 option 里的定义无法设定,比如在Parameter 参数对象

所以需要这里 隐式 的制定类型, 或者需要强制将内置类型对象转换成语言特定对象, 比如 string 隐式 成一个 DateTime, 方便代码生成器推导宿主语言对象类型。

字段类型说明OAS format
BOOLEANbool类型booleanbool
INTEGERinteger整型int32
DOUBLE数字doubledouble
STRINGstring字符串-
FLOATfloat浮点类型float
BIG_DECIMALbigDecimal精度数字big-decimal
LONGlong长整型int64
DATEdate日期date
DATE_TIMEdateTime日期时间date-time
TIMEtime时间time
UUIDuuidUUID 对象uuid
PASSWORDpassword密码对象password
EMAILemail邮箱对象email
BINARYbinary文件对象binary

⚠️ 谨慎使用,这也是为什么我们推崇,复杂对象通过 Message 定义, 避免这种 Ad-hoc Path/Query/Header 隐式推断; 固然通过强制 仅支持 post可以尽量避免, 但是 ApiHug 还是兼容了这些古老的做法。

TimeConstraintType
字段类型说明
FUTURE时间校验@javax.validation.constraints.Future
FUTURE_OR_PRESENT时间校验@javax.validation.constraints.FutureOrPresent
PAST时间校验@javax.validation.constraints.Past
PAST_OR_PRESENT时间校验@javax.validation.constraints.PastOrPresent
DateFormat 枚举类型

预定义formatter java.time.format.DateTimeFormatter

或自定义 customized_date_format, 最好用预定义的, 通过了校验测试。

如果使用 customized_date_format 推导宿主语言类型有不确定性⚠️, 而预定义可以分化: DateTimeTimeDate 更细的分类 ⭐⭐⭐。

字段类型说明
BASIC_ISO_DATEyyyyMMdd比如 20111203 类型 LocalDate
ISO_LOCAL_DATEyyyy-MM-dd比如 2011-12-03 类型 LocalDate
ISO_LOCAL_TIMEHH:mm:ss比如 10:15:30 类型 LocalTime
ISO_LOCAL_DATE_TIMEyyyy-MM-dd T HH:mm:ss比如 2011-12-03T10:15:30 类型 LocalDateTime
YYYY_MM_DD_HH_MM_SSyyyy-MM-dd HH:mm:ss类型 LocalDateTime
YYYY_MM_DD_HH_MM_SS_SSSyyyy-MM-dd HH:mm:ss:SSS类型 LocalDateTime
SLASH_YYYY_MM_DDyyyy/MM/dd类型 LocalDate
SLASH_YYYY_MM_DD_HH_MM_SSyyyy/MM/dd HH:mm:ss类型 LocalDateTime
SLASH_YYYY_MM_DD_HH_MM_SS_SSSyyyy/MM/dd HH:mm:ss:SSS类型 LocalDateTime
HH_MMHH:mm类型 LocalTime

自定义格式日期时间判断方式:

  1. Date 判断包含任何一个:
    1. yyyy
    2. MM
    3. dd
  2. Time 判断包含任何一个:
    1. HH
    2. mm
    3. ss
    4. SSS

Enum

Hope 框架里,引入了 枚举常量的设计, 大大减少了常量的硬编码, Enum 在宿主语言 JavacGo 等都有完整的支持。

同时在 Enum 上又扩展了:错误码 Error + Authority类型。

hope.swagger.enm 为 EnumOptions 用来描述常量对象:

extend google.protobuf.EnumOptions {
    JSONSchema enm = 1042;
}

hope.constant.field 为 EnumValueOptions 用来描述常量值对象:

extend google.protobuf.EnumValueOptions {
  Meta field = 37020;
}
message Meta {

  int32 code = 1;
  string message = 2;
  string cn_message = 3;

  Error error = 4;
}
名词用途说明
code错误代码int
message错误信息string
cn_message错误信息(中)string
Error

错误枚举,在枚举上扩展 Error error = 4; 字段包含;

字段类型说明
titlestring简单标题
tipsstring提示
http_statusHttpStatusHttp 错误码
phasePhase阶段,参考下面文档
severitySeverity严重程度,参考下面文档
错误阶段
字段类型说明
CONTROLLERController表单层
SERVICEService服务层
DOMAINDomain领域层
错误严重性
字段类型说明
LOW低,无影响
WARN警告警告,业务错误可重试
ERROR错误错误,业务无法进行
FATAL灾难灾难,数据破坏
Authority

Authority 为标准 Enum 类型, 在 Wire项目的元信息中指定 authority meta

 "authority" : {
    "enumClass" : "hope.we.proto.infra.enumeration.authority.SystemAuthorityEnum",
    "codePrefix" : 11000000
  }
Map

对于Map类型字段,处理比较头疼, 如果混合宿主语言特征,会非常棘手, 比如 key, value 都有 Generic 特性。 综合:OAS Dictionaries, HashMaps and Associative Arrays, Protobuf: Maps Features 如下约束:

  1. Key, Value 不能 Generic 也就是只能固定类型, 宿主语言内的变幻, 无法控制,比如子类判断。
  2. 参考 Protobuf Map 将 key, value 转换成独立 Message 对象。

Meta

项目基本元信息 resources\hope-wire.json

{
  "packageName": "hope.we",
  "name": "bigger-project-proto",
  "application": "bigger-project",
  "domain": "hope",
  "persistence" : {
    "identifyType" : "LONG",
    "tenantType" : "LONG"
  },
  "authority" : {
    "enumClass" : "hope.we.proto.infra.enumeration.authority.SystemAuthorityEnum",
    "codePrefix" : 11000000
  },
  "createdAt": "2023-01-01",
  "createdBy" : "Aaron",
  "api": {
    "openapi" : "3.0.1",
    "info" : {
      "contact" : {
        "name" : "developer@apihug.com",
        "url" : "https://github.com/hope/apihug",
        "email" : "developer@apihug.com"
      }
    },
    "externalDocs" : {
      "description" : "Hope is the best thing",
      "url" : "https://github.com/hope/apihug/"
    },
    "tags" : [ {
      "name" : "tenant",
      "description" : "租户操作"
    }, {
      "name" : "platform",
      "description" : "平台操作"
    }]
  }
}
名称说明类型值(默认)备注
packageName包名Sting必须项目包名,符合java包命名规范,不可包含预留: wirestub 关键字
name项目名称Sting必须项目标识,符合 artifact ID, 小写,中文标识,proto后缀比如: user-info-proto
application应用项目Sting必须和proto配套项目名称, 一般是name 去掉 proto 后缀比如: user-info
module模块名称Sting必须用在运行时 service locator定位, 如无设置 name替代, domain+module需要保证运行时唯一
domain领域名Sting必须属于领域
description描述Sting可选描述
persistence.identifyType数据库,账号类型Sting可选数据设计,有账号ID标识时启用, STRING|INTEGER|LONG
persistence.tenantType数据库,租户类型Sting可选数据设计,有多租户标识时启用, STRING|INTEGER|LONG
authority.enumClass验权,权限类型枚举Sting可选验权设计,权限枚举类,必须在 proto 有定义,编译时校验
authority.codePrefix验权,权限标识段Long可选验权设计,多模块下,权限标识代码分段,避免重复,比如100000 为user权限区间段,100001为第一个

OAS

只包含基本的 OAS 说明:

  1. openapi OAS 兼容 版本
  2. info OAS 基本 Info
  3. tag OAS 标签 Tag

⚠️其他信息,请勿这里定义,定义也会被忽略!

文件上传

协议定义✏️:

  1. 方法:POST (必须)
  2. consumes 类型: multipart/form-data (必须)
  option (hope.swagger.operation) = {
    post: "/upload-meta";
    consumes: "multipart/form-data";
  };

字段定义 format: "binary":

  // Binary format meaning a file.
  string file = 5 [(hope.swagger.field) = {
    format: "binary"
  }];

  repeat bytes files = 6;

支持单文件, 多文件批量上传;

  1. format: "binary" 自身类型 string 将被忽略;
  2. bytes 类型,自动被识别为 binary 文件类型;
  3. 支持 repeat 多文件批量上传;
  4. 支持附带属性。
message SampleUploadRequest {
  option (hope.swagger.schema) = {
    json_schema: {
      description: "An example to upload a single file";
    };
  };

  string name = 4 [(hope.swagger.field) = {
    description: "new name of this upload file";
    example: "just_another_file"
    max_length: {
      value: 64
    }
  }];


  // Binary format meaning a file.
  string an_file = 5 [(hope.swagger.field) = {
    format: "binary"
  }];
}

Command

配置 wire 项目模块 build.gradle

plugins {
    id "java-library"
    id "com.apihug.wire"
}


hopeWire {
    verbose = true
}

刷新本模块的 gradle 后, 在task 列表可以看到 wire 命令被添加进来, 运行此模块下的 wire 命令 gradlew wire

  1. main\wire 生成运行时代码
  2. main\resources 生成编译元信息
名称说明类型(默认)备注
disable插件调试booleanfalse依赖注入完成,不添加额外 Task,调试测试用
smock插件调试booleanfalse上面步骤完成 + Task 注入完毕, 不执行最后的生成动作,调试测试用
debug插件调试booleanfalse上面步骤完成 + 执行生成动作第一阶段准备, 不最终触发动作,调试测试用
restrict非扩展类型是否隐式转换booleanfalsegoogle.protobuf.Timestamp 定义是否支持默认转换到 local time
verbose执行过程log打开booleanfalse出问题打开,过程全log打开调试
generatedVersion是否携带生成插件版本booleanfalse生成代码 @Generated 说明是否携带插件版本
generatedTime是否携带生成时间戳booleanfalse生成代码 @Generated 说明是否携带生成时间戳
pluginMainVersion插件辅助版本Stringwire 插件版本运行时依赖版本,非必要勿设置,Apihug整体包BOM发行,勿手动设置这个版本
pluginMainClass插件辅助入口MainString如非扩展了插件,勿设置
local本地插件booleanfalse依赖自己扩展插件,如不是,勿设置
protocVersionprotoc版本StringWire发行时候自带,可以自行定义(可能导致不兼容风险)
grpcVersiongrpc版本StringWire发行时候自带,可以自行定义(可能导致不兼容风险)
keepProto是否包含proto原编译文件booleanfalsewire项目发行时候是否携带protoc编译结果,除项目间有深度逻辑依赖,共享的应局限在POJO对象这层
wireProtoBufGradlePluginVersionprotobuf插件版本String未启用
validationVersionValidation版本String未启用
swaggerVersionSwagger版本String未启用

Refer

  1. The OpenAPI Specification
  2. OpenAPI Specification Version 3.1.0 since 2023.
  3. Spring file upload
  4. ApiHug101-Bilibili
  5. ApiHug101-Youtube

秒懂 ApiHug -005 加个对象

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值