著者:重松 亜夢
今回は、「gRPC」という通信プロトコルを使った、Webアプリケーションの作成方法を紹介します。gRPCを使うことで、通信量が減らせます。最近注目のマイクロサービスの連携にも活用できます。
シェルスクリプトマガジン Vol.72は以下のリンク先でご購入できます。
図3 「pb/picture.proto」ファイルに記述する内容
1 2 3 4 5 6 7 8 9 10 11 12 |
syntax = "proto3"; option go_package = "example.com/user_name/sample/pb/go/picture"; package picture; service Picture { rpc GetPictures (GetPicturesRequest) returns (GetPicturesReply) {} } message GetPicturesRequest { uint32 num = 1; } message GetPicturesReply { repeated bytes pictures = 1; } |
図4 「pb/protoc-web/Dockerfile」ファイルに記述する内容
1 2 3 4 5 6 7 |
FROM node:15-buster WORKDIR /pb RUN npm i rimraf -g RUN curl -L -O https://github.com/protocolbuffers/protobuf/releases/download/v3.15.8/protoc-3.15.8-linux-x86_64.zip RUN curl -L -O https://github.com/grpc/grpc-web/releases/download/1.2.1/protoc-gen-grpc-web-1.2.1-linux-x86_64 RUN unzip protoc-3.15.8-linux-x86_64.zip && cp ./bin/protoc /usr/local/bin/. && chmod +x /usr/local/bin/protoc RUN cp protoc-gen-grpc-web-1.2.1-linux-x86_64 /usr/local/bin/protoc-gen-grpc-web && chmod +x /usr/local/bin/protoc-gen-grpc-web |
図5 「pb/scripts/picture-compile.sh」ファイルに追記する内容
1 2 3 4 5 6 7 8 |
docker build protoc-web -t streaming-protoc-web mkdir -p js/picture docker run -v "$(pwd):/pb" -w /pb --rm streaming-protoc-web \ protoc --proto_path=. picture.proto \ --js_out=import_style=commonjs:js/picture \ --grpc-web_out=import_style=typescript,mode=grpcwebtext:js/picture mkdir -p ../services/client/src/pb cp -r ./js/* ../services/client/src/pb/ |
図6 「Makefil e」ファイルの変更内容
1 2 3 4 |
proto: pb/js/picture/picture_pb.js # make .proto pb/js/picture/picture_pb.js: pb/picture.proto bash ./pb/scripts/picture-compile.sh |
図8 「docker-compose.yaml」ファイルに追加する内容
1 2 3 4 5 6 7 |
proxy: container_name: sample-proxy-container image: envoyproxy/envoy-dev:1f642ab20b8975654482411537a6bdc5e2f6c4f6 ports: - "8080:8080" volumes: - ./services/proxy/envoy.yaml:/etc/envoy/envoy.yaml |
図9 「services/client/src/components/Picture.tsx」ファイルの内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
import { useState } from 'react'; import { GetPicturesRequest, GetPicturesReply } from "../pb/picture/picture_pb"; import { PictureClient } from "../pb/picture/PictureServiceClientPb"; import { Error } from 'grpc-web'; export const Picture = () => { const [num, setNumber] = useState(1); // 枚数の指定 const [pictures, setPictures] = useState<JSX.Element[]>([]); const jspb = require('google-protobuf'); const client = new PictureClient(`http://${window.location.hostname}:8080/server`, {}, {}); const getPictures = () => { if (num <= 0) return; const request = new GetPicturesRequest(); request.setNum(num); client.getPictures(request, {}, (err: Error, response: GetPicturesReply) => { if (err || response === null) { throw err; } setPictures(jspb.Message.bytesListAsB64(response.getPicturesList()) .map((images: string, index: number) => ( <img key={`${index}`} width="200px" src={`data:image/jpg;base64,${window.atob(images)}`} alt="pictures" /> ))); }); } const onChange = (event: React.ChangeEvent<HTMLInputElement>) => { const n = event.target.valueAsNumber; if (!isNaN(n)) { setNumber(n); } }; return ( <div> <input type="number" min="1" defaultValue="1" onChange={onChange} /> <button onClick={getPictures}>GetPictures</button> <div className="getPictures">{pictures}</div> </div> ); } |
図10 「services/client/src/App.tsx」ファイルに記述する内容
1 2 3 4 5 6 7 8 9 10 11 12 |
import {Picture} from './components/Picture' import './App.css'; function App() { return ( <div className="App"> <header className="App-header"> <Picture/> </header> </div> ); } export default App; |