Skip to content

Commit 8fade30

Browse files
Merge pull request #13 from oslabs-beta/library
Library
2 parents fb5461a + 0679bf1 commit 8fade30

File tree

4 files changed

+325
-148
lines changed

4 files changed

+325
-148
lines changed

README.md

Lines changed: 138 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -2,117 +2,117 @@
22
![badge](https://img.shields.io/badge/version-v2.0.3.beta%20release-brightgreen)
33
![badge](https://img.shields.io/badge/build-passing-green?labelColor=444444)
44
![badge](https://img.shields.io/badge/license-Apache--2.0-green)
5-
5+
66
Full featured integration library for React and gRPC-Web. Core functions include: packaging the generated proto messages and client stubs, a unified API of gRPC call methods that support Google's and Improbable's gRPC-web specs for unary, client streaming, server streaming and bi-directional streaming.
7-
7+
88
# Getting Started
99
## Install
1010
```
1111
npm install --save reactrpc
1212
```
13-
13+
1414
## 1. Define the Services
1515
Create proto files as the schema for your Server and Client Stubs. It should define the gRPC call methods needed to communicate between the Server and Browser. These files will be used to give your components superpowers -- Remote Procedure Call (RPC) methods.
16-
16+
1717
`helloworld.proto`
1818
```protobuf
1919
syntax = "proto3";
20-
20+
2121
package helloworld;
22-
22+
2323
service Greeter {
2424
rpc SayHello (HelloRequest) returns (HelloReply);
2525
}
26-
26+
2727
message HelloRequest {
2828
string name = 1;
2929
}
30-
30+
3131
message HelloReply {
3232
string message = 1;
3333
}
3434
```
3535
`book_service.proto`
3636
```protobuf
3737
syntax = "proto3";
38-
38+
3939
package examplecom.library;
40-
40+
4141
message Book {
4242
int64 isbn = 1;
4343
string title = 2;
4444
string author = 3;
4545
}
46-
46+
4747
message GetBookRequest {
4848
int64 isbn = 1;
4949
}
50-
50+
5151
message QueryBooksRequest {
5252
string author_prefix = 1;
5353
}
54-
54+
5555
service BookService {
5656
rpc GetBook(GetBookRequest) returns (Book) {}
5757
rpc QueryBooks(QueryBooksRequest) returns (stream Book) {}
5858
}
59-
59+
6060
```
61-
61+
6262
## 2. Generate a Protobuf Messages and Client Service Stub
63-
63+
6464
In order to pass superpowers to our Browser, we first need to package our .proto file.
65-
65+
6666
## For Google's implementation:
6767
To generate the protobuf messages and client service stub class from your
6868
`.proto` definitions, we need the `protoc` binary and the
6969
`protoc-gen-grpc-web` plugin.
70-
70+
7171
You can download the `protoc-gen-grpc-web` protoc plugin from Google's
7272
[release](https://github.com/grpc/grpc-web/releases) page:
73-
73+
7474
If you don't already have `protoc` installed, you will have to download it
7575
first from [here](https://github.com/protocolbuffers/protobuf/releases).
76-
76+
7777
Make sure they are both executable and are discoverable from your PATH.
78-
78+
7979
For example, in MacOS, you can do:
80-
80+
8181
```
8282
$ sudo mv ~/Downloads/protoc-gen-grpc-web-1.0.7-darwin-x86_64 \
8383
/usr/local/bin/protoc-gen-grpc-web
8484
$ chmod +x /usr/local/bin/protoc-gen-grpc-web
8585
```
86-
86+
8787
When you have both `protoc` and `protoc-gen-grpc-web` installed, you can now
8888
run this command:
89-
89+
9090
```sh
9191
$ protoc -I=. helloworld.proto \
9292
--js_out=import_style=commonjs:. \
9393
--grpc-web_out=import_style=commonjs,mode=grpcwebtext:.
9494
```
95-
95+
9696
After the command runs successfully on your `[name of proto].proto` you should see two generated files `[name of proto]_pb.js` which contains the messages and `[name of proto]_grpc_web_pb.js` that contains the services:
97-
97+
9898
For instance the `helloworld.proto` file will generate to:
9999
- messages : `helloworld_pb.js`
100100
- services : `helloworld_grpc_web_pb.js`
101101

102102
## For Improbable's implementation:
103-
103+
104104
For the latest stable version of the ts-protoc-gen plugin:
105-
105+
106106
```
107107
npm install ts-protoc-gen
108108
```
109-
109+
110110
Download or install protoc (the protocol buffer compiler) for your platform from the github releases page or via a package manager (ie: brew, apt).
111-
111+
112112
Download protoc from [here](https://github.com/protocolbuffers/protobuf/releases)
113-
113+
114114
When you have both `protoc` and `ts-protoc-gen` installed, you can now run this command:
115-
115+
116116
```
117117
--plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts \
118118
-I ./proto \
@@ -121,87 +121,87 @@ When you have both `protoc` and `ts-protoc-gen` installed, you can now run this
121121
./proto/examplecom/library/book_service.proto
122122
```
123123
After the command runs successfully on your `[insert_name].proto` you should see two generated files `[insert_name]_pb.js` which contains the messages and `[insert_name]_pb_service.js` that contains the services:
124-
124+
125125
For instance for the helloworld.proto you should see:
126126
- messages : `book_service_pb.js`
127127
- services : `book_service_pb_service.js`
128-
129-
128+
129+
130130
## 3. Create proxy server
131-
131+
132132
In order for gRPC-web to communicate with other gRPC servers, it requires a proxy server as a translation layer to convert between gRPC-web protobuffers and gRPC protobuffers. Links to examples on how to set those up can be found [here](https://github.com/grpc/grpc-web/tree/master/net/grpc/gateway/examples/helloworld) (Envoy proxy) and [here](https://github.com/improbable-eng/grpc-web/tree/master/go/grpcwebproxy) (Improbable's proxy)*
133-
133+
134134
>*Note: To enable bidirectional/client-side streaming you must use Improbable's spec and its proxy with websockets enabled
135-
135+
136136
## 4. Set up React component
137-
137+
138138
Require in the reactRPC library and protobuf files in your React JSX file. Run the build method with the following params: the message, the services and the URL to the proxy server endpoint.
139-
139+
140140
## Google's Implementation
141141
```javascript
142-
const { reactRPC } = require("reactRPC")
143-
142+
const { googleRPC } = require("reactRPC")
143+
144144
const messages = require("helloworld_pb.js")
145-
145+
146146
const services = require("helloworld_grpc_web_pb.js")
147-
147+
148148
const URL = "http://" + window.location.hostname + ":8080"
149-
150-
reactRPC.build(messages, services, URL)
149+
150+
googleRPC.build(messages, services, URL)
151151
```
152-
Export the reactRPC component by passing it as an argument into the reactRPC wrapper as follows:
153-
152+
Export the googleRPC component by passing it as an argument into the reactRPC wrapper as follows:
153+
154154
```javascript
155-
export default reactRPC.wrapper(<your component>);
155+
export default googleRPC.wrapper(<your component>);
156156
```
157-
157+
158158
## Improbable's Implementation
159159
```javascript
160160
const { improbRPC } = require("reactRPC")
161-
161+
162162
const messages = require("book_service_pb.js")
163-
163+
164164
const services = require("book_service_pb_service.js")
165-
165+
166166
const URL = "http://" + window.location.hostname + ":8080"
167-
167+
168168
improbRPC.build(messages, services, URL)
169-
169+
170170
```
171-
172-
Export the reactRPC component by passing it as an argument into the improbRPC wrapper as follows:
173-
171+
172+
Export the improbRPC component by passing it as an argument into the improbRPC wrapper as follows:
173+
174174
```javascript
175175
export default improbRPC.wrapper(<your component>);
176176
```
177-
177+
178178
## 5. Define a message
179-
179+
180180
We define a request message by creating an object with the keys as the message field along with a `msgType` property specifying a message that we set in the proto file. Here is an example of a `HelloRequest` message in the `helloworld.proto` file :
181-
182-
181+
182+
183183
```javascript
184184
const message = { name: "John", lastName: "Doe", msgType: "HelloRequest" }
185185
```
186-
186+
187187
## 6. Create the function
188-
188+
189189
We define a function by listing its service and procedure calls on `this.props`. We then pass in the message we defined above, and an object with any metadata data required (learn more about metadata [here](https://github.com/grpc/grpc-go/blob/master/Documentation/grpc-metadata.md)). For unary calls a third parameter of a callback is required while streaming calls have built in event listeners.
190-
191-
190+
191+
192192
```javascript
193193
// unary call:
194-
194+
195195
this.props.Greeter.sayHello(
196196
message,
197197
{},
198198
(err, response) => {
199199
console.log(response)
200200
}
201201
);
202-
202+
203203
// streaming call
204-
204+
205205
const stream = this.props.Greeter.sayRepeatHello(
206206
message,
207207
{}
@@ -210,7 +210,73 @@ const stream = this.props.Greeter.sayRepeatHello(
210210
console.log(res.getMessage());
211211
});
212212
```
213-
213+
214214
>ReactRPC library supports unary, client-side, server-side and bi-directional streaming.
215-
216-
Check out the [documentation website] for more details on defining messages and sending functions!
215+
216+
217+
# Additional details
218+
219+
## Nested Messages
220+
221+
In the proto file, messages can be nested in other messages. In this example, the FullName message is used in the TestNested message:
222+
223+
```protobuf
224+
message FullName{
225+
string name = 1;
226+
string lastName = 2;
227+
}
228+
229+
message TestNested{
230+
FullName myName = 1;
231+
}
232+
```
233+
234+
## Event listeners for Streams
235+
236+
For flexibility ReactRPC models both Google and Improbable's eventlisteners:
237+
238+
>Google's Implementation
239+
```Javascript
240+
const stream = this.props.Greeter.sayRepeatHello(
241+
message,
242+
{}
243+
);
244+
stream.on("data", res => {
245+
console.log(res.getMessage());
246+
});
247+
stream.on("status", res => {
248+
console.log(res.getMessage());
249+
});
250+
stream.on("end", res => {
251+
console.log(res.getMessage());
252+
});
253+
```
254+
Improbable's Implementation
255+
```Javascript
256+
const stream = this.props.Greeter.sayRepeatHello(
257+
message,
258+
{}
259+
);
260+
stream.onMessage(res => {
261+
console.log(res.getMessage());
262+
});
263+
stream.onHeaders(res => {
264+
console.log(res.getMessage());
265+
});
266+
stream.onEnd(res => {
267+
console.log(res.getMessage());
268+
});
269+
```
270+
271+
>For `improbable's` bidirectional streaming there is client.send that opens the stream and client.finishSend to close the stream as follows:
272+
273+
```Javascript
274+
const stream = this.props.Greeter.sayRepeatHello(
275+
message,
276+
{}
277+
);
278+
stream.send({ name: "John", lastName: "Doe", msgType: "SayHelloRequest" });
279+
});
280+
stream.finishSend({ name: "John", lastName: "Doe", msgType: "SayHelloRequest" });
281+
});
282+
```

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ReactRPC",
3-
"version": "1.0.0",
3+
"version": "1.0.2",
44
"description": "Full featured integration library for React and gRPC-web",
55
"main": "index.js",
66
"scripts": {

0 commit comments

Comments
 (0)