### Install gRPC Binaries Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/readme.md Installs the necessary gRPC binaries using 'go get' and 'go install'. Ensure your $GOBIN is in your $PATH. ```bash go get github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2 go install google.golang.org/protobuf/cmd/protoc-gen-go go install google.golang.org/grpc/cmd/protoc-gen-go-grpc ``` -------------------------------- ### CLI Client Configuration Example Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/README.md Example of how to configure and run the client using command-line flags to create a cell. ```bash go run cmd/client/main.go -a 192.168.1.100 -p 9000 create cell robot-1 ``` -------------------------------- ### Create and Start Server Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/api-reference-server.md Instantiates a new Server with configuration and starts its gRPC and reverse proxy serving routines. Ensure all necessary parameters like addresses, ports, logger, and a channel for shutdown signaling are provided. ```go package main import ( "context" "demoserver/pkg/server" "log" "os" ) func main() { logger := log.New(os.Stdout, "", log.LstdFlags) closedCh := make(chan struct{}) srv := server.New("0.0.0.0", "8081", "8080", logger, &closedCh) ctx := context.Background() go srv.Serve(ctx) go srv.ServeReverseProxy(ctx) <-closedCh } ``` -------------------------------- ### Go Client Library Get Cell Example Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/README.md Example demonstrating how to use the Go client library to retrieve a cell's status by its UUID. Ensure necessary imports and client initialization. ```go import ( "context" "demoserver/pkg/client" "log" ) logger := log.Default() client := client.New("127.0.0.1", "8081", logger) cell, err := client.GetCell(context.Background(), &api.Identifier{Uuid: "robot-1"}) if err != nil { log.Fatal(err) } log.Printf("Cell status: %s", cell.Status) ``` -------------------------------- ### Programmatic Client Configuration Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/README.md Example of initializing a client programmatically with a specified address, port, and logger. ```go client := client.New("192.168.1.100", "9000", logger) ``` -------------------------------- ### Start gRPC Server and Gracefully Shutdown Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/api-reference-server.md Starts the gRPC server and listens for incoming requests. Use a context to manage the server's lifecycle and ensure graceful shutdown. ```go ctx := context.Background() go srv.Serve(ctx) // Later, to gracefully shutdown: cancel() <-closedCh ``` -------------------------------- ### GetCell Go Client Example Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/grpc-service-reference.md Demonstrates how to call the GetCell RPC from a Go client. Requires the api and context packages. ```go req := &api.GetCellRequest{ Identity: &api.Identifier{Uuid: "robot-1"}, } resp, err := client.GetCell(ctx, req) if err != nil { log.Fatal(err) } fmt.Printf("Status: %s\n", resp.Status) ``` -------------------------------- ### CLI Client Usage Examples Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/configuration.md Demonstrates how to run the CLI client with default and overridden address/port values using short and long flag formats. ```bash go run cmd/client/main.go -a 192.168.1.100 get cell robot-1 go run cmd/client/main.go --address 192.168.1.100 get cell robot-1 ``` ```bash go run cmd/client/main.go -p 50051 get cell robot-1 go run cmd/client/main.go --port 50051 get cell robot-1 ``` ```bash # Use defaults (127.0.0.1:8081) go run cmd/client/main.go create cell robot-1 # Override address go run cmd/client/main.go -a 10.0.0.1 create cell robot-1 # Override both address and port go run cmd/client/main.go -a 10.0.0.1 -p 9000 create cell robot-1 # Long form go run cmd/client/main.go --address 10.0.0.1 --port 9000 get cell robot-1 ``` -------------------------------- ### Start the gRPC Server Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/README.md Navigate to the project directory and set environment variables for server address and ports before running the main server application. ```bash cd /workspace/home/grpc-rest-openapi export SERVER_ADDR=0.0.0.0 export SERVER_PORT=8081 export PROXY_SERVER_PORT=8080 go run cmd/server/main.go ``` -------------------------------- ### Start HTTP Reverse Proxy and Observe Client Calls Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/api-reference-server.md Starts the HTTP reverse proxy, which translates REST calls to gRPC. It binds to a specified port and forwards requests to the gRPC server. Clients can then interact via HTTP. ```go ctx := context.Background() go srv.ServeReverseProxy(ctx) // REST client can now call: // GET http://localhost:8080/v1/cells/{uuid} // POST http://localhost:8080/v1/cells ``` -------------------------------- ### Update Cell Response Example Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/endpoints.md Example of a successful response after updating a Cell resource. ```json { "identity": { "uuid": "cell-001" }, "status": "online" } ``` -------------------------------- ### Custom Server File Logging Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/configuration.md Example of setting up custom file logging for the server. It demonstrates opening a file and creating a logger that writes to both the file and standard output. ```go package main import ( "log" "os" ) func main() { // File logging f, _ := os.OpenFile("server.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) logger := log.New(f, "[SERVER] ", log.LstdFlags|log.Lshortfile) // Or: combine file and stdout w := io.MultiWriter(os.Stdout, f) logger := log.New(w, "[SERVER] ", log.LstdFlags) } ``` -------------------------------- ### REST Health Check Example Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/grpc-service-reference.md Shows how to perform a health check using a simple HTTP GET request to the /health endpoint. ```bash curl -X GET http://localhost:8080/health ``` -------------------------------- ### GetCell REST Example Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/grpc-service-reference.md Shows how to make a GET request to the /v1/cells/{identity.uuid} endpoint using curl. ```bash curl -X GET http://localhost:8080/v1/cells/robot-1 ``` -------------------------------- ### gRPC CLI Client Operations Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/README.md Examples of using the gRPC CLI client to perform create, get, and update operations on cells. ```bash # Create a Cell go run cmd/client/main.go create cell robot-1 offline # Get a Cell go run cmd/client/main.go get cell robot-1 # Update a Cell go run cmd/client/main.go update cell robot-1 online ``` -------------------------------- ### Create Cell Response Example Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/endpoints.md Example of a successful response when creating a cell, showing the assigned or provided identity and status. ```json { "identity": { "uuid": "cell-001" }, "status": "offline" } ``` -------------------------------- ### Start gRPC Server Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/readme.md Run the main server application. The terminal will block until the application is exited. ```bash go run cmd/server/main.go # 2022/04/02 22:46:13 SERVER_ADDR: 0.0.0.0 # 2022/04/02 22:46:13 SERVER_PORT: 8081 # 2022/04/02 22:46:13 PROXY_SERVER_PORT: 8080 # 2022/04/02 22:46:13 starting reverse-proxy server on 0.0.0.0:8080 ``` -------------------------------- ### Serve Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/api-reference-server.md Starts the gRPC server on the configured address and port. This method blocks until the provided context is cancelled or a fatal error occurs. ```APIDOC ## Serve ### Description Starts the gRPC server on the configured address and port. Blocks until the context is cancelled or a fatal error occurs. ### Method `Serve` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Behavior: - Binds to `serverAddr:serverPort` using TCP - Registers gRPC reflection for service discovery - Registers `CellService` implementation - Gracefully stops when context is cancelled - Signals shutdown via the `serverClosedCh` channel ### Error Handling: - Network bind failures are logged but do not cause panic - Server shutdown errors are logged ### Example: ```go ctx := context.Background() gs := s.Serve(ctx) // Later, to gracefully shutdown: cancel() <-closedCh ``` ``` -------------------------------- ### Install gRPC Gateway Build Tools Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/readme.md Defines the build dependencies for grpc-gateway and related tools. Run 'go mod tidy' to resolve versions. ```go // +build tools package tools import ( _ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway" _ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2" _ "google.golang.org/grpc/cmd/protoc-gen-go-grpc" _ "google.golang.org/protobuf/cmd/protoc-gen-go" ) ``` -------------------------------- ### GetCell Request Example Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/api-reference-server.md Demonstrates how to construct a request to retrieve a Cell resource using its UUID. This is useful for fetching specific cell details. ```go req := &api.GetCellRequest{ Identity: &api.Identifier{Uuid: "cell-123"}, } cell, err := srv.GetCell(ctx, req) if err != nil { log.Printf("Error: %v\n", err) return } fmt.Printf("Cell status: %s\n", cell.Status) ``` -------------------------------- ### Run Local gRPC Server and Client Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/configuration.md Starts the gRPC server and then runs a client to create a cell resource. Uses default ports. ```bash # Server export SERVER_ADDR=0.0.0.0 export SERVER_PORT=8081 export PROXY_SERVER_PORT=8080 go run cmd/server/main.go # In another terminal, Client go run cmd/client/main.go create cell robot-1 ``` -------------------------------- ### Create Cell Response with Auto-Generated UUID Example Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/endpoints.md Example response after creating a cell where the UUID was auto-generated by the server. ```json { "identity": { "uuid": "f47ac10b-58cc-4372-a567-0e02b2c3d479" }, "status": "offline" } ``` -------------------------------- ### Create Cell with Custom Address, Port, and Status Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/commands-cli.md This example demonstrates creating a Cell resource with a custom server address, port, and an explicit status, combining global flags with the create command. ```bash go run cmd/client/main.go -a 192.168.1.100 -p 9000 create cell robot-1 online ``` -------------------------------- ### Storage Layer Migration Example Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/architecture.md Illustrates the change required to migrate from an in-memory map to a database storage layer. This change is localized to the storage implementation, keeping RPC methods unaffected. ```go // Before: cells[id] = cell // After: db.SaveCell(cell) ``` -------------------------------- ### Add GOBIN to PATH Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/readme.md Exports the GOBIN directory to the system's PATH environment variable to make installed binaries accessible. ```bash export PATH="$PATH:$(go env GOPATH)/bin" ``` -------------------------------- ### Health Check Response Example Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/endpoints.md Example of a successful response from the health check endpoint, indicating server health and the current time. ```json { "healthy": true, "currentTime": "2022-04-02T22:46:13Z" } ``` -------------------------------- ### gRPC Status Method Example (Go Client) Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/grpc-service-reference.md Demonstrates how to call the Status method on the CellService client. Requires context and an empty protobuf message. Handles potential errors and prints the health status and current time. ```Go import ( "context" "google.golang.org/protobuf/types/known/emptypb" ) client := api.NewCellServiceClient(conn) resp, err := client.Status(ctx, &emptypb.Empty{}) if err != nil { log.Fatal(err) } fmt.Printf("Healthy: %v, Time: %v\n", resp.Healthy, resp.CurrentTime) ``` -------------------------------- ### Example JSON Serialization Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/types.md Demonstrates the canonical JSON encoding of a protobuf message, showing camelCase field names and specific timestamp formats. ```json { "identity": { "uuid": "robot-1" }, "status": "online" } ``` -------------------------------- ### Create Cell Error Response Example Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/endpoints.md Example of an error response when creating a cell, typically due to validation errors like missing required fields. ```json { "code": 3, "message": "Invalid argument: missing required field 'cell'", "details": [] } ``` -------------------------------- ### Marshal Identifier to Go Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/types.md Example of creating an Identifier object in Go. This is used for representing unique resource identifiers. ```go id := &api.Identifier{Uuid: "cell-123"} // JSON representation: // { // "uuid": "cell-123" // } ``` -------------------------------- ### UpdateCell Go Client Example Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/grpc-service-reference.md Demonstrates how to call the UpdateCell RPC from a Go client, specifying fields to update using FieldMask. Requires api, context, and fieldmaskpb packages. ```go req := &api.UpdateCellRequest{ Identity: &api.Identifier{Uuid: "robot-1"}, Cell: &api.Cell{ Identity: &api.Identifier{Uuid: "robot-1"}, Status: "online", }, UpdateMask: &fieldmaskpb.FieldMask{ Paths: []string{"status"}, }, } resp, err := client.UpdateCell(ctx, req) if err != nil { log.Fatal(err) } fmt.Printf("Updated status to: %s\n", resp.Status) ``` -------------------------------- ### Go Marshal Example for CreateCellRequest Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/types.md Demonstrates how to marshal a CreateCellRequest into its JSON representation in Go. The Cell object and its identity UUID are specified. ```go req := &api.CreateCellRequest{ Cell: &api.Cell{ Identity: &api.Identifier{Uuid: "robot-1"}, Status: "offline", }, } // JSON representation: // { // "cell": { // "identity": { // "uuid": "robot-1" // }, // "status": "offline" // } // } ``` -------------------------------- ### REST Client Timeout Configuration with curl Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/errors.md This example demonstrates setting a 10-second connect timeout and a 10-second maximum time for a REST request using curl. ```bash # 10-second timeout curl --connect-timeout 10 -m 10 http://127.0.0.1:8080/v1/cells/test-1 ``` -------------------------------- ### Register gRPC Service Server Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/grpc-service-reference.md Registers a gRPC service implementation with a gRPC server. This is typically done once during server setup. ```go func RegisterCellServiceServer(s grpc.ServiceRegistrar, srv CellServiceServer) { s.RegisterService(&CellService_ServiceDesc, srv) } ``` -------------------------------- ### gRPC CreateCell Method Example (Go Client) Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/grpc-service-reference.md Illustrates creating a new Cell resource using the CreateCell method. Constructs a CreateCellRequest with cell identity and status, then sends it to the client. Handles errors and prints the created cell's UUID. ```Go req := &api.CreateCellRequest{ Cell: &api.Cell{ Identity: &api.Identifier{Uuid: "robot-1"}, Status: "offline", }, } resp, err := client.CreateCell(ctx, req) if err != nil { log.Fatal(err) } fmt.Printf("Created cell: %v\n", resp.Identity.Uuid) ``` -------------------------------- ### REST CreateCell Example Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/grpc-service-reference.md Demonstrates creating a Cell resource via a REST API call. Uses a POST request to /v1/cells with a JSON payload containing the cell's identity and status. ```bash curl -X POST http://localhost:8080/v1/cells \ -H 'Content-Type: application/json' \ -d '{ "identity": {"uuid": "robot-1"}, "status": "offline" }' ``` -------------------------------- ### ServeReverseProxy Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/api-reference-server.md Starts the HTTP reverse proxy server that translates REST calls to gRPC. This method blocks until the provided context is cancelled or a fatal error occurs. ```APIDOC ## ServeReverseProxy ### Description Starts the HTTP reverse proxy server that translates REST calls to gRPC. Blocks until context is cancelled or a fatal error occurs. ### Method `ServeReverseProxy` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Behavior: - Binds to `serverAddr:proxyPort` using HTTP - Dials the gRPC server at `serverAddr:serverPort` - Registers `CellService` handler from the gRPC endpoint - Uses gRPC gateway runtime to translate REST to gRPC - Gracefully shuts down when context is cancelled - Signals shutdown via the `serverClosedCh` channel ### Error Handling: - Handler registration failures are logged - Shutdown errors are logged ### Example: ```go ctx := context.Background() gs := s.ServeReverseProxy(ctx) // REST client can now call: // GET http://localhost:8080/v1/cells/{uuid} // POST http://localhost:8080/v1/cells ``` ``` -------------------------------- ### gRPC NOT_FOUND Error Example Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/errors.md Demonstrates triggering a NOT_FOUND error by calling GetCell with a non-existent UUID. This error typically indicates that a requested resource does not exist. ```go _, err := client.GetCell(ctx, &api.Identifier{Uuid: "nonexistent"}) // Error: rpc error: code = Unknown desc = cell with ID nonexistent not found ``` -------------------------------- ### Run gRPC Server and Client on Remote Host Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/configuration.md Starts the gRPC server on a specified IP address and runs a client from a different machine to access it. Allows specifying the server address. ```bash # Server (on 192.168.1.100) export SERVER_ADDR=0.0.0.0 export SERVER_PORT=8081 export PROXY_SERVER_PORT=8080 go run cmd/server/main.go # Client (from different machine) go run cmd/client/main.go -a 192.168.1.100 get cell robot-1 ``` -------------------------------- ### UpdateCell Request Example Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/api-reference-server.md Shows how to update an existing Cell resource with selective field updates using a field mask. This method allows for partial updates to a cell's properties. ```go req := &api.UpdateCellRequest{ Identity: &api.Identifier{Uuid: "cell-123"}, Cell: &api.Cell{ Identity: &api.Identifier{Uuid: "cell-123"}, Status: "online", }, UpdateMask: &fieldmaskpb.FieldMask{ Paths: []string{"status"}, }, } updated, err := srv.UpdateCell(ctx, req) if err != nil { log.Fatal(err) } fmt.Printf("Updated cell status to: %s\n", updated.Status) ``` -------------------------------- ### Get Cell Error Responses Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/endpoints.md Examples of error responses for Get Cell requests, including not found (404) and invalid UUID format (400). ```json { "code": 5, "message": "cell with ID cell-001 not found", "details": [] } ``` ```json { "code": 3, "message": "Invalid argument: type mismatch, parameter: identity.uuid", "details": [] } ``` -------------------------------- ### Execute 'get cell' Command from Remote Server Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/commands-cli.md Demonstrates retrieving a cell by ID from a remote server by specifying the server address using the -a flag. ```bash go run cmd/client/main.go -a 192.168.1.100 get cell robot-1 ``` -------------------------------- ### Setting Environment Variables for CLI Operations Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/commands-cli.md This example shows how to set environment variables for server address and port, which are then used by the CLI client for subsequent commands. Command-line flags will override these environment variables if both are specified. ```bash export SERVER_ADDR="192.168.1.100" export SERVER_PORT="8081" go run cmd/client/main.go create cell robot-1 offline go run cmd/client/main.go get cell robot-1 go run cmd/client/main.go update cell robot-1 online ``` -------------------------------- ### Go Marshal Example for UpdateCellRequest Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/types.md Shows how to marshal an UpdateCellRequest in Go, including specifying the identity, new cell data, and a field mask to update only the status. If update_mask is omitted, all fields in cell are updated. ```go import "google.golang.org/protobuf/types/known/fieldmaskpb" req := &api.UpdateCellRequest{ Identity: &api.Identifier{Uuid: "robot-1"}, Cell: &api.Cell{ Identity: &api.Identifier{Uuid: "robot-1"}, Status: "online", }, UpdateMask: &fieldmaskpb.FieldMask{ Paths: []string{"status"}, }, } // JSON representation: // { // "identity": { // "uuid": "robot-1" // }, // "cell": { // "identity": { // "uuid": "robot-1" // }, // "status": "online" // }, // "updateMask": { // "paths": ["status"] // } // } ``` -------------------------------- ### Initialize Server with Constructor Parameters Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/configuration.md Initialize the server using the server.New() function, providing configuration as parameters including server address, ports, logger, and a channel for shutdown signaling. ```go package main import ( "context" "demoserver/pkg/server" "log" "os" ) func main() { logger := log.New(os.Stdout, "[SERVER] ", log.LstdFlags) closedCh := make(chan struct{}) srv := server.New("127.0.0.1", "8081", "8080", logger, &closedCh) ctx := context.Background() go srv.Serve(ctx) go srv.ServeReverseProxy(ctx) <-closedCh } ``` -------------------------------- ### Increase File Descriptor Limit (Linux) Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/configuration.md Example command to increase the system's file descriptor limit on Linux. This is relevant for handling a large number of concurrent connections. ```bash ulimit -n 65536 # Increase file descriptor limit ``` -------------------------------- ### Instantiate gRPC Client with Configuration Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/configuration.md Use the `client.New` function to create a new client instance. Pass the server address, port, and a logger instance. ```go package main import ( "context" "demoserver/api" "demoserver/pkg/client" "log" "os" ) func main() { logger := log.New(os.Stdout, "[CLIENT] ", log.LstdFlags) client := client.New("127.0.0.1", "8081", logger) ctx := context.Background() cell := &api.Cell{ Identity: &api.Identifier{Uuid: "robot-1"}, Status: "offline", } created, err := client.CreateCell(ctx, cell) if err != nil { log.Fatalf("Error: %v", err) } log.Printf("Created: %+v", created) } ``` -------------------------------- ### Health Check Error Response Example Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/endpoints.md Example of an error response from the health check endpoint, typically returned on server failure. ```json { "code": 2, "message": "Server internal error", "details": [] } ``` -------------------------------- ### Implement gRPC Retry Logic for Transient Errors Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/errors.md Implement a retry loop for gRPC calls that are prone to transient network issues or temporary unavailability. This example retries up to 3 times with increasing delays, only for specific error codes like DeadlineExceeded or Unavailable. ```go import ( "time" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) var cell *api.Cell var err error for attempt := 0; attempt < 3; attempt++ { cell, err = client.GetCell(ctx, id) if err == nil { break } st, _ := status.FromError(err) // Only retry on transient errors if st.Code() == codes.DeadlineExceeded || st.Code() == codes.Unavailable { wait := time.Duration(attempt+1) * time.Second time.Sleep(wait) continue } // Non-retryable error log.Fatal(err) } ``` -------------------------------- ### Initialize gRPC Client Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/api-reference-client.md Creates a new Client instance configured to connect to a gRPC server. Requires server address, port, and a logger instance. ```go package main import ( "demoserver/pkg/client" "log" "os" ) func main() { logger := log.New(os.Stdout, "", log.LstdFlags) client := client.New("127.0.0.1", "8081", logger) // Client is ready to use } ``` -------------------------------- ### GET Health Check Endpoint Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/endpoints.md Performs a server health check. Use this to verify the server is operational and to get the current server status. ```bash curl -X GET http://127.0.0.1:8080/health ``` -------------------------------- ### Default gRPC Server Initialization Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/configuration.md Initializes a new gRPC server instance using default configurations from the grpc package. ```go grpcServer := grpc.NewServer() ``` -------------------------------- ### New Server Constructor Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/api-reference-server.md Creates a new Server instance with the specified configuration. This function initializes the server with network addresses, ports, a logger, and a channel for shutdown signaling. ```APIDOC ## New Server Constructor ### Description Creates a new Server instance with the specified configuration. This function initializes the server with network addresses, ports, a logger, and a channel for shutdown signaling. ### Signature `New(serverAddr, serverPort, proxyPort string, logger *log.Logger, apiClosedCh *chan struct{}) *Server` ### Parameters #### Path Parameters - **serverAddr** (string) - Required - The address the gRPC server binds to (e.g., "0.0.0.0" or "127.0.0.1") - **serverPort** (string) - Required - The port for the gRPC server (e.g., "8081") - **proxyPort** (string) - Required - The port for the HTTP reverse proxy (e.g., "8080") - **logger** (*log.Logger) - Required - Logger instance for server output - **apiClosedCh** (*chan struct{}) - Required - Channel to signal when the server shuts down ### Returns - **`*Server`** - A fully initialized server instance ready to serve. ### Example ```go package main import ( "context" "demoserver/pkg/server" "log" ) func main() { logger := log.New(os.Stdout, "", log.LstdFlags) closedCh := make(chan struct{}) srv := server.New("0.0.0.0", "8081", "8080", logger, &closedCh) ctx := context.Background() go srv.Serve(ctx) go srv.ServeReverseProxy(ctx) <-closedCh } ``` ``` -------------------------------- ### Create HTTP Server Instance Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/architecture.md Instantiate an HTTP server with a specified address and handler. This server handles concurrent HTTP requests, with each request processed in its own goroutine. ```go server := &http.Server{Addr: address, Handler: mux} ``` -------------------------------- ### Get gRPC Cell Resource Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/readme.md Use the client to retrieve a 'cell' resource by its key. ```bash go run cmd/client/main.go get cell foo-cell # connecting to server on 127.0.0.1:8081 # getting cell... # identity:{uuid:"foo-cell"} status:"offline" ``` -------------------------------- ### gRPC Error Handling Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/architecture.md Example of returning a gRPC error with a specific status code and message. ```go return nil, status.Errorf(codes.NotFound, "cell with ID %s not found", id) ``` -------------------------------- ### Create gRPC Server Instance Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/architecture.md Instantiate a gRPC server. Each RPC call will execute in its own goroutine, allowing for concurrent handling of requests. ```go grpcServer := grpc.NewServer() // Handles concurrent requests ``` -------------------------------- ### Get Cell Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/README.md Retrieves a specific Cell resource by its ID. This operation is available via gRPC and REST. ```APIDOC ## GET /v1/cells/{id} ### Description Retrieves a specific Cell resource by its ID. ### Method GET ### Endpoint /v1/cells/{id} ### Parameters #### Path Parameters - **id** (string) - Required - The unique identifier of the cell to retrieve. ### Response #### Success Response (200) - **identity** (object) - The identity of the cell. - **uuid** (string) - The unique identifier for the cell. - **status** (string) - The status of the cell. ### Response Example { "identity": {"uuid": "robot-1"}, "status": "offline" } ``` -------------------------------- ### REST API Health Check Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/README.md Use curl to send a GET request to the health check endpoint. ```bash curl http://localhost:8080/health ``` -------------------------------- ### Get a Cell (REST API) Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/endpoints.md Retrieve a specific cell resource by its UUID using the REST API. ```bash curl http://127.0.0.1:8080/v1/cells/test-1 ``` -------------------------------- ### Client Constructor Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/api-reference-client.md Initializes a new Client instance to connect to a gRPC server. It requires the server's address, port, and a logger instance. ```APIDOC ## New ### Description Creates a new Client instance configured to connect to a gRPC server. ### Signature `New(serverAddr, serverPort string, logger *log.Logger) *Client` ### Parameters #### Path Parameters - **serverAddr** (string) - Required - Server address (e.g., "127.0.0.1") - **serverPort** (string) - Required - Server port (e.g., "8081") - **logger** (*log.Logger) - Required - Logger instance for client output ### Returns - `*Client` - A fully initialized client ready to make RPC calls. ### Example ```go package main import ( "demoserver/pkg/client" "log" "os" ) func main() { logger := log.New(os.Stdout, "", log.LstdFlags) client := client.New("127.0.0.1", "8081", logger) // Client is ready to use } ``` ``` -------------------------------- ### Get Cell by UUID Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/endpoints.md Retrieves a Cell resource using its UUID. Ensure the UUID is correctly formatted. ```bash curl -X GET http://127.0.0.1:8080/v1/cells/cell-001 ``` ```bash curl -X GET http://127.0.0.1:8080/v1/cells/f47ac10b-58cc-4372-a567-0e02b2c3d479 ``` -------------------------------- ### View Subcommand Help Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/commands-cli.md Displays help information for specific CLI subcommands. This includes usage, short, and long descriptions. ```bash go run cmd/client/main.go create -h ``` ```bash go run cmd/client/main.go get -h ``` ```bash go run cmd/client/main.go update -h ``` -------------------------------- ### Get REST Cell Resource Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/readme.md Use curl to retrieve a 'cell' resource via the REST API. ```bash curl http://127.0.0.1:8080/v1/cells/foo-cell-2 # {"identity":{"uuid":"foo-cell-2"}, "status":"online"} ``` -------------------------------- ### Run gRPC Server and Client with Alternative Ports Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/configuration.md Configures the gRPC server to listen on custom ports and demonstrates how to connect a client and a REST client to these ports. ```bash # Server on ports 9000 (gRPC) and 9001 (HTTP) export SERVER_ADDR=0.0.0.0 export SERVER_PORT=9000 export PROXY_SERVER_PORT=9001 go run cmd/server/main.go # Client go run cmd/client/main.go -p 9000 get cell robot-1 # REST client curl http://localhost:9001/v1/cells/robot-1 ``` -------------------------------- ### Get Cell Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/README.md Retrieves details of a specific cell resource by its UUID. Supports gRPC, REST, and CLI interactions. ```APIDOC ## GET /v1/cells/{uuid} ### Description Retrieves a specific cell resource using its unique identifier. ### Method GET ### Endpoint /v1/cells/{uuid} ### Parameters #### Path Parameters - **uuid** (string) - Required - The unique identifier of the cell to retrieve. ### Response #### Success Response (200) - **cell** (object) - The requested cell object. - **identity** (object) - The identity of the cell. - **uuid** (string) - The unique identifier for the cell. - **status** (string) - The current status of the cell. #### Response Example { "identity": {"uuid": "robot-1"}, "status": "offline" } ``` -------------------------------- ### Create gRPC Client Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/grpc-service-reference.md Establishes a connection to a gRPC server and creates a client stub for making service calls. Ensure the server address and credentials are correct. ```go conn, _ := grpc.Dial("localhost:8081", grpc.WithTransportCredentials(insecure.NewCredentials())) client := api.NewCellServiceClient(conn) ``` -------------------------------- ### CellService.Status Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/grpc-service-reference.md Performs a server health check. This method can be called directly via gRPC or through its HTTP GET mapping. ```APIDOC ## GET /health ### Description Performs a server health check. ### Method GET ### Endpoint /health ### Request Body None ### Response #### Success Response (200 OK) - **healthy** (bool) - Server health status (always true) - **current_time** (google.protobuf.Timestamp) - Current server time in UTC ### Response Example ```json { "healthy": true, "currentTime": "2023-10-27T10:00:00Z" } ``` ### Request Example (REST) ```bash curl -X GET http://localhost:8080/health ``` ``` -------------------------------- ### Cross-Server Commands CLI Usage Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/commands-cli.md Demonstrates how to execute commands against different servers by specifying the server address using the CLI. ```bash # Connect to different servers go run cmd/client/main.go -a server1.example.com create cell robot-1 offline go run cmd/client/main.go -a server2.example.com create cell robot-1 offline go run cmd/client/main.go -a server3.example.com get cell robot-1 ``` -------------------------------- ### Create Cell using CLI Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/INDEX.md Execute this command to create a cell using the command-line interface. Ensure the client binary is available. ```bash go run cmd/client/main.go create cell robot-1 offline ``` -------------------------------- ### Customize gRPC Call with Options Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/grpc-service-reference.md Demonstrates how to pass custom options to a gRPC method call for advanced control. Options like capturing headers, trailers, or setting message size limits can be used. ```go resp, err := client.GetCell( ctx, req, grpc.Header(&headerMD), // Capture response headers grpc.Trailer(&trailerMD), // Capture response trailers grpc.MaxCallRecvMsgSize(10*1024*1024), // Increase message size limit ) ``` -------------------------------- ### Marshal ServerHealthResponse to Go Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/types.md Example of creating and marshaling a ServerHealthResponse object in Go. This is useful for preparing responses for the health check endpoint. ```go resp := &api.ServerHealthResponse{ Healthy: true, CurrentTime: timestamppb.Now(), } // JSON representation: // { // "healthy": true, // "currentTime": "2022-04-02T22:46:13Z" // } ``` -------------------------------- ### GetCell Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/grpc-service-reference.md Retrieves a Cell resource by its unique identifier. This method supports direct gRPC calls and maps to an HTTP GET request. ```APIDOC ## GetCell ### Description Retrieves a Cell resource by identifier. ### Method GET ### Endpoint /v1/cells/{identity.uuid} ### Parameters #### Path Parameters - **identity.uuid** (string) - Required - The UUID of the Cell to retrieve. #### Request Body None ### Response #### Success Response (200) - **identity** (Identifier) - The Cell's identity. - **status** (string) - The Cell's current status. ### Response Example ```json { "identity": { "uuid": "robot-1" }, "status": "online" } ``` ### Error Conditions - NOT_FOUND (gRPC 5): Cell with UUID not found - INVALID_ARGUMENT (gRPC 3): Missing or invalid UUID - UNKNOWN (gRPC 2): Server error ``` -------------------------------- ### gRPC and HTTP Message Marshaling Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/grpc-service-reference.md Demonstrates how to marshal Protocol Buffer messages into binary format for gRPC and JSON format for HTTP using grpc-gateway. ```go import "google.golang.org/protobuf/proto" cell := &api.Cell{ Identity: &api.Identifier{Uuid: "robot-1"}, Status: "offline", } // Binary binaryData, _ := proto.Marshal(cell) // JSON (via grpc-gateway marshaler) jsonBytes, _ := json.Marshal(cell) ``` -------------------------------- ### GetCell gRPC Definition Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/grpc-service-reference.md Defines the GetCell RPC method for retrieving a Cell resource. Includes HTTP mapping for GET requests. ```protobuf rpc GetCell(GetCellRequest) returns (Cell) { option (google.api.http) = { get: "/v1/cells/{identity.uuid=*}" }; } ``` -------------------------------- ### Create, Update, and Verify Cell CLI Commands Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/commands-cli.md Shows the workflow for creating a cell, updating its state to online, and then verifying the change via the CLI. ```bash # Create offline go run cmd/client/main.go create cell robot-1 offline # Update to online go run cmd/client/main.go update cell robot-1 online # Verify go run cmd/client/main.go get cell robot-1 ``` -------------------------------- ### Create Cell using gRPC (Go) Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/INDEX.md This Go snippet demonstrates how to create a cell using the gRPC client. It requires the API client and context to be initialized. ```go client.CreateCell(ctx, &api.CreateCellRequest{ Cell: &api.Cell{ Identity: &api.Identifier{Uuid: "robot-1"}, Status: "offline", }, }) ``` -------------------------------- ### Use grpcurl for Service Discovery Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/grpc-service-reference.md Use grpcurl to list services and describe specific services exposed by a gRPC server with reflection enabled. ```bash grpcurl -plaintext localhost:8081 list ``` ```bash grpcurl -plaintext localhost:8081 describe CellService ``` -------------------------------- ### Update Cell with Field Mask Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/endpoints.md Updates a Cell resource using a field mask to specify the fields to be updated. This example updates the status. ```bash curl -X PATCH "http://127.0.0.1:8080/v1/cells/cell-001?updateMask=status" \ -H 'Content-Type: application/json' \ -d '{ "status": "online" }' ``` -------------------------------- ### Initialize Logger Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/commands-cli.md Initializes the logger for the CLI. The logger is configured to write to standard output/error with no prefix and default timestamp formatting. ```go config.logger = log.New(log.Writer(), "", 0) ``` -------------------------------- ### Get Cell Endpoint Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/endpoints.md Retrieves a Cell resource by its unique identifier (UUID). This endpoint allows fetching the current state of a specific cell. ```APIDOC ## Get Cell Endpoint ### GET /v1/cells/{identity.uuid} Retrieves a Cell resource by identifier. ### Method GET ### Endpoint /v1/cells/{identity.uuid} ### Parameters #### Path Parameters - **identity.uuid** (string) - Required - The UUID of the Cell to retrieve ### Response #### Success Response (200) - **identity** (object) - Resource identifier object - **identity.uuid** (string) - The UUID of the retrieved Cell - **status** (string) - The current status of the Cell #### Response Example ```json { "identity": { "uuid": "cell-001" }, "status": "offline" } ``` ``` -------------------------------- ### GET /health Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/endpoints.md Performs a server health check and returns the current server status with a timestamp. This endpoint is mapped to the CellService.Status() gRPC method. ```APIDOC ## GET /health ### Description Performs a server health check and returns current server status with timestamp. ### Method GET ### Endpoint /health ### Parameters #### Query Parameters None #### Request Body None ### Request Example ```bash curl -X GET http://127.0.0.1:8080/health ``` ### Response #### Success Response (200 OK) - **healthy** (boolean) - Server health status - **currentTime** (string (date-time)) - RFC 3339 formatted timestamp #### Response Example ```json { "healthy": true, "currentTime": "2022-04-02T22:46:13Z" } ``` #### Error Response (5xx on server failure) ```json { "code": 2, "message": "Server internal error", "details": [] } ``` ``` -------------------------------- ### Generate gRPC, gRPC-Gateway, and OpenAPI Specs Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/readme.md Use this command with protoc to generate Go code, gRPC-Gateway handlers, and OpenAPI v2 specifications from a .proto file. Ensure logtostderr=true is set for visible output. ```bash protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative service.proto ; protoc -I . --grpc-gateway_out . --grpc-gateway_opt logtostderr=true --grpc-gateway_opt paths=source_relative service.proto ; protoc -I . --openapiv2_out ./openapiv2 --openapiv2_opt logtostderr=true service.proto ``` -------------------------------- ### Client Creation Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/grpc-service-reference.md This demonstrates how to create a gRPC client for the CellService. It establishes a connection to the server and instantiates the client. ```APIDOC ## NewCellServiceClient ### Description Creates a new CellServiceClient, establishing a connection to the specified server address. ### Go Signature ```go func NewCellServiceClient(cc grpc.ClientConn) CellServiceClient ``` ### Usage Example ```go conn, _ := grpc.Dial("localhost:8081", grpc.WithTransportCredentials(insecure.NewCredentials())) client := api.NewCellServiceClient(conn) ``` ``` -------------------------------- ### Initialize gRPC Gateway Mux Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/configuration.md Initializes a new gRPC gateway ServeMux and sets up dial options for connecting to the backend gRPC server. Uses insecure transport credentials for simplicity. ```go mux := runtime.NewServeMux() opts := []grpc.DialOption{ grpc.WithTransportCredentials(insecure.NewCredentials()), } err := api.RegisterCellServiceHandlerFromEndpoint(ctx, mux, grpcAddress, opts) ``` -------------------------------- ### UpdateCell REST Example Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/grpc-service-reference.md Shows how to make a PATCH request to the /v1/cells/{identity.uuid} endpoint using curl, with a JSON body and updateMask query parameter. ```bash curl -X PATCH "http://localhost:8080/v1/cells/robot-1?updateMask=status" \ -H 'Content-Type: application/json' \ -d '{ "identity": {"uuid": "robot-1"}, "status": "online" }' ``` -------------------------------- ### Create and Retrieve a Cell CLI Commands Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/commands-cli.md Demonstrates how to create a cell in an offline state and then retrieve its status using the CLI. ```bash # Create go run cmd/client/main.go create cell robot-1 offline # Retrieve go run cmd/client/main.go get cell robot-1 ``` -------------------------------- ### Execute 'update cell' Command to Set Status Offline Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/commands-cli.md Example of how to execute the 'update cell' command to change a cell's status to 'offline'. ```bash go run cmd/client/main.go update cell robot-1 offline ``` -------------------------------- ### Generate gRPC Code with Protoc Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/readme.md Generates Go and gRPC code from a .proto file using the 'protoc' compiler and specified plugins. ```bash protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative service.proto ``` -------------------------------- ### Configure HTTP Server Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/configuration.md Defines the HTTP server with its address and handler. The address can be modified via environment variables. ```go server := &http.Server{ Addr: address, Handler: mux, } ``` -------------------------------- ### Get Cell by ID using gRPC Client Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/commands-cli.md Retrieves a Cell resource by its unique identifier using the client.GetCell() method. Ensure the client and logger are configured. ```go cell, err := config.client.GetCell(cmd.Context(), &api.Identifier{Uuid: objectID}) if err != nil { config.logger.Fatalf("error: %s", err.Error()) } config.logger.Println(cell) ``` -------------------------------- ### Create Cell Implementation Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/commands-cli.md This Go code snippet shows the implementation for creating a Cell resource. It constructs a Cell object with identity and status, then calls the client's CreateCell method. ```go cell := &api.Cell{ Identity: &api.Identifier{Uuid: objectID}, Status: objectStatus, } resp, err := config.client.CreateCell(cmd.Context(), cell) if err != nil { config.logger.Fatalf("error: %s", err.Error()) } config.logger.Println(resp) ``` -------------------------------- ### Generate OpenAPIv2 Definitions with protoc-gen-openapiv2 Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/readme.md Execute this command to generate OpenAPIv2 definitions for your gRPC service. The output will be placed in the ./openapiv2 directory. ```bash protoc -I . --openapiv2_out ./openapiv2 --openapiv2_opt logtostderr=true service.proto ``` -------------------------------- ### Get Server Health Status Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/api-reference-server.md Checks the health of the gRPC server and retrieves the current server time. Use this to verify server availability and monitor its operational status. ```go import "google.golang.org/protobuf/types/known/emptypb" resp, err := srv.Status(ctx, &emptypb.Empty{}) if err != nil { log.Fatal(err) } fmt.Printf("Server healthy: %v, Time: %v\n", resp.Healthy, resp.CurrentTime) ``` -------------------------------- ### Default Server Logger Source: https://github.com/danielscrouch/grpc-rest-openapi/blob/main/_autodocs/configuration.md Initializes the default logger for the server. This can be customized for file logging or combined output. ```go logger := log.Default() ```