使用 Protobuf 设计 REST API

关于数据序列化与传输格式的选型:https://www.jianshu.com/p/3504d4643dba

 

概述

一个设计的好的 REST API 接口,需要一个严格的接口定义。本文试图使用 Protobuf 作为接口设计语言,设计 API。

创建文件,main/proto/Login.proto

syntax = "proto3";
package org.wcy123.api;
option java_outer_classname = "Protos";
message LoginRequest {
    string name = 1;
    string password = 2;
}
message LoginResponse {
    enum LoginResult {
        DEFAULT = 0;
        OK = 1;
        FAIL = 2;
    }
    LoginResult result  = 1;
}

然后创建一个 Bean 用于转换 JSON 到 Java 对象

@Bean
ProtobufHttpMessageConverter protobufHttpMessageConverter() {
  return new ProtobufHttpMessageConverter();
}

然后创建 Controller

@RestController
@Slf4j
public class MyRestController {
    @RequestMapping(path = "/login", method = POST)
    public ResponseEntity<Protos.LoginResponse> login(HttpServletRequest request,
            HttpServletResponse response, @RequestBody Protos.LoginRequest command) {
        log.info("input is {}", new JsonFormat().printToString(command));
        return ResponseEntity.ok().body(Protos.LoginResponse.newBuilder()
                .setResult(Protos.LoginResponse.LoginResult.OK)
                .build());
    }
}

Protos.LoginRequest 和 Protos.LoginResponse 是自动生成的

测试程序

curl -v -s -H 'Content-Type: application/json' -H 'Accept: application/json' http://127.0.0.1:8080/login -d '{"name":"wcy123", "password":"123456"}'
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
> POST /login HTTP/1.1
> Host: 127.0.0.1:8080
> User-Agent: curl/7.43.0
> Content-Type: application/json
> Accept: application/json
> Content-Length: 39
>
* upload completely sent off: 39 out of 39 bytes
< HTTP/1.1 200
< Content-Type: application/json
< Transfer-Encoding: chunked
< Date: Tue, 22 Nov 2016 10:03:43 GMT
<
* Connection #0 to host 127.0.0.1 left intact
{"result": "OK"}

从外部看开,请求和响应都是 JSON,PB 只是内部实现。注意要加 Content-Type:application/json 和 Accept: application/json 两个 header。

Protobuf 支持的常用数据类型和 JSON之间的转换关系。

syntax = "proto3";
package org.wcy123.api;
message Root {
    Obj1 obj1 = 1;
    bytes base64 = 2;
    enum AnEnum { FOO_BAR = 0 ; GOOD = 2; BYE = 3;};
    AnEnum anEnum = 3;
    repeated string anArray = 4;
    bool aBoolean = 5;
    string aString = 6;
    int32 aInt32 = 7;
    uint32 aUint32 = 8;
    fixed32 aFixed = 9;
    int64 aInt64 = 10;
    uint64 aUint64 = 11;
    fixed64 aFixed64 = 12;
    float aFloat = 13;
    double aDouble = 14;
    //Timestamp aTimestamp = 15;
    //Duration aDuaration = 16;
    oneof anOneOf {
        string eitherString = 17;
        int32 orAnInt = 18;
    }
}
message Obj1{
    string name = 1;
}

我写了一个例子,用于实验所有的改动,具体文档,参考 https://developers.google.com/protocol-buffers/docs/proto3#json
这个转换成 JSON 是下面这个样子。

{
  "obj1": {
    "name": "YourName"
  },
  "base64": "abc123!?$*&()'-=@~",
  "aBoolean": true,
  "aString": "hello world",
  "aInt32": -32,
  "aUint32": 32,
  "aFixed": 64,
  "aInt64": -64,
  "aUint64": 64,
  "aFixed64": 128,
  "aFloat": 1,
  "aDouble": 2,
  "eitherString": "Now It is a String, not an integer"
}

注意到 oneOf 使用字段名称来表示哪一个字段被选择了。

细节

依赖关系

<dependency>
  <groupId>com.google.protobuf</groupId>
  <artifactId>protobuf-java</artifactId>
  <version>3.0.0-beta-1</version>
</dependency>

需要插件

<plugin>
  <groupId>org.xolstice.maven.plugins</groupId>
  <artifactId>protobuf-maven-plugin</artifactId>
  <version>0.5.0</version>
  <configuration>
    <protocExecutable>/usr/local/bin/protoc</protocExecutable>
  </configuration>
  <executions>
    <execution>
      <goals>
        <goal>compile</goal>
        <goal>test-compile</goal>
      </goals>
    </execution>
  </executions>
</plugin>

默认值的处理

注意到在 OK 和 FAIL 前面,我放了一个无用的 DEFAULT 值。如果没有这个值,那么 JSON 转换的时候,认为 result 是默认值,那么就不会包含这个字段。

  • 如果要强制包含这个字段,那么填一个无用的默认值,占位,永远不用这个默认值。
  • 如果想节省带宽,默认值就不传输的话,那么就保留这个行为。接收端需要判断如果字段不存在,就使用默认值。

不能识别的 JSON 字段

PB 忽略不能识别的字段。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Protobuf 是一种由 Google 开发的用于序列化结构化数据的协议。Protobuf Java API 是用于在 Java 中操作和使用 Protobuf 的开发者接口。 Protobuf Java API 提供了一种简单而高效的方式来处理和管理 Protobuf 数据。使用 Protobuf Java API,开发者可以定义数据模型,将数据序列化成二进制格式,并可以将二进制数据反序列化为对象实例。 通过 Protobuf Java API,开发者可以轻松地创建 Protobuf 消息,定义消息字段和类型,并根据自己的需求对消息进行定制。API 还提供了一些实用的方法,例如对消息进行合并、拷贝和克隆。开发者还可以使用 API 将消息序列化为二进制数据,并通过网络传输或存储到磁盘等介质中。 使用 Protobuf Java API 还可以实现高效的数据交互。由于 Protobuf 的数据结构紧凑且二进制化,相比于 XML 和 JSON 等文本格式,Protobuf 可以显著减少数据的大小,从而减少网络传输的负载和提高传输效率。在需要对大量数据进行交换和处理的场景中,Protobuf Java API 可以提供快速和高效的数据序列化和反序列化功能。 此外,Protobuf Java API 还支持版本兼容性。当数据结构发生变化时,可以使用 Protobuf Java API 进行兼容升级,而无需更改现有的代码和数据格式。这样可以保持系统的平滑过渡和持续演进,减少了对系统的影响和维护成本。 总之,Protobuf Java API 提供了一种强大且灵活的方式来处理和管理结构化数据。它简化了数据的序列化和反序列化过程,提供了高效的数据交互方式,并支持版本兼容性。无论是在网络通信、分布式系统、大数据处理还是移动应用开发等领域,Protobuf Java API 都是一种非常有用的工具。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值