gRPC
Create gRPC server with rk-boot and rk-grpc plugins.
Overview#
We will use rk-boot start gRPC microservice and add /v1/hello API into it.
Furthermore, we will enable bellow functionalities.
| Functionality | Description |
|---|---|
| Swagger UI | Enable Swagger UI |
| API Docs UI | Enable RapiDoc UI |
| Prometheus Client | Enable Prometheus Client |
| Logging middleware | Automatically record logs for every API calls |
| Prometheus middleware | Automatically record prometheus metrics for every API calls |
| Meta middleware | Automatically add requestID for every API response |
Install gRPC related CLI#
In order to compile protocol buffer, we need to install a couple of CLI.
User can use rk to install them quickly.
# Install RK CLI $ go get -u github.com/rookie-ninja/rk/cmd/rk # List available installation $ rk install COMMANDS: buf install buf on local machine cfssl install cfssl on local machine cfssljson install cfssljson on local machine gocov install gocov on local machine golangci-lint install golangci-lint on local machine mockgen install mockgen on local machine pkger install pkger on local machine protobuf install protobuf on local machine protoc-gen-doc install protoc-gen-doc on local machine protoc-gen-go install protoc-gen-go on local machine protoc-gen-go-grpc install protoc-gen-go-grpc on local machne protoc-gen-grpc-gateway install protoc-gen-grpc-gateway on local machine protoc-gen-openapiv2 install protoc-gen-openapiv2 on local machine swag install swag on local machine rk-std install rk standard environment on local machine help, h Shows a list of commands or help for one command # Install buf, protoc-gen-go, protoc-gen-go-grpc, protoc-gen-grpc-gateway, protoc-gen-openapiv2 $ rk install protoc-gen-go $ rk install protoc-gen-go-grpc $ rk install protoc-gen-go-grpc-gateway $ rk install protoc-gen-openapiv2 $ rk install buf | CLI | Description | 安装 |
|---|---|---|
| buf | Compile protocol buffer API | Install |
| protoc-gen-go | Generate .go files | Install |
| protoc-gen-go-grpc | Generate gRPC related .go files | Install |
| protoc-gen-grpc-gateway | Generate grpc-gateway related .go files | Install |
| protoc-gen-openapiv2 | Generate swagger UI related .json files | Install |
Install#
go get github.com/rookie-ninja/rk-boot/v2 go get github.com/rookie-ninja/rk-grpc/v2 1. Create greeter.proto#
Create greeter.proto file at api/v1 folder.
syntax = "proto3"; package api.v1; option go_package = "api/v1/greeter"; service Greeter { rpc Hello (HelloRequest) returns (HelloResponse) {} } message HelloRequest {} message HelloResponse { string message = 1; } 2. Copy googleapis files#
rk-grpc plugin use some data structures in googleapi. We recommend putting those proto files in project folder.
Copy files from github/googleapi, or copy from rk-boot.
Please copy files into third-party folder.
third-party └── googleapis └── google ├── api │ ├── annotations.proto │ ├── http.proto │ └── httpbody.proto └── rpc ├── code.proto ├── error_details.proto └── status.proto 3. Create buf related config files#
buf.yaml
version: v1beta1 name: github.com/rk-dev/rk-boot build: roots: - api - third-party/googleapis buf.gen.yaml
version: v1beta1 plugins: - name: go out: api/gen opt: - paths=source_relative - name: go-grpc out: api/gen opt: - paths=source_relative - require_unimplemented_servers=false - name: grpc-gateway out: api/gen opt: - paths=source_relative - grpc_api_configuration=api/v1/gw_mapping.yaml - allow_repeated_fields_in_body=true - generate_unbound_methods=true - name: openapiv2 out: api/gen opt: - grpc_api_configuration=api/v1/gw_mapping.yaml - allow_repeated_fields_in_body=true api/v1/gw_mapping.yaml
type: google.api.Service config_version: 3 # Please refer google.api.Http in third-party/googleapis/google/api/http.proto file for details. http: rules: - selector: api.v1.Greeter.Hello get: /v1/hello Run buf command
$ buf generate --path api/v1 # By configuration in buf.gen.yaml, generated files would be write to api/gen folder $ tree . ├── api │ ├── gen │ │ ├── google │ │ │ ... │ │ └── v1 │ │ ├── greeter.pb.go │ │ ├── greeter.pb.gw.go │ │ ├── greeter.swagger.json │ │ └── greeter_grpc.pb.go │ └── v1 │ ├── greeter.proto │ └── gw_mapping.yaml ├── boot.yaml ├── buf.gen.yaml ├── buf.yaml ├── go.mod ├── go.sum ├── main.go └── third-party └── googleapis ... 4. Create boot.yaml#
grpc: - name: greeter port: 8080 # gwPort: 8081 # Optional, default: gateway port will be the same as grpc port if not provided enabled: true enableReflection: true # Enable gRPC reflection mainly for grpcurl enableRkGwOption: true # Enable RK style grpc-gateway options sw: enabled: true # Enable Swagger UI,default path: /sw docs: enabled: true # Enable API Doc UI,default path: /docs prom: enabled: true # Enable Prometheus Client,default path: /metrics middleware: logging: enabled: true prom: enabled: true meta: enabled: true 5. Create main.go#
// Copyright (c) 2021 rookie-ninja // // Use of this source code is governed by an Apache-style // license that can be found in the LICENSE file. package main import ( "context" "github.com/rookie-ninja/rk-boot/v2" "github.com/rookie-ninja/rk-demo/api/gen/v1" "github.com/rookie-ninja/rk-grpc/v2/boot" "google.golang.org/grpc" ) func main() { boot := rkboot.NewBoot() // 注册 RPC entry := rkgrpc.GetGrpcEntry("greeter") entry.AddRegFuncGrpc(registerGreeter) entry.AddRegFuncGw(greeter.RegisterGreeterHandlerFromEndpoint) // 启动 boot.Bootstrap(context.TODO()) // 等待关闭信号 boot.WaitForShutdownSig(context.TODO()) } func registerGreeter(server *grpc.Server) { greeter.RegisterGreeterServer(server, &GreeterServer{}) } type GreeterServer struct{} func (server *GreeterServer) Hello(_ context.Context, _ *greeter.HelloRequest) (*greeter.HelloResponse, error) { return &greeter.HelloResponse{ Message: "Hello!", }, nil } 6. Run main.go#
$ go run main.go 2022-04-14T16:25:23.538+0800 INFO boot/grpc_entry.go:960 Bootstrap grpcEntry {"eventId": "f09d0b94-b491-4148-8438-3e65610fbdde", "entryName": "greeter", "entryType": "gRPCEntry"} 2022-04-14T16:25:23.542+0800 INFO boot/grpc_entry.go:681 SwaggerEntry: http://localhost:8080/sw/ 2022-04-14T16:25:23.542+0800 INFO boot/grpc_entry.go:684 DocsEntry: http://localhost:8080/docs/ 2022-04-14T16:25:23.542+0800 INFO boot/grpc_entry.go:687 PromEntry: http://localhost:8080/metrics ------------------------------------------------------------------------ endTime=2022-04-14T16:25:23.54236+08:00 startTime=2022-04-14T16:25:23.537974+08:00 elapsedNano=4385739 timezone=CST ids={"eventId":"f09d0b94-b491-4148-8438-3e65610fbdde"} app={"appName":"rk","appVersion":"local","entryName":"greeter","entryType":"gRPCEntry"} env={"arch":"amd64","domain":"*","hostname":"lark.local","localIP":"10.8.0.2","os":"darwin"} payloads={"docsEnabled":true,"docsPath":"/docs/","grpcPort":8080,"gwPort":8080,"promEnabled":true,"promPath":"/metrics","promPort":8080,"swEnabled":true,"swPath":"/sw/"} counters={} pairs={} timing={} remoteAddr=localhost operation=Bootstrap resCode=OK eventStatus=Ended EOE 7. Validate#
7.1 Swagger UI#
7.2 API Docs UI#
7.3 Prometheus Client#
7.4 Send request#
Restful API
$ curl -vs localhost:8080/v1/hello ... < X-Request-Id: b047072d-a433-4b98-b2ff-3ba54bbb0243 < X-Rk-App-Domain: * < X-Rk-App-Name: rk < X-Rk-App-Unix-Time: 2022-04-14T16:35:28.387937+08:00 < X-Rk-App-Version: local < X-Rk-Received-Time: 2022-04-14T16:35:28.387937+08:00 ... {"message":"Hello!"} gRPC
$ grpcurl -v -plaintext localhost:8080 api.v1.Greeter.Hello Resolved method descriptor: rpc Hello ( .api.v1.HelloRequest ) returns ( .api.v1.HelloResponse ); Request metadata to send: (empty) Response headers received: content-type: application/grpc x-request-id: c783eeaa-2a77-44ec-bb9c-9cbf19a58ee6 x-rk-app-domain: * x-rk-app-name: rk x-rk-app-unix-time: 2022-04-14T16:36:59.258112+08:00 x-rk-app-version: local x-rk-received-time: 2022-04-14T16:36:59.258112+08:00 Response contents: { "message": "Hello!" } ... 7.5 API logs#
By default, rk-boot will use bellow format of logs. JSON is also supported, please visit user-guide for details.
------------------------------------------------------------------------ endTime=2022-04-14T16:35:28.387969+08:00 startTime=2022-04-14T16:35:28.387928+08:00 elapsedNano=41020 timezone=CST ids={"eventId":"b047072d-a433-4b98-b2ff-3ba54bbb0243","requestId":"b047072d-a433-4b98-b2ff-3ba54bbb0243"} app={"appName":"rk","appVersion":"local","entryName":"greeter","entryType":"gRPCEntry"} env={"arch":"amd64","domain":"*","hostname":"lark.local","localIP":"10.8.0.2","os":"darwin"} payloads={"apiMethod":"","apiPath":"/api.v1.Greeter/Hello","apiProtocol":"","apiQuery":"","grpcMethod":"Hello","grpcService":"api.v1.Greeter","grpcType":"UnaryServer","gwMethod":"GET","gwPath":"/v1/hello","gwScheme":"http","gwUserAgent":"curl/7.64.1","userAgent":""} counters={} pairs={} timing={} remoteAddr=127.0.0.1:56369 operation=/api.v1.Greeter/Hello resCode=OK eventStatus=Ended EOE 



