diff --git a/README.md b/README.md index f1afdef..ce6a16a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # GO GRPC BASIC ### Requirements ( Do It Letter ) +- +- ### Setup Project - create `proto` dir @@ -29,6 +31,7 @@ - create `router.go` in router dir and implement IgnoreErr, this is for ignore error so can be safely ignore - `go get golang.org/x/sync/errgroup`, is for ? - implement `main.go` to create grpc server from grpc.go with errgroup handler +- `go run .`, run server grpc - `go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest` - test `grpcurl -plaintext localhost:5566 list`, to show list name of services - test `grpcurl -plaintext localhost:5566 list api.gogrpc.v1.health.HealthService`, to show list name of service methods @@ -41,4 +44,31 @@ "desc": "SUCCESS" } ``` -- or test via postman , new -> grpc request -> Enter Server Url : localhost:5566 -> Import proto file / Select Method : Status -> Click Invoke \ No newline at end of file +- or test via postman , new -> grpc request -> Enter Server Url : localhost:5566 -> Import proto file / Select Method : Status -> Click Invoke + +### Implment gRPC-Gateway +ref https://github.com/grpc-ecosystem/grpc-gateway +- implement `import "google/api/annotations.proto";` in proto file +- changes line below in all service methods for rest compile to rest +``` +service HealthService { + rpc Status(google.protobuf.Empty) returns (Response) { + + option (google.api.http) = { + + get: "/api/gogrpc/v1/health/status" + + }; + } +} +``` +- re - compile / re - generate proto with `compile-proto.sh` in proto dir +- `go mod tidy` +- `go get "github.com/gorilla/handlers"` +- create `http.go` in router dir and implement NewHTTPServer and register health api service +- register httpserver to `main.go` +``` +g.Go(func() error { return router.NewHTTPServer(configs, logger) }) +``` +- `go run .` run grpc and http server +- test `curl localhost:8080/api/v1/health/status`, reponse +``` +{"success":true,"code":"0000","desc":"SUCCESS"} +``` \ No newline at end of file diff --git a/go.mod b/go.mod index 895dd77..7f3369a 100644 --- a/go.mod +++ b/go.mod @@ -7,18 +7,21 @@ require ( google.golang.org/protobuf v1.28.0 ) -require github.com/sirupsen/logrus v1.8.1 - require ( - github.com/soheilhy/cmux v0.1.5 // indirect - golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f // indirect + github.com/grpc-ecosystem/grpc-gateway v1.16.0 + github.com/sirupsen/logrus v1.8.1 + github.com/soheilhy/cmux v0.1.5 + golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f ) +require github.com/felixge/httpsnoop v1.0.1 // indirect + require ( - github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/protobuf v1.5.2 + github.com/gorilla/handlers v1.5.1 golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb // indirect golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 // indirect golang.org/x/text v0.3.3 // indirect - google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect + google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index f3c4d73..cbcf63d 100644 --- a/go.sum +++ b/go.sum @@ -20,6 +20,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= +github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -46,6 +48,9 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= +github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -74,7 +79,6 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= diff --git a/main.go b/main.go index a48ecd6..58d8f4a 100644 --- a/main.go +++ b/main.go @@ -49,6 +49,7 @@ func main() { }) g.Go(func() error { return router.NewGRPCServer(configs, logger) }) + g.Go(func() error { return router.NewHTTPServer(configs, logger) }) if err := g.Wait(); !router.IgnoreErr(err) { log.Printf("[SERVER] ERROR %v", err) diff --git a/proto/v1/health/health.pb.go b/proto/v1/health/health.pb.go index 6b1e135..c635630 100644 --- a/proto/v1/health/health.pb.go +++ b/proto/v1/health/health.pb.go @@ -8,6 +8,7 @@ package health import ( context "context" + _ "google.golang.org/genproto/googleapis/api/annotations" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" @@ -93,23 +94,27 @@ var File_v1_health_health_proto protoreflect.FileDescriptor var file_v1_health_health_proto_rawDesc = []byte{ 0x0a, 0x16, 0x76, 0x31, 0x2f, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x2f, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x14, 0x61, 0x70, 0x69, 0x2e, 0x67, 0x6f, - 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x1a, 0x1b, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, - 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x4c, 0x0a, 0x08, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x63, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x65, 0x73, 0x63, 0x32, 0x53, 0x0a, 0x0d, 0x48, 0x65, 0x61, - 0x6c, 0x74, 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x42, 0x0a, 0x06, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1e, 0x2e, 0x61, - 0x70, 0x69, 0x2e, 0x67, 0x6f, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x68, 0x65, 0x61, - 0x6c, 0x74, 0x68, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x37, - 0x5a, 0x35, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x6a, 0x69, - 0x6b, 0x61, 0x6d, 0x61, 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x2f, 0x67, 0x6f, 0x2d, 0x67, 0x72, 0x70, - 0x63, 0x5f, 0x62, 0x61, 0x73, 0x69, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x31, - 0x2f, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x1a, 0x1c, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, + 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x4c, 0x0a, 0x08, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, + 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, + 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x64, 0x65, 0x73, 0x63, 0x32, 0x70, 0x0a, 0x0d, 0x48, 0x65, 0x61, 0x6c, 0x74, + 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5f, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1e, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x67, 0x6f, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x68, 0x65, 0x61, 0x6c, 0x74, + 0x68, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x17, 0x12, 0x15, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x68, 0x65, 0x61, 0x6c, + 0x74, 0x68, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x37, 0x5a, 0x35, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x6a, 0x69, 0x6b, 0x61, 0x6d, 0x61, 0x6c, + 0x75, 0x64, 0x69, 0x6e, 0x2f, 0x67, 0x6f, 0x2d, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x62, 0x61, 0x73, + 0x69, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x31, 0x2f, 0x68, 0x65, 0x61, 0x6c, + 0x74, 0x68, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/proto/v1/health/health.pb.gw.go b/proto/v1/health/health.pb.gw.go new file mode 100644 index 0000000..0c7f161 --- /dev/null +++ b/proto/v1/health/health.pb.gw.go @@ -0,0 +1,154 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: v1/health/health.proto + +/* +Package health is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package health + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/emptypb" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage +var _ = metadata.Join + +func request_HealthService_Status_0(ctx context.Context, marshaler runtime.Marshaler, client HealthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq emptypb.Empty + var metadata runtime.ServerMetadata + + msg, err := client.Status(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_HealthService_Status_0(ctx context.Context, marshaler runtime.Marshaler, server HealthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq emptypb.Empty + var metadata runtime.ServerMetadata + + msg, err := server.Status(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterHealthServiceHandlerServer registers the http handlers for service HealthService to "mux". +// UnaryRPC :call HealthServiceServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterHealthServiceHandlerFromEndpoint instead. +func RegisterHealthServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server HealthServiceServer) error { + + mux.Handle("GET", pattern_HealthService_Status_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_HealthService_Status_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_HealthService_Status_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterHealthServiceHandlerFromEndpoint is same as RegisterHealthServiceHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterHealthServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterHealthServiceHandler(ctx, mux, conn) +} + +// RegisterHealthServiceHandler registers the http handlers for service HealthService to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterHealthServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterHealthServiceHandlerClient(ctx, mux, NewHealthServiceClient(conn)) +} + +// RegisterHealthServiceHandlerClient registers the http handlers for service HealthService +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "HealthServiceClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "HealthServiceClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "HealthServiceClient" to call the correct interceptors. +func RegisterHealthServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client HealthServiceClient) error { + + mux.Handle("GET", pattern_HealthService_Status_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_HealthService_Status_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_HealthService_Status_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_HealthService_Status_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "v1", "health", "status"}, "", runtime.AssumeColonVerbOpt(true))) +) + +var ( + forward_HealthService_Status_0 = runtime.ForwardResponseMessage +) diff --git a/proto/v1/health/health.proto b/proto/v1/health/health.proto index cce32cf..98105a7 100644 --- a/proto/v1/health/health.proto +++ b/proto/v1/health/health.proto @@ -4,7 +4,7 @@ package api.gogrpc.v1.health; option go_package = "github.com/ajikamaludin/go-grpc_basic/proto/v1/health"; -// import "lib/google/api/annotations.proto"; +import "google/api/annotations.proto"; import "google/protobuf/empty.proto"; message Response { @@ -14,5 +14,9 @@ message Response { } service HealthService { - rpc Status(google.protobuf.Empty) returns (Response) {} + rpc Status(google.protobuf.Empty) returns (Response) { + option (google.api.http) = { + get: "/api/v1/health/status" + }; + } } \ No newline at end of file diff --git a/router/http.go b/router/http.go new file mode 100644 index 0000000..2f2e394 --- /dev/null +++ b/router/http.go @@ -0,0 +1,76 @@ +package router + +import ( + "context" + "fmt" + "log" + "net/http" + + "github.com/ajikamaludin/go-grpc_basic/configs" + hlpb "github.com/ajikamaludin/go-grpc_basic/proto/v1/health" + "github.com/gorilla/handlers" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/sirupsen/logrus" + "google.golang.org/grpc" +) + +func NewHTTPServer(configs *configs.Configs, loggger *logrus.Logger) error { + + ctx := context.Background() + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + // Connect to the GRPC server + address := fmt.Sprintf("0.0.0.0:%v", configs.Config.Server.Grpc.Port) + conn, err := grpc.Dial(address, grpc.WithInsecure()) + if err != nil { + return err + } + defer conn.Close() + + // Create new grpc-gateway + rmux := runtime.NewServeMux() + + // register gateway endpoints + for _, f := range []func(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error{ + // register grpc service handler + hlpb.RegisterHealthServiceHandler, + } { + if err = f(ctx, rmux, conn); err != nil { + return err + } + } + + mux := http.NewServeMux() + mux.Handle("/", rmux) + + // if configs.Config.Env != constants.EnvProduction { + // CreateSwagger(mux) + // } + + headerOk := handlers.AllowedHeaders([]string{"Accept", "Accept-Language", "Content-Language", "Content-Type", "X-Requested-With", "Content-Length", "Accept-Encoding", "X-CSRF-Token", "Authorization", "Timezone-Offset"}) + originsOk := handlers.AllowedOrigins([]string{"*"}) + methodsOk := handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "OPTIONS"}) + + // running rest http server + log.Println("[SERVER] REST HTTP server is ready") + + err = http.ListenAndServe(fmt.Sprintf("0.0.0.0:%v", configs.Config.Server.Rest.Port), handlers.CORS(headerOk, originsOk, methodsOk)(mux)) + if err != nil { + return err + } + + return nil +} + +// // CreateSwagger creates the swagger server serve mux. +// func CreateSwagger(gwmux *http.ServeMux) { +// // register swagger service server +// gwmux.HandleFunc("/api/health/docs.json", func(w http.ResponseWriter, r *http.Request) { +// http.ServeFile(w, r, "swagger/docs.json") +// }) + +// // load swagger-ui file +// fs := http.FileServer(http.Dir("swagger/swagger-ui")) +// gwmux.Handle("/api/health/docs/", http.StripPrefix("/api/health/docs", fs)) +// }