Nest+GRPC场景下适配现有REST响应的GetLocationResponse Proto结构定义
适配原有REST返回结构的GRPC消息定义方案
直接对齐现有REST的返回层级结构,利用proto3原生类型减少业务代码改造量,同时避开proto3的语法限制,具体实现如下:
- 先定义基础坐标结构
原来的嵌套数组内层是两个浮点数存储的纬度、经度,直接拆成结构化字段,比直接传无含义的数字数组可读性更强,也方便后续扩展字段:
// 单个地理坐标点 message Coordinates { // 纬度,对应原数组第一个浮点数 double lat = 1; // 经度,对应原数组第二个浮点数 double lng = 2; }
选double而非float存储坐标,是因为浮点数数组长度变长后容易出现精度偏移,和原有REST返回的浮点数兼容性也最好。
- 处理proto3 map的语法限制
proto3原生map不支持直接把repeated结构作为value类型,需要定义一层中间消息,承载单个资产的全部坐标点,对齐原REST中每个资产ID键下的嵌套数组结构:
// 单个资产对应的坐标点集合 message AssetLocationSet { // 查询时间范围内该资产的所有坐标点列表 repeated Coordinates locations = 1; }
- 补全GetLocationResponse的定义
完全沿用原REST的data字段命名,用原生map类型实现「字符串格式资产ID为键、坐标集合为值」的结构,和原REST返回的层级完全一致:
message GetLocationResponse { // 对应原REST返回的data字段,键为形如"2-2-2-2"格式的资产ID map<string, AssetLocationSet> data = 1; }
- Nest服务端的适配说明
不需要重构原有业务逻辑,只需要在接口返回层做一层薄转换,把原有二维数组格式的坐标转成结构化对象即可,示例转换代码:
// 原有REST接口逻辑产出的原始数据 const originalRestData = { "2-2-2-2": [[39.9042, 116.4074], [39.9142, 116.4174]] } // 转换为GRPC接口要求的返回结构 const grpcResponse = { data: Object.fromEntries( Object.entries(originalRestData).map(([assetId, pointList]) => [ assetId, { locations: pointList.map(([lat, lng]) => ({ lat, lng })) } ]) ) }
- 方案对比
相比手写repeated键值对列表的实现方式,用原生map定义的结构,在Nest的GRPC序列化层会自动输出和普通JS对象完全一致的格式,调用方的取值逻辑和原REST接口几乎无差别,整体改造成本最低。
内容的提问来源于stack exchange,提问作者Jay Desani
相关产品推荐
相关产品推荐

