1
1
![ ] ( docs/connect-rpc-scala-logo.png )
2
2
3
- # Connect-RPC ↔ ScalaPB GRPC Bridge
3
+ # REST API for GRPC services with Connect protocol / GRPC Transcoding for Scala
4
4
5
- This library provides a bridge between [ Connect] ( https://connectrpc.com/docs/protocol ) protocol and
6
- [ ScalaPB] ( https://scalapb.github.io ) GRPC compiler for Scala.
7
- It is inspired and takes ideas from [ grpc-json-bridge] ( https://github.com/avast/grpc-json-bridge ) library, which doesn't
8
- seem to be supported anymore + the library doesn't follow a Connect-RPC standard (while being very close to it),
9
- which makes using clients generated with ConnectRPC not possible.
5
+ ![ Maven Central] ( https://img.shields.io/maven-central/v/io.github.igor-vovk/connect-rpc-scala-core_3?style=flat-square&color=green )
10
6
11
- Since integration happens on the foundational ScalaPB level, it works with all common GRPC code-generation projects for
12
- Scala:
7
+ This library makes it easy to expose your GRPC services to the clients using Connect protocol (with JSON messages),
8
+ without Envoy or any other proxy.
13
9
14
- * [ ScalaPB] ( https://scalapb.github.io ) services with ` Future ` monad
15
- * [ fs2-grpc] ( https://github.com/typelevel/fs2-grpc ) , built on top of ` cats-effect ` and ` fs2 `
16
- * [ ZIO gRPC] ( https://scalapb.github.io/zio-grpc/ ) , built on top of ` ZIO `
10
+ In essence, a service implementing the following protobuf definition:
17
11
18
- * Note* : at the moment, only unary (non-streaming) methods are supported.
12
+ ``` protobuf
13
+ syntax = "proto3";
19
14
20
- ## Motivation
15
+ package example;
21
16
22
- As a part of a GRPC adoption, there is usually a need to expose REST APIs.
23
- Since GRPC is based on HTTP2, it's not the best option to expose it directly to the clients, which aren’t
24
- natively supporting HTTP2.
25
- So the most common approach is to expose REST APIs, which will be translated to GRPC on the server side.
26
- There are two main protocols for this:
17
+ service ExampleService {
18
+ rpc GetExample(GetExampleRequest) returns (GetExampleResponse) {
19
+ }
20
+ }
27
21
28
- * [ GRPC-WEB] ( https://github.com/grpc/grpc-web )
29
- * [ Connect] ( https://connectrpc.com/docs/introduction )
22
+ message GetExampleRequest {
23
+ string id = 1;
24
+ }
30
25
31
- They are similar, but GRPC-WEB target is to be as close to GRPC as possible, while Connect is more
32
- web-friendly: it has better client libraries, better web semantics:
33
- content-type is ` application/json ` instead of ` application/grpc-web+json ` , error codes are just normal http codes
34
- instead of being sent in headers, errors are output in the body of the response JSON-encoded, it supports GET-requests,
35
- etc (you can also read
36
- this [ blog post describing why Connect is better] ( https://buf.build/blog/connect-a-better-grpc ) ).
26
+ message GetExampleResponse {
27
+ string name = 1;
28
+ }
29
+ ```
37
30
38
- Both protocols support encoding data in Protobuf and JSON.
39
- JSON is more web-friendly, but it requires having some component in the middle, providing JSON → Protobuf
40
- conversion during the request phase and Protobuf → JSON conversion during the response phase.
31
+ Will be exposed to the clients as a REST API:
41
32
42
- * And this can be tricky to set up* :
33
+ ``` http
34
+ POST /example.ExampleService/GetExample HTTP/1.1
35
+ Content-Type: application/json
43
36
44
- The suggested approach in this case is to use a web-server ([ Envoy] ( https://scalapb.github.io ) ) as a proxy,
45
- supporting translation of both protocols to GRPC.
46
- The general setup of the Envoy in this case allows proxying HTTP/1.1 requests to GRPC, while still having protobuf
47
- messages in the body of the request.
37
+ {
38
+ "id": "123"
39
+ }
48
40
49
- To support JSON, Envoy needs to be configured with Protobuf descriptors, which is not very convenient.
41
+ HTTP/1.1 200 OK
50
42
51
- * That's where this library comes in* :
43
+ {
44
+ "name": "example"
45
+ }
46
+ ```
52
47
53
- It allows exposing GRPC services, built with [ ScalaPB] ( https://scalapb.github.io ) , to the clients
54
- using Connect protocol (with JSON messages), without Envoy or any other proxy, so a web service can expose
55
- both GRPC and REST APIs at the same time on two ports.
48
+ It is compatible with Connect protocol clients (e.g., you can generate clients with [ Connect RPC] ( https://connectrpc.com ) ` protoc ` and
49
+ ` buf ` plugins instead of writing requests manually).
56
50
57
- This simplifies overall setup: simpler CI, fewer network components, faster execution speed.
51
+ In addition, the library supports creating free-form REST APIs,
52
+ using [ GRPC Transcoding] ( https://cloud.google.com/endpoints/docs/grpc/transcoding ) approach
53
+ (full support of ` google.api.http ` annotations is in progress).:
58
54
59
- ## Features of the protocol supported by the library
55
+ ``` protobuf
56
+ syntax = "proto3";
60
57
61
- ``` yaml
62
- versions : [ HTTP_VERSION_1, HTTP_VERSION_2 ]
63
- protocols : [ PROTOCOL_CONNECT ]
64
- codecs : [ CODEC_JSON, CODEC_PROTO ]
65
- stream_types : [ STREAM_TYPE_UNARY ]
66
- supports_tls : false
67
- supports_trailers : false
68
- supports_connect_get : true
69
- supports_message_receive_limit : false
58
+ package example;
59
+
60
+ import "google/api/annotations.proto";
61
+
62
+ service ExampleService {
63
+ rpc GetExample(GetExampleRequest) returns (GetExampleResponse) {
64
+ option (google.api.http) = {
65
+ get: "/example/{id}"
66
+ };
67
+ }
68
+ }
69
+
70
+ message GetExampleRequest {
71
+ string id = 1;
72
+ }
73
+
74
+ message GetExampleResponse {
75
+ string name = 1;
76
+ }
77
+ ```
78
+
79
+ In addition to the previous way of calling it, this endpoint will be exposed as a REST API:
80
+
81
+ ``` http
82
+ GET /example/123 HTTP/1.1
83
+
84
+ HTTP/1.1 200 OK
85
+
86
+ {
87
+ "name": "example"
88
+ }
70
89
```
71
90
91
+ Since integration happens on the foundational ScalaPB level, it works with all common GRPC code-generators:
92
+
93
+ * [ ScalaPB] ( https://scalapb.github.io ) services with ` Future ` monad
94
+ * [ fs2-grpc] ( https://github.com/typelevel/fs2-grpc ) , built on top of ` cats-effect ` and ` fs2 `
95
+ * [ ZIO gRPC] ( https://scalapb.github.io/zio-grpc/ ) , built on top of ` ZIO `
96
+
97
+ * Note* : at the moment, only unary (non-streaming) methods are supported.
98
+
72
99
## Usage
73
100
74
- Installing with SBT (you also need to install particular ` http4s` server implementation):
101
+ For SBT (you also need to install particular ` http4s ` server implementation):
75
102
76
103
``` scala
77
104
libraryDependencies ++= Seq (
@@ -138,7 +165,9 @@ You can read [this](https://zio.dev/guides/interop/with-cats-effect/).
138
165
139
166
## Development
140
167
141
- # ## Running Connect-RPC conformance tests
168
+ ### Connect RPC
169
+
170
+ #### Running Connect-RPC conformance tests
142
171
143
172
Run the following command to run Connect-RPC conformance tests:
144
173
@@ -149,7 +178,7 @@ docker build . --output "out" --progress=plain
149
178
Execution results are output to STDOUT.
150
179
Diagnostic data from the server itself is written to the log file ` out/out.log ` .
151
180
152
- # ## Connect protocol conformance tests status
181
+ #### Connect protocol conformance tests status
153
182
154
183
✅ JSON codec conformance status: __ full conformance__ .
155
184
@@ -159,9 +188,40 @@ Known issues:
159
188
160
189
* Errors serialized incorrectly for protobuf codec.
161
190
162
- # # Future improvements
191
+ #### Supported features of the protocol
192
+
193
+ ``` yaml
194
+ versions : [ HTTP_VERSION_1, HTTP_VERSION_2 ]
195
+ protocols : [ PROTOCOL_CONNECT ]
196
+ codecs : [ CODEC_JSON, CODEC_PROTO ]
197
+ stream_types : [ STREAM_TYPE_UNARY ]
198
+ supports_tls : false
199
+ supports_trailers : false
200
+ supports_connect_get : true
201
+ supports_message_receive_limit : false
202
+ ` ` `
203
+
204
+ ### GRPC Transcoding
205
+
206
+ #### Support
207
+
208
+ - [x] GET, POST, PUT, DELETE, PATCH methods
209
+ - [x] Path parameters, e.g., ` /v1/countries/{name}`
210
+ - [x] Query parameters, repeating query parameters (e.g., `?a=1&a=2`) as arrays
211
+ - [x] Request body (JSON)
212
+ - [ ] Body field mapping, e.g. `body : " request" ` (not supported yet), ` body: "*"` (supported)
213
+ - [ ] Path suffixes, e.g., `/v1/{name=projects/*/locations/*}/datasets` (not supported yet)
214
+
215
+ # ## Future improvements
163
216
164
217
- [x] Support GET-requests ([#10](https://github.com/igor-vovk/connect-rpc-scala/issues/10))
165
- - [ ] Support `google.api.http` annotations (GRPC transcoding) ([#51](https://github.com/igor-vovk/connect-rpc-scala/issues/51))
218
+ - [x] Support `google.api.http` annotations (GRPC
219
+ transcoding) ([#51](https://github.com/igor-vovk/connect-rpc-scala/issues/51))
166
220
- [ ] Support configurable timeouts
167
221
- [ ] Support non-unary (streaming) methods
222
+
223
+ # ## Thanks
224
+
225
+ The library is inspired and takes some ideas from the [grpc-json-bridge](https://github.com/avast/grpc-json-bridge).
226
+ Which doesn't seem to be supported anymore, + also the library doesn't follow a Connect-RPC standard (while being very
227
+ close to it).
0 commit comments