J'écrirai sur la façon d'utiliser gRPC pour la communication entre le serveur Go API et le client Dart (en supposant Flutter).
Hibiya Music Festival Osanpo App 2020 Development Behind the Scenes / Server Edition Les 20 nouveaux diplômés et 21 diplômés de DeNA J'ai fait référence à l'article de la personne, je vais donc le partager.
Aussi, pourquoi est-il agréable d'utiliser gRPC? Une session de Nao Minami de Cloud Native Days Tokyo 2020 "Real World Migration from HTTP to gRPC" C'est facile à comprendre lorsque vous écoutez, alors je vais également partager ceci. Vous pouvez accéder à la vidéo archivée à partir du lien.
Pour générer automatiquement à partir d'un fichier .proto, vous devez utiliser la commande protoc et les plug-ins périphériques, mais je ne veux pas installer diverses choses localement, donc je lance un conteneur Docker et génère du code pour chaque langue. Vous pouvez vérifier la dernière version des tampons de protocole actuels à partir du référentiel GitHub (https://github.com/protocolbuffers/protobuf/releases).
Dockerfile
FROM golang:1.15.0
ENV DEBIAN_FRONTEND=noninteractive
ARG PROTO_VERSION=3.13.0
WORKDIR /proto
COPY ./proto .
RUN mkdir /output /output/server /output/client
RUN apt-get -qq update && apt-get -qq install -y \
unzip
RUN curl -sSL https://github.com/protocolbuffers/protobuf/releases/download/v${PROTO_VERSION}/protoc-${PROTO_VERSION}-linux-x86_64.zip -o protoc.zip && \
unzip -qq protoc.zip && \
cp ./bin/protoc /usr/local/bin/protoc && \
cp -r ./include /usr/local
# Go
RUN go get -u github.com/golang/protobuf/protoc-gen-go
# Dart
RUN apt-get install apt-transport-https
RUN sh -c 'curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -'
RUN sh -c 'curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list'
RUN apt-get update
RUN apt-get install dart -y
ENV PATH="${PATH}:/usr/lib/dart/bin/"
ENV PATH="${PATH}:/root/.pub-cache/bin"
RUN pub global activate protoc_plugin
Exécutez le script suivant dans ce conteneur
protoc.sh
#!/bin/sh
set -xe
SERVER_OUTPUT_DIR=/output/server
CLIENT_OUTPUT_DIR=/output/client
protoc --version
protoc -I=/proto/protos hoge.proto fuga.proto\
--go_out=plugins="grpc:${SERVER_OUTPUT_DIR}" \
--dart_out="grpc:${CLIENT_OUTPUT_DIR}"
#horodatage dans le fichier proto.Requis lors de l'importation de proto, etc.
protoc -I=/proto/protos timestamp.proto wrappers.proto\
--dart_out="grpc:${CLIENT_OUTPUT_DIR}"
Lorsque vous utilisez docker-compose, si vous définissez la commande pour exécuter protoc.sh plus tôt, le code sera automatiquement généré au démarrage. Synchronisez le répertoire contenant le fichier proto et protoc.sh avec les volumes, le répertoire de sortie côté serveur et le répertoire de sortie côté client.
docker-compose.yml
version: '3.8'
services:
proto:
build:
context: .
dockerfile: docker/proto/Dockerfile
command: ./protoc.sh
volumes:
- ./proto:/proto
- ./client:/output/client
- ./server:/output/server
Cependant, lorsque vous spécifiez le package go du côté du fichier proto, par exemple
hoge.proto
syntax = "proto3";
package hoge.hoge;
option go_package = "hoge/fuga/foo/bar";
service Hoge{
}
Si tel est le cas, il sera affiché dans `` / output / server / hoge / fuga / foo '' du côté du conteneur.
hoge.pb.go``` est généré dans les volumes spécifiés dans docker-compose.yml. Puisqu'il contient la définition d'Inerface de Clinet (il est facile à trouver si vous recherchez dans le fichier avec ctx), nous allons implémenter la méthode en regardant cette partie.
go:hoge.pb.go
// HogeClient is the client API for Hoge service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type HogeClient interface {
CreateHoge(ctx context.Context, in *CreateHogeMessage, opts ...grpc.CallOption) (*CreateHogeResponse, error)
}
Créez HogeController en tant que classe qui implémente HogeClient. Le point à noter ici est que l'argument de longueur variable est reçu après le troisième argument, mais il n'est pas nécessaire d'écrire des opts dans la méthode côté implémentation.
hoge_controller.go
type HogeController struct{
}
func (ctrl HogeController) CreateHoge(ctx context.Context, in *CreateHogeMessage) (*CreateHogeResponse, error){
// TODO: return *CreateHogeResponse, error
}
Enregistrez l'instance HogeController créée ci-dessus avec l'instance de serveur gRPC avec RegisterHogeServer ().
main.go
func main() {
listenPort, err := net.Listen("tcp", ":8000")
if err != nil {
log.Fatalln(err)
}
server := grpc.NewServer()
hogeCtrl := NewHogeController()
pb.RegisterHogeServer(server, &hogeCtrl)
if err := server.Serve(listenPort); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
Le client est hoge.pb.dart```,
hoge.pbgrpc.dart, `` hoge.pbjson.dart
, `` hoge. Si vous utilisez enum. pbenum.dart '' est généré.
Si timestamp.dart est utilisé du côté du fichier proto, une erreur se produira dans le chemin généré, changez donc simplement l'instruction d'importation dans `hoge.pb.dart``` en` `ʻimport'timestamp.pb.dart ' Vous pouvez l'utiliser en le changeant comme $ 1;
``. Dans le cas d'un appel unaire, vous pouvez communiquer avec les fonctions suivantes.
hoge.dart
Future<void> createHoge(dartSideParam1, dartSideParam2, dartSideParam3) async {
final channel = ClientChannel('localhost',
port: 8000,
options:
const ChannelOptions(credentials: ChannelCredentials.insecure()));
final grpcClient = KitchenClient(channel,
options: CallOptions(timeout: Duration(seconds: 10)));
try {
await grpcClient.createHoge(CreateHogerMessage()
..param1 = dartSideParam1
..param2 = dartSideParam2
..param3 = dartSideParam3;
await channel.shutdown();
} catch (error) {
developer.log('Caught error: $error');
await channel.shutdown();
return Future.error(error);
}
}
C'était un moyen de communiquer entre Go et Dart en utilisant gRPC. Dans certaines entreprises, nous mettons en œuvre en utilisant la méthode de communication Server Streaming, je voudrais donc partager ces informations à une date ultérieure.
Recommended Posts