{"id":15399464,"url":"https://github.com/chai2010/pbgo-grpc","last_synced_at":"2026-05-03T19:32:32.042Z","repository":{"id":57598594,"uuid":"167108752","full_name":"chai2010/pbgo-grpc","owner":"chai2010","description":"pbgo grpc/rest examples","archived":false,"fork":false,"pushed_at":"2020-07-05T09:47:13.000Z","size":54,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-03-25T22:51:57.541Z","etag":null,"topics":["gateway","go","golang","grpc","pbgo","protobuf"],"latest_commit_sha":null,"homepage":"https://github.com/chai2010/pbgo","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chai2010.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-01-23T03:14:06.000Z","updated_at":"2022-08-28T06:23:20.000Z","dependencies_parsed_at":"2022-08-30T01:51:09.009Z","dependency_job_id":null,"html_url":"https://github.com/chai2010/pbgo-grpc","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/chai2010/pbgo-grpc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chai2010%2Fpbgo-grpc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chai2010%2Fpbgo-grpc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chai2010%2Fpbgo-grpc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chai2010%2Fpbgo-grpc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chai2010","download_url":"https://codeload.github.com/chai2010/pbgo-grpc/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chai2010%2Fpbgo-grpc/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32582622,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-03T06:36:36.687Z","status":"ssl_error","status_checked_at":"2026-05-03T06:36:09.306Z","response_time":103,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["gateway","go","golang","grpc","pbgo","protobuf"],"created_at":"2024-10-01T15:48:59.828Z","updated_at":"2026-05-03T19:32:32.029Z","avatar_url":"https://github.com/chai2010.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"- *Go语言QQ群: 102319854, 1055927514*\n- *凹语言(凹读音“Wa”)(The Wa Programming Language): https://github.com/wa-lang/wa*\n\n----\n\n# pbgo-examples\n\n- https://github.com/chai2010/pbgo\n\n## Proto File(hello.proto)\n\n```protobuf\nsyntax = \"proto3\";\n\npackage hello_pb;\n\nimport \"github.com/chai2010/pbgo/pbgo.proto\";\n\nmessage String {\n\tstring value = 1;\n}\nmessage StaticFile {\n\tstring content_type = 1;\n\tbytes content_body = 2;\n}\n\nmessage Message {\n\tstring value = 1;\n\trepeated int32 array = 2;\n\tmap\u003cstring,string\u003e dict = 3;\n\tString subfiled = 4;\n}\n\nservice HelloService {\n\toption (pbgo.service_opt) = {\n\t\trename: \"PBGOHelloService\"\n\t};\n\n\trpc Hello (String) returns (String) {\n\t\toption (pbgo.rest_api) = {\n\t\t\tget: \"/hello/:value\"\n\t\t\tpost: \"/hello\"\n\n\t\t\tadditional_bindings {\n\t\t\t\tmethod: \"DELETE\"; url: \"/hello\"\n\t\t\t}\n\t\t\tadditional_bindings {\n\t\t\t\tmethod: \"PATCH\"; url: \"/hello\"\n\t\t\t}\n\t\t};\n\t}\n\trpc Echo (Message) returns (Message) {\n\t\toption (pbgo.rest_api) = {\n\t\t\tget: \"/echo/:subfiled.value\"\n\t\t};\n\t}\n\trpc Static(String) returns (StaticFile) {\n\t\toption (pbgo.rest_api) = {\n\t\t\tadditional_bindings {\n\t\t\t\tmethod: \"GET\"\n\t\t\t\turl: \"/static/:value\"\n\t\t\t\tcontent_type: \":content_type\"\n\t\t\t\tcontent_body: \":content_body\"\n\t\t\t}\n\t\t};\n\t}\n\n\trpc ServerStream(String) returns (stream String);\n\trpc ClientStream(stream String) returns (String);\n\trpc Channel(stream String) returns (stream String);\n}\n```\n\nGenerate stub code:\n\n```\n$ go install github.com/chai2010/pbgo-grpc/protoc-gen-pbgo-grpc\n$ protoc -I=. -I=./api/third_party --pbgo-grpc_out=plugins=grpc+pbgo:. hello.proto\n```\n\n## Example\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"flag\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"mime\"\n\t\"net\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/metadata\"\n\t\"google.golang.org/grpc/reflection\"\n\n\tctxpkg \"github.com/chai2010/pbgo-grpc/context\"\n\tpb \"github.com/chai2010/pbgo-grpc/example/api\"\n)\n\nvar (\n\t_ pb.HelloServiceServer = (*HelloService)(nil)\n)\n\nvar (\n\tflagRoot = flag.String(\"root\", \"./testdata\", \"set root dir\")\n)\n\nfunc init() {\n\tlog.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)\n}\n\nfunc main() {\n\tflag.Parse()\n\n\thelloService := NewHelloService(*flagRoot)\n\n\tgo func() {\n\t\tgrpcServer := grpc.NewServer()\n\t\treflection.Register(grpcServer)\n\n\t\tpb.RegisterHelloServiceServer(grpcServer, helloService)\n\n\t\tlog.Println(\"grpc server on :3999\")\n\t\tlis, err := net.Listen(\"tcp\", \":3999\")\n\t\tif err != nil {\n\t\t\tlog.Fatal(err)\n\t\t}\n\t\tgrpcServer.Serve(lis)\n\t}()\n\n\tctx := context.Background()\n\trouter := pb.PBGOHelloServiceGrpcHandler(\n\t\tctx, helloService,\n\t\tfunc(ctx context.Context, req *http.Request) (context.Context, error) {\n\t\t\tif methodName == \"HelloService.Echo\" {\n\t\t\t\treturn ctxpkg.AnnotateOutgoingContext(ctx, req, nil)\n\t\t\t} else {\n\t\t\t\treturn ctxpkg.AnnotateIncomingContext(ctx, req, nil)\n\t\t\t}\n\t\t},\n\t)\n\n\tlog.Println(\"http server on :8080\")\n\tlog.Fatal(http.ListenAndServe(\":8080\", someMiddleware(router)))\n}\n\nfunc someMiddleware(next http.Handler) http.Handler {\n\treturn http.HandlerFunc(func(wr http.ResponseWriter, r *http.Request) {\n\t\ttimeStart := time.Now()\n\t\tdefer func() {\n\t\t\ttimeElapsed := time.Since(timeStart)\n\t\t\tlog.Println(r.Method, r.URL, timeElapsed)\n\t\t}()\n\n\t\tnext.ServeHTTP(wr, r)\n\t})\n}\n\ntype HelloService struct {\n\trootdir string\n}\n\nfunc NewHelloService(rootdir string) *HelloService {\n\treturn \u0026HelloService{\n\t\trootdir: rootdir,\n\t}\n}\n\nfunc (p *HelloService) Hello(ctx context.Context, req *pb.String) (*pb.String, error) {\n\tlog.Printf(\"HelloService.Hello: req = %v\\n\", req)\n\n\t// curl -H \"Grpc-Metadata-user-id: chai2010\" localhost:8080/hello/gopher\n\t// curl -H \"Grpc-Metadata-user-password-Bin: MTIzNDU2\" localhost:8080/hello/gopher\n\t// base64(\"123456\"): MTIzNDU2\n\tif md, ok := metadata.FromIncomingContext(ctx); ok {\n\t\tlog.Printf(\"metadata.user-id: %v\\n\", md[\"user-id\"])\n\t\tlog.Printf(\"metadata.user-password-bin: %v\\n\", md[\"user-password-bin\"])\n\t} else {\n\t\tlog.Println(\"no metadata\")\n\t}\n\n\treply := \u0026pb.String{Value: \"hello:\" + req.GetValue()}\n\treturn reply, nil\n}\n\nfunc (p *HelloService) Echo(ctx context.Context, req *pb.Message) (*pb.Message, error) {\n\tlog.Printf(\"HelloService.Echo: req = %v\\n\", req)\n\n\t// curl -H \"Grpc-Metadata-user-id: chai2010\" localhost:8080/echo/gopher\n\t// curl -H \"Grpc-Metadata-user-password-Bin: MTIzNDU2\" localhost:8080/echo/gopher\n\t// base64(\"123456\"): MTIzNDU2\n\tconn, err := grpc.Dial(\"localhost:3999\", grpc.WithInsecure())\n\tif err != nil {\n\t\tlog.Println(err)\n\t\treturn nil, err\n\t}\n\tdefer conn.Close()\n\n\tclient := pb.NewHelloServiceClient(conn)\n\tresult, err := client.Hello(ctx, \u0026pb.String{Value: \"hello\"})\n\tif err != nil {\n\t\tlog.Println(err)\n\t\treturn nil, err\n\t}\n\n\treply := \u0026pb.Message{\n\t\tValue: result.GetValue(),\n\t}\n\n\treturn reply, nil\n}\n\nfunc (p *HelloService) Static(ctx context.Context, req *pb.String) (*pb.StaticFile, error) {\n\tlog.Printf(\"HelloService.Static: req = %v\\n\", req)\n\n\tdata, err := ioutil.ReadFile(p.rootdir + \"/\" + req.Value)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treply := new(pb.StaticFile)\n\treply.ContentType = mime.TypeByExtension(req.Value)\n\treply.ContentBody = data\n\treturn reply, nil\n}\n\nfunc (p *HelloService) ServerStream(*pb.String, pb.HelloService_ServerStreamServer) error {\n\tlog.Printf(\"HelloService.ServerStream: todo\\n\")\n\n\treturn errors.New(\"todo\")\n}\n\nfunc (p *HelloService) ClientStream(pb.HelloService_ClientStreamServer) error {\n\tlog.Printf(\"HelloService.ClientStream: todo\\n\")\n\n\treturn errors.New(\"todo\")\n}\n\nfunc (p *HelloService) Channel(pb.HelloService_ChannelServer) error {\n\tlog.Printf(\"HelloService.Channel: todo\\n\")\n\n\treturn errors.New(\"todo\")\n}\n```\n\nStart gRPC \u0026 Rest server:\n\n```\ngo run server.go\n```\n\nRest API:\n\n```\n$ curl localhost:8080/hello/gopher\n{\"value\":\"hello:gopher\"}\n$ curl localhost:8080/hello/gopher?value=vgo\n{\"value\":\"hello:vgo\"}\n$ curl localhost:8080/hello -X POST --data '{\"value\":\"cgo\"}'\n{\"value\":\"hello:cgo\"}\n\n$ curl localhost:8080/echo/gopher\n{\"subfiled\":{\"value\":\"gopher\"}}\n$ curl \"localhost:8080/echo/gopher?array=123\u0026array=456\"\n{\"array\":[123,456],\"subfiled\":{\"value\":\"gopher\"}}\n$ curl \"localhost:8080/echo/gopher?dict%5Babc%5D=123\"\n{\"dict\":{\"abc\":\"123\"},\"subfiled\":{\"value\":\"gopher\"}}\n\n$ curl localhost:8080/static/gopher.png\n$ curl localhost:8080/static/hello.txt\n```\n\ngRPC Context:\n\n```\n$ curl -H \"Grpc-Metadata-user-id: chai2010\" localhost:8080/hello/gopher\n$ curl -H \"Grpc-Metadata-user-password-Bin: MTIzNDU2\" localhost:8080/hello/gopher\n$ curl -H \"Grpc-Metadata-user-id: chai2010\" localhost:8080/echo/gopher\n$ curl -H \"Grpc-Metadata-user-password-Bin: MTIzNDU2\" localhost:8080/echo/gopher\n```\n\ngRPC API:\n\n```\n$ grpcurl -plaintext localhost:3999 list\n```\n\n## BUGS\n\nReport bugs to \u003cchaishushan@gmail.com\u003e.\n\nThanks!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchai2010%2Fpbgo-grpc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchai2010%2Fpbgo-grpc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchai2010%2Fpbgo-grpc/lists"}