Sử dụng gRPC-Web để gọi API từ grpc server trong ứng dụng React JS

Sử dụng gRPC-Web để gọi API từ grpc server trong ứng dụng React JS

Bài viết này sẽ trả lời cho các câu hỏi gRPC-Web là gì? Tại sao cần sử dụng nó? Và cách sử dụng gRPC-Web trong một ứng dụng React JS như thế nào thông qua một demo nho nhỏ. Ok, bắt đầu thôi nào!

Why?

Từ khi bắt đầu lập trình ứng dụng web / mobile mình đã biết đến những ưu điểm tuyệt vời của REST so với SOAP trong việc giao tiếp với backend thông qua APIs, vì thế mà mình chỉ sử dụng mỗi REST cho đến khi được công ty yêu cầu tìm hiểu về RPC - một kiến trúc API khác được thiết kế tập trung vào action thay vì resource như REST. Nếu bạn cũng ở trong hoàn cảnh giống tôi chắc hẳn bạn cũng sẽ tự đặt ra cho mình câu hỏi “tại sao lại phải chuyển qua sử dụng RPC thay vì REST ?” Để trả lời được cho câu hỏi này thì bạn cần phải tìm hiểu thêm về anh Protobuf này, bởi vì gRPC sử dụng nó và có nhiều lý do để chọn Protobuf hơn là JSON truyền thống nhưng mà lý do mà mình ấn tượng nhất là tốc độ của nó thật sự rất nhanh (một phần là vì dung lượng gói tin của nó nhỏ gọn và truyền tải theo binary nên cực kỳ tối ưu cho máy tính), nếu muốn xem Protobuf đánh bại JSON như thế nào thì bạn có thể xem thêm ở đây [link].

What?

Quay trở lại câu hỏi đề bài nào! Thế thì còn gRPC-Web là ông thần nào nữa? Ta đã biết gRPC là một RPC framework do Google phát triển và sử dụng Protobuf để tranfer data thay vì JSON/XML truyền thống nên tốc độ được gia tăng đáng kể, gRPC hỗ trợ rất nhiều ngôn ngữ lập trình để tích hợp trên mobile, backend service và cả trên trình duyệt. Và trong bài viết này mình muốn giới thiệu với các bạn về gRPC-Web, một thư viện Javascript hỗ trợ trình duyệt giao tiếp với gRPC service.

How?

Bởi vì gRPC-Web không hỗ trợ HTTP/2 vì vậy chúng ta cần một gateway proxy, thường chúng ta sẽ sử dụng Envoy để translate request từ HTTP/1 sang HTTP/2. Đồng thời Envoy cũng sẽ hỗ trợ cấu hình cho phép CORS request. Chúng ta có thể build một Envoy proxy dễ dàng với Docker thông qua file cấu hình envoy.yaml và chạy nó với câu lệnh sau:

1
2
docker run -d -v "$(pwd)"/envoy.yaml:/etc/envoy/envoy.yaml:ro \
-p 8080:8080 -p 9901:9901 envoyproxy/envoy:v1.15.0

Bây giờ để minh hoạ cho việc chạy gRPC-Web trên React JS mình sẽ tạo ra một gRPC service nhỏ bằng NodeJS sẽ nhận vào request là tên một người và response trả về sẽ là lời chào “Hello! + <tên người đó>”. Đầu tiên chúng ta cần định nghĩa ra file proto như bên dưới:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
syntax = "proto3";

package helloworld;

service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}

message HelloRequest {
string name = 1;
}

message HelloReply {
string message = 1;
}

Để build một server gRPC với NodeJS chúng ta cần sử dụng proto-loader để load file proto của chúng ta lên và grpc-js để implement các service mà ta đã định nghĩa trong file proto.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var PROTO_PATH = __dirname + "/helloworld.proto";

var assert = require("assert");
var async = require("async");
var _ = require("lodash");
var grpc = require("@grpc/grpc-js");
var protoLoader = require("@grpc/proto-loader");
var packageDefinition = protoLoader.loadSync(PROTO_PATH, {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true,
});
var protoDescriptor = grpc.loadPackageDefinition(packageDefinition);
var helloworld = protoDescriptor.helloworld;

/**
* @param {!Object} call
* @param {function():?} callback
*/
function doSayHello(call, callback) {
callback(null, { message: "Hello! " + call.request.name });
}

Tiếp theo để biên dịch file proto này thành code Javascript để trình duyệt có thể đọc được chúng ta cần sử dụng một compiler tên là protoc, các bạn có thể cài đặt theo hướng dẫn ở đây [link]. Sau khi cài đặt thành công thì chúng ta tiến hành biên dịch bằng cách chạy câu lệnh sau:

1
2
3
protoc -I=. helloworld.proto \
--js_out=import_style=commonjs:. \
--grpc-web_out=import_style=commonjs,mode=grpcwebtext:.

Cuối cùng việc còn lại là implement các file grpc được biên dịch ra từ tool protoc vào ứng dụng React JS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { GreeterClient } from '../rpc/helloworld_grpc_web_pb.js';
import { HelloRequest, RepeatHelloRequest } from '../rpc/helloworld_pb.js';

const URL = "http://" + window.location.hostname + ":8080";
const client = new GreeterClient(URL, null, null);

const metadata = { 'custom-header-1': 'value1' };

export default {
sayHello: (name, callback) => {
const request = new HelloRequest();
request.setName(name);
client.sayHello(request, metadata, callback);
},
sayRepeatHello: ({ name, count }) => {
const streamRequest = new RepeatHelloRequest();
streamRequest.setName(name);
streamRequest.setCount(count);
return client.sayRepeatHello(streamRequest, metadata);
},
};

Như vậy là chúng ta đã cùng nhau tìm hiểu xong các vấn đề xoay quanh liên quan đến gRPC-Web và cách triển khai nó, tóm lại mình không khuyên các bạn từ bỏ REST để chuyển sang dùng gRPC hoàn toàn nếu như dự án trước giờ bạn đang làm vẫn đang hoạt động tốt với REST thì hết tiếp tục với nó, nếu như ứng dụng của bạn cần tối ưu hơn về tốc độ hoặc bạn đang bắt đầu một dự án mới thì hãy cân nhắc việc sử dụng gRPC, việc triển khai trên môi trường web application là hoàn toàn khả thi. Dưới đây là đường link repo github chứa full code demo nếu bạn cần tham khảo chi tiết.
Link code demo: https://github.com/ozuit/react-grpc-web

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×