{"id":13740476,"url":"https://github.com/rookie-ninja/rk-grpc","last_synced_at":"2025-10-14T05:04:53.168Z","repository":{"id":38403495,"uuid":"282520659","full_name":"rookie-ninja/rk-grpc","owner":"rookie-ninja","description":"Start gRPC microservice from YAML, plugin of rk-boot","archived":false,"fork":false,"pushed_at":"2023-10-31T12:37:21.000Z","size":50294,"stargazers_count":78,"open_issues_count":4,"forks_count":20,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-08-09T21:41:13.705Z","etag":null,"topics":["bootstrapper","golang","grpc","interceptor","opentracing","rk","swagger"],"latest_commit_sha":null,"homepage":"https://rk.mofcloud.com","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rookie-ninja.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2020-07-25T20:33:46.000Z","updated_at":"2025-07-30T09:12:11.000Z","dependencies_parsed_at":"2023-07-19T00:57:13.542Z","dependency_job_id":"a3996c63-0956-4f74-a7f5-99ef3bde885f","html_url":"https://github.com/rookie-ninja/rk-grpc","commit_stats":null,"previous_names":["rookie-ninja/rk-interceptor"],"tags_count":70,"template":false,"template_full_name":null,"purl":"pkg:github/rookie-ninja/rk-grpc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rookie-ninja%2Frk-grpc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rookie-ninja%2Frk-grpc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rookie-ninja%2Frk-grpc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rookie-ninja%2Frk-grpc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rookie-ninja","download_url":"https://codeload.github.com/rookie-ninja/rk-grpc/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rookie-ninja%2Frk-grpc/sbom","scorecard":{"id":784529,"data":{"date":"2025-08-11","repo":{"name":"github.com/rookie-ninja/rk-grpc","commit":"5518537a3694fb05a6d748515cbd7d0134986760"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.6,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 1/15 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/ci.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/rookie-ninja/rk-grpc/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/rookie-ninja/rk-grpc/ci.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/rookie-ninja/rk-grpc/ci.yml/master?enable=pin","Warn: containerImage not pinned by hash: example/boot/simple/Dockerfile:1","Warn: containerImage not pinned by hash: example/boot/simple/Dockerfile:7: pin your Docker image by updating alpine to alpine@sha256:4bcff63911fcb4448bd4fdacec207030997caf25e9bea4045fa6c8c44de311d1","Warn: downloadThenRun not pinned by hash: .github/workflows/ci.yml:26","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned","Info:   0 out of   1 downloadThenRun dependencies pinned","Info:   0 out of   2 containerImage dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 27 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":1,"reason":"9 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GO-2024-3250 / GHSA-29wx-vh33-7x7r","Warn: Project is vulnerable to: GO-2025-3553 / GHSA-mh63-6h87-95cp","Warn: Project is vulnerable to: GO-2023-2102 / GHSA-4374-p667-p6c8","Warn: Project is vulnerable to: GHSA-qppj-fm5r-hxr3","Warn: Project is vulnerable to: GO-2024-2687 / GHSA-4v7x-pqxf-cx7m","Warn: Project is vulnerable to: GO-2024-3333","Warn: Project is vulnerable to: GO-2025-3503 / GHSA-qxp5-gwg8-xv66","Warn: Project is vulnerable to: GO-2025-3595 / GHSA-vvgc-356p-c3xw","Warn: Project is vulnerable to: GO-2024-2611 / GHSA-8r3f-844c-mc37"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-23T05:44:09.218Z","repository_id":38403495,"created_at":"2025-08-23T05:44:09.219Z","updated_at":"2025-08-23T05:44:09.219Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279018014,"owners_count":26086237,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-14T02:00:06.444Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bootstrapper","golang","grpc","interceptor","opentracing","rk","swagger"],"created_at":"2024-08-03T04:00:48.365Z","updated_at":"2025-10-14T05:04:53.132Z","avatar_url":"https://github.com/rookie-ninja.png","language":"Go","funding_links":[],"categories":["Web Frameworks","Tools","Middlewares","Web框架","Actual middlewares"],"sub_categories":["Middlewares","Other","Microsoft Word","中间件","Fail injection"],"readme":"\u003ch2 align=\"center\"\u003e\n  rk-grpc\n\u003c/h2\u003e\n\u003cp align=\"center\"\u003e\n  Inject middlewares \u0026 server configuration of \u003ca href=\"https://grpc.io/docs/languages/go/\"\u003egRPC\u003c/a\u003e and \u003ca href=\"https://github.com/grpc-ecosystem/grpc-gateway\"\u003egrpc-gateway\u003c/a\u003e from YAML file.\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  This belongs to \u003ca href=\"https://github.com/rookie-ninja/rk-boot\"\u003erk-boot\u003c/a\u003e family. We suggest use this lib with \u003ca href=\"https://github.com/rookie-ninja/rk-boot\"\u003erk-boot\u003c/a\u003e.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n \u003ca href=\"https://github.com/rookie-ninja/rk-grpc/actions/workflows/ci.yml\"\u003e\u003cimg src=\"https://github.com/rookie-ninja/rk-grpc/actions/workflows/ci.yml/badge.svg\"\u003e\u003c/a\u003e\n \u003ca href=\"https://codecov.io/gh/rookie-ninja/rk-grpc\"\u003e\u003cimg src=\"https://codecov.io/gh/rookie-ninja/rk-grpc/branch/master/graph/badge.svg?token=08TCFIIVS0\"\u003e\u003c/a\u003e\n \u003ca href=\"https://goreportcard.com/badge/github.com/rookie-ninja/rk-grpc\"\u003e\u003cimg src=\"https://goreportcard.com/badge/github.com/rookie-ninja/rk-grpc\"\u003e\u003c/a\u003e\n \u003ca href=\"https://sourcegraph.com/github.com/rookie-ninja/rk-grpc?badge\"\u003e\u003cimg src=\"https://sourcegraph.com/github.com/rookie-ninja/rk-grpc/-/badge.svg\"\u003e\u003c/a\u003e\n \u003ca href=\"https://godoc.org/github.com/rookie-ninja/rk-grpc\"\u003e\u003cimg src=\"https://godoc.org/github.com/rookie-ninja/rk-grpc?status.svg\"\u003e\u003c/a\u003e\n \u003ca href=\"https://github.com/rookie-ninja/rk-grpc/releases\"\u003e\u003cimg src=\"https://img.shields.io/github/release/rookie-ninja/rk-grpc.svg?style=flat-square\"\u003e\u003c/a\u003e\n \u003ca href=\"https://opensource.org/licenses/Apache-2.0\"\u003e\u003cimg src=\"https://img.shields.io/badge/License-Apache%202.0-blue.svg\"\u003e\u003c/a\u003e\n\u003cp\u003e\n\n\u003cdiv id=\"badges\" align=\"center\"\u003e\n  \u003ca href=\"https://medium.com/@pointgoal/list/grpc-101-790c4c160a05\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Medium-12100E?style=for-the-badge\u0026logo=medium\u0026logoColor=white\" alt=\"Medium Badge\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://rkdev.info\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Official Site-blue?logo=mdbook\u0026logoColor=white\u0026style=for-the-badge\" alt=\"Docs Badge\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://rk-syz1767.slack.com/rk-boot\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Slack-4A154B?style=for-the-badge\u0026logo=slack\u0026logoColor=white\" alt=\"Docs Badge\"/\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\n\n## Architecture\n![image](docs/img/grpc-arch.png)\n\n## Quick Start\nIn the bellow example, we will start microservice with bellow functionality and middlewares enabled via YAML.\n\n- [gRPC](https://grpc.io/docs/languages/go/) and [grpc-gateway](https://github.com/grpc-ecosystem/grpc-gateway) server\n- [gRPC](https://grpc.io/docs/languages/go/) server reflection\n- Swagger UI\n- CommonService\n- Docs\n- Prometheus Metrics (middleware)\n- Logging (middleware)\n- Meta (middleware)\n\nPlease refer example at [example/boot/simple](example/boot/simple).\n\n### Installation\n\n```shell\ngo get github.com/rookie-ninja/rk-grpc/v2\n```\n\n### 1.Prepare .proto files\n\u003cdetails\u003e\n\u003csummary\u003eshow\u003c/summary\u003e\n\n- api/v1/greeter.proto\n\n```protobuf\nsyntax = \"proto3\";\n\npackage api.v1;\n\noption go_package = \"api/v1/greeter\";\n\nservice Greeter {\n  rpc Greeter (GreeterRequest) returns (GreeterResponse) {}\n}\n\nmessage GreeterRequest {\n  bytes msg = 1;\n}\n\nmessage GreeterResponse {}\n```\n\n- api/v1/gw_mapping.yaml\n\n```yaml\ntype: google.api.Service\nconfig_version: 3\n\n# Please refer google.api.Http in https://github.com/googleapis/googleapis/blob/master/google/api/http.proto file for details.\nhttp:\n  rules:\n    - selector: api.v1.Greeter.Greeter\n      get: /v1/greeter\n```\n\n- buf.yaml\n\n```yaml\nversion: v1beta1\nname: github.com/rk-dev/rk-boot\nbuild:\n  roots:\n    - api\n```\n\n- buf.gen.yaml\n\n```yaml\nversion: v1beta1\nplugins:\n  # protoc-gen-go needs to be installed, generate go files based on proto files\n  - name: go\n    out: api/gen\n    opt:\n     - paths=source_relative\n  # protoc-gen-go-grpc needs to be installed, generate grpc go files based on proto files\n  - name: go-grpc\n    out: api/gen\n    opt:\n      - paths=source_relative\n      - require_unimplemented_servers=false\n  # protoc-gen-grpc-gateway needs to be installed, generate grpc-gateway go files based on proto files\n  - name: grpc-gateway\n    out: api/gen\n    opt:\n      - paths=source_relative\n      - grpc_api_configuration=api/v1/gw_mapping.yaml\n  # protoc-gen-openapiv2 needs to be installed, generate swagger config files based on proto files\n  - name: openapiv2\n    out: api/gen\n    opt:\n      - grpc_api_configuration=api/v1/gw_mapping.yaml\n```\n\u003c/details\u003e\n\n### 2.Generate .pb.go files with [buf](https://docs.buf.build/introduction)\n\u003cdetails\u003e\n\u003csummary\u003eshow\u003c/summary\u003e\n\n```\n$ buf generate --path api/v1\n```\n\n```\n.\n├── api\n│   ├── gen\n│   │   └── v1\n│   │       ├── greeter.pb.go\n│   │       ├── greeter.pb.gw.go\n│   │       ├── greeter.swagger.json\n│   │       └── greeter_grpc.pb.go\n│   └── v1\n│       ├── greeter.proto\n│       └── gw_mapping.yaml\n├── boot.yaml\n├── buf.gen.yaml\n├── buf.yaml\n├── go.mod\n├── go.sum\n└── main.go\n```\n\u003c/details\u003e\n\n### 3.Create boot.yaml\n\u003cdetails\u003e\n\u003csummary\u003eshow\u003c/summary\u003e\n\n```yaml\n---\ngrpc:\n  - name: greeter                     # Required\n    port: 8080                        # Required\n    enabled: true                     # Required\n    enableReflection: true            # Optional, default: false\n    enableRkGwOption: true            # Optional, default: false\n    commonService:\n      enabled: true                   # Optional, default: false\n    docs:\n      enabled: true                   # Optional, default: false\n    sw:\n      enabled: true                   # Optional, default: false\n    prom:\n      enabled: true                   # Optional, default: false\n    middleware:\n      logging:\n        enabled: true                 # Optional, default: false\n      prom:\n        enabled: true                 # Optional, default: false\n      meta:\n        enabled: true                 # Optional, default: false\n```\n\u003c/details\u003e\n\n### 4.Create main.go\n\u003cdetails\u003e\n\u003csummary\u003eshow\u003c/summary\u003e\n\n```go\n// Copyright (c) 2021 rookie-ninja\n//\n// Use of this source code is governed by an Apache-style\n// license that can be found in the LICENSE file.\npackage main\n\nimport (\n  \"context\"\n  \"embed\"\n  _ \"embed\"\n  \"github.com/rookie-ninja/rk-entry/v2/entry\"\n  \"github.com/rookie-ninja/rk-grpc/v2/boot\"\n  proto \"github.com/rookie-ninja/rk-grpc/v2/example/boot/simple/api/gen/v1\"\n  \"google.golang.org/grpc\"\n)\n\n//go:embed boot.yaml\nvar boot []byte\n\n//go:embed api/gen/v1\nvar docsFS embed.FS\n\n//go:embed api/gen/v1\nvar staticFS embed.FS\n\nfunc init() {\n  rkentry.GlobalAppCtx.AddEmbedFS(rkentry.DocsEntryType, \"greeter\", \u0026docsFS)\n  rkentry.GlobalAppCtx.AddEmbedFS(rkentry.SWEntryType, \"greeter\", \u0026docsFS)\n  rkentry.GlobalAppCtx.AddEmbedFS(rkentry.StaticFileHandlerEntryType, \"greeter\", \u0026staticFS)\n}\n\nfunc main() {\n  // Bootstrap basic entries from boot config.\n  rkentry.BootstrapPreloadEntryYAML(boot)\n\n  // Bootstrap grpc entry from boot config\n  res := rkgrpc.RegisterGrpcEntryYAML(boot)\n\n  // Get GrpcEntry\n  grpcEntry := res[\"greeter\"].(*rkgrpc.GrpcEntry)\n  // Register gRPC server\n  grpcEntry.AddRegFuncGrpc(func(server *grpc.Server) {\n    proto.RegisterGreeterServer(server, \u0026GreeterServer{})\n  })\n  // Register grpc-gateway func\n  grpcEntry.AddRegFuncGw(proto.RegisterGreeterHandlerFromEndpoint)\n\n  // Bootstrap grpc entry\n  grpcEntry.Bootstrap(context.Background())\n\n  // Wait for shutdown signal\n  rkentry.GlobalAppCtx.WaitForShutdownSig()\n\n  // Interrupt gin entry\n  grpcEntry.Interrupt(context.Background())\n}\n\n// GreeterServer Implementation of GreeterServer.\ntype GreeterServer struct{}\n\n// Greeter Handle Greeter method.\nfunc (server *GreeterServer) Greeter(context.Context, *proto.GreeterRequest) (*proto.GreeterResponse, error) {\n  return \u0026proto.GreeterResponse{}, nil\n}\n```\n\n\u003c/details\u003e\n\n### 5.Start server\n```\n$ go run main.go\n```\n\n### 6.Validation\n\u003cdetails\u003e\n\u003csummary\u003eshow\u003c/summary\u003e\n\n#### 6.1 gRPC \u0026 grpc-gateway server\nTry to test [gRPC](https://grpc.io/docs/languages/go/) \u0026 [grpc-gateway](https://github.com/grpc-ecosystem/grpc-gateway) Service with [curl](https://curl.se/) \u0026 [grpcurl](https://github.com/fullstorydev/grpcurl)\n\n```shell script\n# Curl to common service\n$ curl localhost:8080/rk/v1/ready\n{\"ready\":true}\n```\n\n#### 6.2 Swagger UI\nPlease refer **sw** section at [Full YAML](#full-yaml).\n\nBy default, we could access swagger UI at [http://localhost:8080/sw](http://localhost:8080/sw)\n\n![sw](docs/img/simple-sw.png)\n\n#### 6.3 Docs UI\nPlease refer **docs** section at [Full YAML](#full-yaml).\n\nBy default, we could access docs UI at [http://localhost:8080/docs](http://localhost:8080/docs)\n\n![docs](docs/img/simple-docs.png)\n\n#### 6.4 Prometheus Metrics\nPlease refer **middleware.prom** section at [Full YAML](#full-yaml).\n\nBy default, we could access prometheus client at [http://localhost:8080/metrics](http://localhost:8080/metrics)\n\n![prom](docs/img/simple-prom.png)\n\n#### 6.5 Logging\nPlease refer **middleware.logging** section at [Full YAML](#full-yaml).\n\nBy default, we enable zap logger and event logger with encoding type of [console]. Encoding type of [json] and [flatten] is also supported.\n\n```shell script\n2021-12-28T05:36:21.561+0800    INFO    boot/grpc_entry.go:1515 Bootstrap grpcEntry     {\"eventId\": \"db2c977c-e0ff-4b21-bc0d-5966f1cad093\", \"entryName\": \"greeter\"}\n------------------------------------------------------------------------\nendTime=2021-12-28T05:36:21.563575+08:00\nstartTime=2021-12-28T05:36:21.561362+08:00\nelapsedNano=2213846\ntimezone=CST\nids={\"eventId\":\"db2c977c-e0ff-4b21-bc0d-5966f1cad093\"}\napp={\"appName\":\"rk\",\"appVersion\":\"\",\"entryName\":\"greeter\",\"entryType\":\"GrpcEntry\"}\nenv={\"arch\":\"amd64\",\"az\":\"*\",\"domain\":\"*\",\"hostname\":\"lark.local\",\"localIP\":\"10.8.0.2\",\"os\":\"darwin\",\"realm\":\"*\",\"region\":\"*\"}\npayloads={\"commonServiceEnabled\":true,\"commonServicePathPrefix\":\"/rk/v1/\",\"grpcPort\":8080,\"gwPort\":8080,\"promEnabled\":true,\"promPath\":\"/metrics\",\"promPort\":8080,\"swEnabled\":true,\"swPath\":\"/sw/\",\"tvEnabled\":true,\"tvPath\":\"/rk/v1/tv/\"}\nerror={}\ncounters={}\npairs={}\ntiming={}\nremoteAddr=localhost\noperation=Bootstrap\nresCode=OK\neventStatus=Ended\nEOE\n```\n\n#### 6.6 Meta\nPlease refer **meta** section at [Full YAML](#full-yaml).\n\nBy default, we will send back some metadata to client with headers.\n\n```shell script\n$ curl -vs localhost:8080/rk/v1/ready\n...\n\u003c HTTP/1.1 200 OK\n\u003c Content-Type: application/json\n\u003c X-Request-Id: 7e4f5ac5-3369-485f-89f7-55551cc4a9a1\n\u003c X-Rk-App-Name: rk\n\u003c X-Rk-App-Unix-Time: 2021-12-28T05:39:50.508328+08:00\n\u003c X-Rk-App-Version: \n\u003c X-Rk-Received-Time: 2021-12-28T05:39:50.508328+08:00\n\u003c Date: Mon, 27 Dec 2021 21:39:50 GMT\n...\n```\n\n#### 6.7 Send request\nWe registered /v1/greeter API in [grpc-gateway](https://github.com/grpc-ecosystem/grpc-gateway) server and let's validate it!\n\n```shell script\n$ curl -vs localhost:8080/v1/greeter             \n*   Trying ::1...\n* TCP_NODELAY set\n* Connection failed\n* connect to ::1 port 8080 failed: Connection refused\n*   Trying 127.0.0.1...\n* TCP_NODELAY set\n* Connected to localhost (127.0.0.1) port 8080 (#0)\n\u003e GET /v1/greeter HTTP/1.1\n\u003e Host: localhost:8080\n\u003e User-Agent: curl/7.64.1\n\u003e Accept: */*\n\u003e \n\u003c HTTP/1.1 200 OK\n\u003c Content-Type: application/json\n\u003c X-Request-Id: 07b0fbf6-cebf-40ac-84a2-533bbd4b8958\n\u003c X-Rk-App-Name: rk\n\u003c X-Rk-App-Unix-Time: 2021-12-28T05:41:04.653652+08:00\n\u003c X-Rk-App-Version: \n\u003c X-Rk-Received-Time: 2021-12-28T05:41:04.653652+08:00\n\u003c Date: Mon, 27 Dec 2021 21:41:04 GMT\n\u003c Content-Length: 2\n\u003c \n* Connection #0 to host localhost left intact\n{}\n```\n\nWe registered api.v1.Greeter.Greeter API in [gRPC](https://grpc.io/docs/languages/go/) server and let's validate it!\n\n```shell script\n$ grpcurl -plaintext localhost:8080 api.v1.Greeter.Greeter \n{}\n```\n\n#### 6.8 RPC logs\nBellow logs would be printed in stdout.\n\nThe first block of log is from [grpc-gateway](https://github.com/grpc-ecosystem/grpc-gateway) request.\n\nThe second block of log is from [gRPC](https://grpc.io/docs/languages/go/) request.\n\n```\n------------------------------------------------------------------------\nendTime=2021-12-28T05:45:52.986041+08:00\nstartTime=2021-12-28T05:45:52.985956+08:00\nelapsedNano=85065\ntimezone=CST\nids={\"eventId\":\"88362f69-7eda-4f03-bdbe-7ef667d06bac\",\"requestId\":\"88362f69-7eda-4f03-bdbe-7ef667d06bac\"}\napp={\"appName\":\"rk\",\"appVersion\":\"\",\"entryName\":\"greeter\",\"entryType\":\"GrpcEntry\"}\nenv={\"arch\":\"amd64\",\"az\":\"*\",\"domain\":\"*\",\"hostname\":\"lark.local\",\"localIP\":\"10.8.0.2\",\"os\":\"darwin\",\"realm\":\"*\",\"region\":\"*\"}\npayloads={\"grpcMethod\":\"Greeter\",\"grpcService\":\"api.v1.Greeter\",\"grpcType\":\"unaryServer\",\"gwMethod\":\"GET\",\"gwPath\":\"/v1/greeter\",\"gwScheme\":\"http\",\"gwUserAgent\":\"curl/7.64.1\"}\nerror={}\ncounters={}\npairs={}\ntiming={}\nremoteAddr=127.0.0.1:61520\noperation=/api.v1.Greeter/Greeter\nresCode=OK\neventStatus=Ended\nEOE\n------------------------------------------------------------------------\nendTime=2021-12-28T05:44:45.686734+08:00\nstartTime=2021-12-28T05:44:45.686592+08:00\nelapsedNano=141716\ntimezone=CST\nids={\"eventId\":\"7765862c-9e83-443a-a6e5-bb28f17f8ea0\",\"requestId\":\"7765862c-9e83-443a-a6e5-bb28f17f8ea0\"}\napp={\"appName\":\"rk\",\"appVersion\":\"\",\"entryName\":\"greeter\",\"entryType\":\"GrpcEntry\"}\nenv={\"arch\":\"amd64\",\"az\":\"*\",\"domain\":\"*\",\"hostname\":\"lark.local\",\"localIP\":\"10.8.0.2\",\"os\":\"darwin\",\"realm\":\"*\",\"region\":\"*\"}\npayloads={\"grpcMethod\":\"Greeter\",\"grpcService\":\"api.v1.Greeter\",\"grpcType\":\"unaryServer\",\"gwMethod\":\"\",\"gwPath\":\"\",\"gwScheme\":\"\",\"gwUserAgent\":\"\"}\nerror={}\ncounters={}\npairs={}\ntiming={}\nremoteAddr=127.0.0.1:57149\noperation=/api.v1.Greeter/Greeter\nresCode=OK\neventStatus=Ended\nEOE\n```\n\n#### 6.9 RPC prometheus metrics\nPrometheus client will automatically register into [grpc-gateway](https://github.com/grpc-ecosystem/grpc-gateway) instance at /metrics.\n\nAccess [http://localhost:8080/metrics](http://localhost:8080/metrics)\n\n![image](docs/img/prom-inter.png)\n\n\u003c/details\u003e\n\n## Supported features\n**User can enable anyone of those as needed! No mandatory binding!**\n\n| Instance                                                               | Description                                                                                                                    |\n|------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------|\n| [gRPC](https://grpc.io/docs/languages/go/)                             | [gRPC](https://grpc.io/docs/languages/go/) defined with protocol buffer.                                                       |\n| [gRPC](https://grpc.io/docs/languages/go/) proxy                       | Proxy gRPC request to another gRPC server.                                                                                     |\n| [grpc-gateway](https://github.com/grpc-ecosystem/grpc-gateway)         | [grpc-gateway](https://github.com/grpc-ecosystem/grpc-gateway) service with same port.                                         |\n| [grpc-gateway](https://github.com/grpc-ecosystem/grpc-gateway) options | Well defined [grpc-gateway](https://github.com/grpc-ecosystem/grpc-gateway) options.                                           |\n| Config                                                                 | Configure [spf13/viper](https://github.com/spf13/viper) as config instance and reference it from YAML                          |\n| Logger                                                                 | Configure [uber-go/zap](https://github.com/uber-go/zap) logger configuration and reference it from YAML                        |\n| Event                                                                  | Configure logging of RPC with [rk-query](https://github.com/rookie-ninja/rk-query) and reference it from YAML                  |\n| Cert                                                                   | Fetch TLS/SSL certificates from remote datastore like ETCD and start microservice.                                             |\n| Prometheus                                                             | Start prometheus client at client side and push metrics to [pushgateway](https://github.com/prometheus/pushgateway) as needed. |\n| Swagger                                                                | Builtin swagger UI handler.                                                                                                    |\n| Docs                                                                   | Builtin [RapiDoc](https://github.com/mrin9/RapiDoc) instance which can be used to replace swagger and RK TV.                   |\n| CommonService                                                          | List of common APIs.                                                                                                           |\n| StaticFileHandler                                                      | A Web UI shows files could be downloaded from server, currently support source of local and embed.FS.                          |\n| PProf                                                                  | PProf web UI.                                                                                                                  |\n| gRPC Web                                                               | gRPC Web                                                                                                                       |\n\n## Supported middlewares\nAll middlewares could be configured via YAML or Code.\n\n**User can enable anyone of those as needed! No mandatory binding!**\n\n| Middleware | Description                                                                                                                                           |\n|------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|\n| Metrics    | Collect RPC metrics and export to [prometheus](https://github.com/prometheus/client_golang) client.                                                   |\n| Log        | Log every RPC requests as event with [rk-query](https://github.com/rookie-ninja/rk-query).                                                            |\n| Trace      | Collect RPC trace and export it to stdout, file or jaeger with [open-telemetry/opentelemetry-go](https://github.com/open-telemetry/opentelemetry-go). |\n| Panic      | Recover from panic for RPC requests and log it.                                                                                                       |\n| Meta       | Send micsroservice metadata as header to client.                                                                                                      |\n| Auth       | Support [Basic Auth] and [API Key] authorization types.                                                                                               |\n| RateLimit  | Limiting RPC rate globally or per path.                                                                                                               |\n| Timeout    | Timing out request by configuration.                                                                                                                  |\n| CORS       | Server side CORS validation.                                                                                                                          |\n| JWT        | Server side JWT validation.                                                                                                                           |\n| Secure     | Server side secure validation.                                                                                                                        |\n| CSRF       | Server side csrf validation.                                                                                                                          |\n\n## YAML options\nUser can start multiple [gRPC](https://grpc.io/docs/languages/go/) and [grpc-gateway](https://github.com/grpc-ecosystem/grpc-gateway) instances at the same time. Please make sure use different port and name.\n\n\u003cdetails\u003e\n\u003csummary\u003eshow\u003c/summary\u003e\n\n```yaml\n---\n#app:\n#  name: my-app                                            # Optional, default: \"rk-app\"\n#  version: \"v1.0.0\"                                       # Optional, default: \"v0.0.0\"\n#  description: \"this is description\"                      # Optional, default: \"\"\n#  keywords: [\"rk\", \"golang\"]                              # Optional, default: []\n#  homeUrl: \"http://example.com\"                           # Optional, default: \"\"\n#  docsUrl: [\"http://example.com\"]                         # Optional, default: []\n#  maintainers: [\"rk-dev\"]                                 # Optional, default: []\n#logger:\n#  - name: my-logger                                       # Required\n#    description: \"Description of entry\"                   # Optional\n#    domain: \"*\"                                           # Optional, default: \"*\"\n#    default: false                                        # Optional, default: false, use as default logger entry\n#    zap:                                                  # Optional\n#      level: info                                         # Optional, default: info\n#      development: true                                   # Optional, default: true\n#      disableCaller: false                                # Optional, default: false\n#      disableStacktrace: true                             # Optional, default: true\n#      encoding: console                                   # Optional, default: console\n#      outputPaths: [\"stdout\"]                             # Optional, default: [stdout]\n#      errorOutputPaths: [\"stderr\"]                        # Optional, default: [stderr]\n#      encoderConfig:                                      # Optional\n#        timeKey: \"ts\"                                     # Optional, default: ts\n#        levelKey: \"level\"                                 # Optional, default: level\n#        nameKey: \"logger\"                                 # Optional, default: logger\n#        callerKey: \"caller\"                               # Optional, default: caller\n#        messageKey: \"msg\"                                 # Optional, default: msg\n#        stacktraceKey: \"stacktrace\"                       # Optional, default: stacktrace\n#        skipLineEnding: false                             # Optional, default: false\n#        lineEnding: \"\\n\"                                  # Optional, default: \\n\n#        consoleSeparator: \"\\t\"                            # Optional, default: \\t\n#      sampling:                                           # Optional, default: nil\n#        initial: 0                                        # Optional, default: 0\n#        thereafter: 0                                     # Optional, default: 0\n#      initialFields:                                      # Optional, default: empty map\n#        key: value\n#    lumberjack:                                           # Optional, default: nil\n#      filename:\n#      maxsize: 1024                                       # Optional, suggested: 1024 (MB)\n#      maxage: 7                                           # Optional, suggested: 7 (day)\n#      maxbackups: 3                                       # Optional, suggested: 3 (day)\n#      localtime: true                                     # Optional, suggested: true\n#      compress: true                                      # Optional, suggested: true\n#    loki:\n#      enabled: true                                       # Optional, default: false\n#      addr: localhost:3100                                # Optional, default: localhost:3100\n#      path: /loki/api/v1/push                             # Optional, default: /loki/api/v1/push\n#      username: \"\"                                        # Optional, default: \"\"\n#      password: \"\"                                        # Optional, default: \"\"\n#      maxBatchWaitMs: 3000                                # Optional, default: 3000\n#      maxBatchSize: 1000                                  # Optional, default: 1000\n#      insecureSkipVerify: false                           # Optional, default: false\n#      labels:                                             # Optional, default: empty map\n#        my_label_key: my_label_value\n#event:\n#  - name: my-event                                        # Required\n#    description: \"Description of entry\"                   # Optional\n#    domain: \"*\"                                           # Optional, default: \"*\"\n#    encoding: console                                     # Optional, default: console\n#    default: false                                        # Optional, default: false, use as default event entry\n#    outputPaths: [\"stdout\"]                               # Optional, default: [stdout]\n#    lumberjack:                                           # Optional, default: nil\n#      filename:\n#      maxsize: 1024                                       # Optional, suggested: 1024 (MB)\n#      maxage: 7                                           # Optional, suggested: 7 (day)\n#      maxbackups: 3                                       # Optional, suggested: 3 (day)\n#      localtime: true                                     # Optional, suggested: true\n#      compress: true                                      # Optional, suggested: true\n#    loki:\n#      enabled: true                                       # Optional, default: false\n#      addr: localhost:3100                                # Optional, default: localhost:3100\n#      path: /loki/api/v1/push                             # Optional, default: /loki/api/v1/push\n#      username: \"\"                                        # Optional, default: \"\"\n#      password: \"\"                                        # Optional, default: \"\"\n#      maxBatchWaitMs: 3000                                # Optional, default: 3000\n#      maxBatchSize: 1000                                  # Optional, default: 1000\n#      insecureSkipVerify: false                           # Optional, default: false\n#      labels:                                             # Optional, default: empty map\n#        my_label_key: my_label_value\n#cert:\n#  - name: my-cert                                         # Required\n#    description: \"Description of entry\"                   # Optional, default: \"\"\n#    domain: \"*\"                                           # Optional, default: \"*\"\n#    caPath: \"certs/ca.pem\"                                # Optional, default: \"\"\n#    certPemPath: \"certs/server-cert.pem\"                  # Optional, default: \"\"\n#    keyPemPath: \"certs/server-key.pem\"                    # Optional, default: \"\"\n#config:\n#  - name: my-config                                       # Required\n#    description: \"Description of entry\"                   # Optional, default: \"\"\n#    domain: \"*\"                                           # Optional, default: \"*\"\n##    path: \"config/config.yaml\"                            # Optional\n#    envPrefix: \"\"                                         # Optional, default: \"\"\n#    content:                                              # Optional, defualt: empty map\n#      key: value\ngrpc:\n  - name: greeter                                          # Required\n    enabled: true                                          # Required\n    port: 8080                                             # Required\n#    gwPort: 8081                                          # Optional, default: gateway port will be the same as grpc port if not provided \n#    description: \"greeter server\"                         # Optional, default: \"\"\n#    enableReflection: true                                # Optional, default: false\n#    enableRkGwOption: true                                # Optional, default: false\n#    grpcWeb:\n#      enabled: true\n#      cors:\n#        allowOrigins: []                                  # Optional, default: [*]\n#      websocket:\n#        enabled: true                                     # Optional, default: disable websocket\n#        pingIntervalMs: 10                                # Optional, default: disable ping\n#        messageReadLimitBytes: 32769                      # Optional, default: 32769\n#    gwOption:                                             # Optional, default: nil\n#      marshal:                                            # Optional, default: nil\n#        multiline: false                                  # Optional, default: false\n#        emitUnpopulated: false                            # Optional, default: false\n#        indent: \"\"                                        # Optional, default: false\n#        allowPartial: false                               # Optional, default: false\n#        useProtoNames: false                              # Optional, default: false\n#        useEnumNumbers: false                             # Optional, default: false\n#      unmarshal:                                          # Optional, default: nil\n#        allowPartial: false                               # Optional, default: false\n#        discardUnknown: false                             # Optional, default: false\n#    noRecvMsgSizeLimit: true                              # Optional, default: false\n#    certEntry: my-cert                                    # Optional, default: \"\", reference of cert entry declared above\n#    loggerEntry: my-logger                                # Optional, default: \"\", reference of cert entry declared above, STDOUT will be used if missing\n#    eventEntry: my-event                                  # Optional, default: \"\", reference of cert entry declared above, STDOUT will be used if missing\n#    sw:\n#      enabled: true                                       # Optional, default: false\n#      path: \"sw\"                                          # Optional, default: \"sw\"\n#      jsonPath: [\"\"]                                      # Optional\n#      headers: [\"sw:rk\"]                                  # Optional, default: []\n#    docs:\n#      enabled: true                                       # Optional, default: false\n#      path: \"docs\"                                        # Optional, default: \"docs\"\n#      specPath: \"\"                                        # Optional\n#      headers: [\"sw:rk\"]                                  # Optional, default: []\n#      style:                                              # Optional\n#        theme: \"light\"                                    # Optional, default: \"light\"\n#      debug: false                                        # Optional, default: false\n#    commonService:\n#      enabled: true                                       # Optional, default: false\n#    static:\n#      enabled: true                                       # Optional, default: false\n#      path: \"/static\"                                     # Optional, default: /static\n#      sourceType: local                                   # Required, options: pkger, local\n#      sourcePath: \".\"                                     # Required, full path of source directory\n#    pprof:\n#      enabled: true                                       # Optional, default: false\n#      path: \"/pprof\"                                      # Optional, default: /pprof\n#    prom:\n#      enabled: true                                       # Optional, default: false\n#      path: \"\"                                            # Optional, default: \"metrics\"\n#      pusher:\n#        enabled: false                                    # Optional, default: false\n#        jobName: \"greeter-pusher\"                         # Required\n#        remoteAddress: \"localhost:9091\"                   # Required\n#        basicAuth: \"user:pass\"                            # Optional, default: \"\"\n#        intervalMs: 10000                                 # Optional, default: 1000\n#        certEntry: my-cert                                # Optional, default: \"\", reference of cert entry declared above\n#    middleware:\n#      ignore: [\"\"]                                        # Optional, default: []\n#      errorModel: google                                  # Optional, default: google, [amazon, google] are supported options\n#      logging:\n#        enabled: true                                     # Optional, default: false\n#        ignore: [\"\"]                                      # Optional, default: []\n#        loggerEncoding: \"console\"                         # Optional, default: \"console\"\n#        loggerOutputPaths: [\"logs/app.log\"]               # Optional, default: [\"stdout\"]\n#        eventEncoding: \"console\"                          # Optional, default: \"console\"\n#        eventOutputPaths: [\"logs/event.log\"]              # Optional, default: [\"stdout\"]\n#      prom:\n#        enabled: true                                     # Optional, default: false\n#        ignore: [\"\"]                                      # Optional, default: []\n#      auth:\n#        enabled: true                                     # Optional, default: false\n#        ignore: [\"\"]                                      # Optional, default: []\n#        basic:\n#          - \"user:pass\"                                   # Optional, default: []\n#        apiKey:\n#          - \"keys\"                                        # Optional, default: []\n#      meta:\n#        enabled: true                                     # Optional, default: false\n#        ignore: [\"\"]                                      # Optional, default: []\n#        prefix: \"rk\"                                      # Optional, default: \"rk\"\n#      trace:\n#        enabled: true                                     # Optional, default: false\n#        ignore: [\"\"]                                      # Optional, default: []\n#        exporter:                                         # Optional, default will create a stdout exporter\n#          file:\n#            enabled: true                                 # Optional, default: false\n#            outputPath: \"logs/trace.log\"                  # Optional, default: stdout\n#          jaeger:\n#            agent:\n#              enabled: false                              # Optional, default: false\n#              host: \"\"                                    # Optional, default: localhost\n#              port: 0                                     # Optional, default: 6831\n#            collector:\n#              enabled: true                               # Optional, default: false\n#              endpoint: \"\"                                # Optional, default: http://localhost:14268/api/traces\n#              username: \"\"                                # Optional, default: \"\"\n#              password: \"\"                                # Optional, default: \"\"\n#      rateLimit:\n#        enabled: false                                    # Optional, default: false\n#        ignore: [\"\"]                                      # Optional, default: []\n#        algorithm: \"leakyBucket\"                          # Optional, default: \"tokenBucket\"\n#        reqPerSec: 100                                    # Optional, default: 1000000\n#        paths:\n#          - path: \"/rk/v1/healthy\"                        # Optional, default: \"\"\n#            reqPerSec: 0                                  # Optional, default: 1000000\n#      timeout:\n#        enabled: false                                    # Optional, default: false\n#        ignore: [\"\"]                                      # Optional, default: []\n#        timeoutMs: 5000                                   # Optional, default: 5000\n#        paths:\n#          - path: \"/rk/v1/healthy\"                        # Optional, default: \"\"\n#            timeoutMs: 1000                               # Optional, default: 5000\n#      jwt:\n#        enabled: true                                     # Optional, default: false\n#        ignore: [ \"\" ]                                    # Optional, default: []\n#        signerEntry: \"\"                                   # Optional, default: \"\"\n#        skipVerify: false                                 # Optional, default: false\n#        symmetric:                                        # Optional\n#          algorithm: \"\"                                   # Required, default: \"\"\n#          token: \"\"                                       # Optional, default: \"\"\n#          tokenPath: \"\"                                   # Optional, default: \"\"\n#        asymmetric:                                       # Optional\n#          algorithm: \"\"                                   # Required, default: \"\"\n#          privateKey: \"\"                                  # Optional, default: \"\"\n#          privateKeyPath: \"\"                              # Optional, default: \"\"\n#          publicKey: \"\"                                   # Optional, default: \"\"\n#          publicKeyPath: \"\"                               # Optional, default: \"\"\n#        tokenLookup: \"header:\u003cname\u003e\"                      # Optional, default: \"header:Authorization\"\n#        authScheme: \"Bearer\"                              # Optional, default: \"Bearer\"\n#      secure:\n#        enabled: true                                     # Optional, default: false\n#        ignore: [\"\"]                                      # Optional, default: []\n#        xssProtection: \"\"                                 # Optional, default: \"1; mode=block\"\n#        contentTypeNosniff: \"\"                            # Optional, default: nosniff\n#        xFrameOptions: \"\"                                 # Optional, default: SAMEORIGIN\n#        hstsMaxAge: 0                                     # Optional, default: 0\n#        hstsExcludeSubdomains: false                      # Optional, default: false\n#        hstsPreloadEnabled: false                         # Optional, default: false\n#        contentSecurityPolicy: \"\"                         # Optional, default: \"\"\n#        cspReportOnly: false                              # Optional, default: false\n#        referrerPolicy: \"\"                                # Optional, default: \"\"\n#      csrf:\n#        enabled: true                                     # Optional, default: false\n#        ignore: [\"\"]                                      # Optional, default: []\n#        tokenLength: 32                                   # Optional, default: 32\n#        tokenLookup: \"header:X-CSRF-Token\"                # Optional, default: \"header:X-CSRF-Token\"\n#        cookieName: \"_csrf\"                               # Optional, default: _csrf\n#        cookieDomain: \"\"                                  # Optional, default: \"\"\n#        cookiePath: \"\"                                    # Optional, default: \"\"\n#        cookieMaxAge: 86400                               # Optional, default: 86400\n#        cookieHttpOnly: false                             # Optional, default: false\n#        cookieSameSite: \"default\"                         # Optional, default: \"default\", options: lax, strict, none, default\n#      gzip:\n#        enabled: true                                     # Optional, default: false\n#        ignore: [\"\"]                                      # Optional, default: []\n#        level: bestSpeed                                  # Optional, options: [noCompression, bestSpeed， bestCompression, defaultCompression, huffmanOnly]\n#      cors:\n#        enabled: true                                     # Optional, default: false\n#        ignore: [\"\"]                                      # Optional, default: []\n#        allowOrigins:                                     # Optional, default: []\n#          - \"http://localhost:*\"                          # Optional, default: *\n#        allowCredentials: false                           # Optional, default: false\n#        allowHeaders: []                                  # Optional, default: []\n#        allowMethods: []                                  # Optional, default: []\n#        exposeHeaders: []                                 # Optional, default: []\n#        maxAge: 0                                         # Optional, default: 0\n```\n\n\u003c/details\u003e\n\n## Development Status: Stable\n\n## Build instruction\nSimply run make all to validate your changes. Or run codes in example/ folder.\n\n- make all\n\nRun unit-test, golangci-lint, doctoc and gofmt.\n\n- make buf\n\n## Test instruction\nRun unit test with **make test** command.\n\nGithub workflow will automatically run unit test and golangci-lint for testing and lint validation.\n\n## Contributing\nWe encourage and support an active, healthy community of contributors;\nincluding you! Details are in the [contribution guide](CONTRIBUTING.md) and\nthe [code of conduct](CODE_OF_CONDUCT.md). The rk maintainers keep an eye on\nissues and pull requests, but you can also report any negative conduct to\nlark@rkdev.info.\n\nReleased under the [Apache 2.0 License](LICENSE).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frookie-ninja%2Frk-grpc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frookie-ninja%2Frk-grpc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frookie-ninja%2Frk-grpc/lists"}