### How to Use Connect-Go Documentation Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/MANIFEST.md A guide on how to navigate and utilize the Connect-Go documentation effectively, suggesting a starting point and directing users to specific files based on their needs. ```APIDOC ## How to Use Connect-Go Documentation 1. Start with **README.md** for navigation and overview. 2. Use **INDEX.md** for a complete quick reference. 3. Consult specific files based on your task: - Building clients: `client-api.md` + `streaming.md` - Building handlers: `handler-api.md` + `streaming.md` - Configuring: `options-api.md` - Error handling: `errors.md` - Middleware: `interceptors.md` + `http-integration.md` - Metadata: `context-callinfo.md` ``` -------------------------------- ### HTTP GET Request Example Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/http-integration.md An example of an HTTP GET request for a Connect RPC. Note that this is for illustrative purposes and not actual Go code. ```http GET /foo.FooService/Get?query=value HTTP/1.1 ``` -------------------------------- ### Run Connect-Go Server Source: https://github.com/connectrpc/connect-go/blob/main/internal/example/README.md Execute the server component of the Connect-Go example. ```bash go run ./server ``` -------------------------------- ### Handler Example: Not Found Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/errors.md Provides an example of returning a `CodeNotFound` error when a requested database record does not exist. ```go user, err := db.GetUser(id) if err == sql.ErrNoRows { return connect.NewError(connect.CodeNotFound, errors.New("user not found")) } ``` -------------------------------- ### Run Connect-Go Client Source: https://github.com/connectrpc/connect-go/blob/main/internal/example/README.md Execute the client component of the Connect-Go example. ```bash go run ./client ``` -------------------------------- ### Register Handlers with HTTP Server Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/INDEX.md Register generated service handlers with an HTTP multiplexer and start an HTTP server. This example assumes a generated handler `NewMyServiceHandler`. ```go mux := http.NewServeMux() mux.Handle(mygen.NewMyServiceHandler(&myServiceImpl{})) server := &http.Server{ Addr: ":8080", Handler: mux, } server.ListenAndServe() ``` -------------------------------- ### Connect Protocol Example Request Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/http-integration.md An example POST request for the Connect protocol using application/proto Content-Type. This protocol is simple, browser-friendly, and optimized for gzip compression. ```http POST /foo.FooService/Bar HTTP/1.1 Content-Type: application/proto Content-Length: 42 ``` -------------------------------- ### Connect-Go Client Example Source: https://github.com/connectrpc/connect-go/blob/main/README.md This snippet demonstrates how to create a Connect-Go client to interact with a running server. It shows how to instantiate the client and make a basic RPC call. ```go package main import ( "context" "log" "net/http" pingv1 "connectrpc.com/connect/internal/gen/connect/ping/v1" "connectrpc.com/connect/internal/gen/simple/connect/ping/v1/pingv1connect" ) func main() { client := pingv1connect.NewPingServiceClient( http.DefaultClient, "http://localhost:8080/", ) req := &pingv1.PingRequest{Number: 42} res, err := client.Ping(context.Background(), req) if err != nil { log.Fatalln(err) } log.Println(res) } ``` -------------------------------- ### Configure Client with Compression Options Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/INDEX.md Example of creating a Connect client with options to enable sending compressed requests (gzip) and accepting specific compression algorithms. ```go client := connect.NewClient( httpClient, url, connect.WithSendGzip(), connect.WithAcceptCompression("gzip", ...), ) ``` -------------------------------- ### Client Streaming RPC Example (Simple) Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/streaming.md Example of using `Client.CallClientStreamSimple()`. Sends 100 requests and closes the stream to receive the response directly, without a `connect.Response` wrapper. Response metadata is accessed via `CallInfo`. ```go ctx, info := connect.NewClientContext(context.Background()) stream, err := client.CallClientStreamSimple(ctx) if err != nil { log.Fatal(err) } for i := 0; i < 100; i++ { err := stream.Send(&MyRequest{Index: i}) if err != nil { log.Fatal(err) } } resp, err := stream.CloseAndReceive() if err != nil { log.Fatal(err) } // Access response metadata from info log.Printf("Response headers: %v", info.ResponseHeader()) log.Printf("Response: %v", resp) ``` -------------------------------- ### Connect-Go Server Example Source: https://github.com/connectrpc/connect-go/blob/main/README.md This snippet shows how to set up a basic Connect-Go RPC server. It includes defining a service handler and configuring the HTTP server with Protovalidate interceptor. ```go package main import ( "context" "log" "net/http" "connectrpc.com/connect" pingv1 "connectrpc.com/connect/internal/gen/connect/ping/v1" "connectrpc.com/connect/internal/gen/simple/connect/ping/v1/pingv1connect" "connectrpc.com/validate" ) type PingServer struct { pingv1connect.UnimplementedPingServiceHandler // returns errors from all methods } func (ps *PingServer) Ping(ctx context.Context, req *pingv1.PingRequest) (*pingv1.PingResponse, error) { return &pingv1.PingResponse{ Number: req.Number, }, nil } func main() { mux := http.NewServeMux() // The generated constructors return a path and a plain net/http // handler. mux.Handle( pingv1connect.NewPingServiceHandler( &PingServer{}, // Validation via Protovalidate is almost always recommended connect.WithInterceptors(validate.NewInterceptor()), ), ) p := new(http.Protocols) p.SetHTTP1(true) // For gRPC clients, it's convenient to support HTTP/2 without TLS. p.SetUnencryptedHTTP2(true) s := &http.Server{ Addr: "localhost:8080", Handler: mux, Protocols: p, } if err := s.ListenAndServe(); err != nil { log.Fatalf("listen failed: %v", err) } } ``` -------------------------------- ### Handler Example: Already Exists Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/errors.md Demonstrates returning a `CodeAlreadyExists` error when attempting to create a resource that already exists, indicating a conflict. ```go if userExists { return connect.NewError(connect.CodeAlreadyExists, errors.New("user already exists")) } ``` -------------------------------- ### Handler Example: Failed Precondition Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/errors.md Provides an example of returning a `CodeFailedPrecondition` error when the system is not in the required state for an operation, such as an inactive account. ```go if !account.IsActivated { return connect.NewError(connect.CodeFailedPrecondition, errors.New("account not activated")) } ``` -------------------------------- ### Client Streaming RPC Example Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/streaming.md Example of using `Client.CallClientStream()`. Sends 100 requests and then closes the stream to receive a single response. Custom headers can be set on the request. ```go stream := client.CallClientStream(ctx) stream.RequestHeader().Set("custom-header", "value") for i := 0; i < 100; i++ { err := stream.Send(&MyRequest{Index: i}) if err != nil { log.Fatal(err) } } resp := &connect.Response[MyResponse]{} err := stream.CloseAndReceive(resp) if err != nil { log.Fatal(err) } log.Printf("Response: %v", resp.Msg) ``` -------------------------------- ### Enable HTTP GET on Client - Go Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/http-integration.md Configure a Connect client to use HTTP GET for idempotent unary RPCs. This allows requests to be cached by proxies and browsers. ```go client := connect.NewClient( httpClient, url, connect.WithHTTPGet(), ) ``` -------------------------------- ### gRPC Protocol Example Request Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/http-integration.md An example POST request for the gRPC protocol using application/grpc+proto Content-Type. This protocol requires HTTP/2 and uses trailers for metadata. ```http POST /foo.FooService/Bar HTTP/2.0 Content-Type: application/grpc+proto TE: trailers ``` -------------------------------- ### Enable HTTP GET on Handler - Go Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/http-integration.md Configure a Connect handler to support HTTP GET requests. This is suitable for idempotent unary RPCs marked with `IdempotencyNoSideEffects`. ```go handler := connect.NewUnaryHandler( "/foo.FooService/Get", handler, connect.WithIdempotency(connect.IdempotencyNoSideEffects), ) ``` -------------------------------- ### Handler Example: Permission Denied Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/errors.md Shows how to return a `CodePermissionDenied` error when a user lacks the necessary permissions to perform an action, distinct from authentication failures. ```go if !userIsAdmin { return connect.NewError(connect.CodePermissionDenied, errors.New("admin access required")) } ``` -------------------------------- ### Example: Logging Unary Interceptor Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/interceptors.md Demonstrates how to create and use a `UnaryInterceptorFunc` for logging RPC procedure names and errors. The interceptor is then applied to a new client using `connect.WithInterceptors`. ```go loggingInterceptor := connect.UnaryInterceptorFunc(func(next connect.UnaryFunc) connect.UnaryFunc { return func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) { log.Printf("RPC: %v", req.Spec().Procedure) resp, err := next(ctx, req) if err != nil { log.Printf("Error: %v", err) } return resp, err } }) client := connect.NewClient( httpClient, url, connect.WithInterceptors(loggingInterceptor), ) ``` -------------------------------- ### Accessing HTTP Method Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/context-callinfo.md Illustrates how to get the HTTP method (e.g., POST, GET) used for an RPC call. This is useful for understanding the underlying transport mechanism. ```go ctx, callInfo := connect.NewClientContext(context.Background()) resp, err := client.CallUnary(ctx, req) if err == nil { method := callInfo.HTTPMethod() log.Printf("Used HTTP method: %v", method) // "POST" or "GET" } ``` -------------------------------- ### gRPC-Web Protocol Example Request Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/http-integration.md An example POST request for the gRPC-Web protocol using application/grpc-web+proto Content-Type. This protocol is suitable for browser clients and works over HTTP/1.1. ```http POST /foo.FooService/Bar HTTP/1.1 Content-Type: application/grpc-web+proto X-Grpc-Web: 1 ``` -------------------------------- ### Registering Handlers Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/INDEX.md Provides an example of registering generated handlers with an HTTP server. ```APIDOC ## Registering Handlers ```go mux := http.NewServeMux() mux.Handle(mygen.NewMyServiceHandler(&myServiceImpl{})) server := &http.Server{ Addr: ":8080", Handler: mux, } server.ListenAndServe() ``` ``` -------------------------------- ### Connect-Go Error Codes Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/README.md Shows examples of accessing predefined error code constants within the Connect-Go library. ```go connect.CodeNotFound // Code = 5 connect.CodePermissionDenied // Code = 7 ``` -------------------------------- ### Enable HTTP GET for Unary RPCs with Connect-Go Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/options-api.md Use WithHTTPGet to allow side-effect-free unary RPCs to use HTTP GET requests, improving caching support. This is typically set on the client. ```go client := connect.NewClient( httpClient, url, connect.WithHTTPGet(), // Set idempotency in handler or schema ) ``` -------------------------------- ### Handler Example: Resource Exhausted Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/errors.md Illustrates returning a `CodeResourceExhausted` error when a rate limit is exceeded or another resource quota is hit. ```go if requests > rateLimitPerMinute { return connect.NewError(connect.CodeResourceExhausted, errors.New("rate limit exceeded")) } ``` -------------------------------- ### Calling a Connect API with buf curl (gRPC protocol) Source: https://github.com/connectrpc/connect-go/blob/main/README.md Shows how to call a Connect API using `buf curl` with the gRPC protocol. This requires installing the `buf` tool. The `--protocol grpc` flag specifies the protocol. ```shell go install github.com/bufbuild/buf/cmd/buf@latest buf curl --protocol grpc \ --data '{"sentence": "I feel happy."}' \ https://demo.connectrpc.com/connectrpc.eliza.v1.ElizaService/Say ``` -------------------------------- ### Handler Example: Out of Range Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/errors.md Shows how to return a `CodeOutOfRange` error when an operation is attempted outside the valid bounds, such as requesting a page number beyond the maximum. ```go if page < 1 || page > maxPages { return connect.NewError(connect.CodeOutOfRange, errors.New("page out of range")) } ``` -------------------------------- ### WithHTTPGet Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/options-api.md Allows Connect-protocol clients to use HTTP GET requests for side-effect-free unary RPCs. This can improve caching and CDN support for idempotent procedures. ```APIDOC ## WithHTTPGet ### Description Allows Connect-protocol clients to use HTTP GET requests for side-effect-free unary RPCs. This can improve caching and CDN support for idempotent procedures. ### Signature ```go func WithHTTPGet() ClientOption ``` ### Effect - Idempotent procedures can use GET instead of POST. - Procedure idempotency is set via `WithIdempotency()` or Protobuf schema. - Better CDN and proxy caching support. ### Default All requests use POST. ### Limitation gRPC and gRPC-Web are POST-only. ### Example ```go client := connect.NewClient( httpClient, url, connect.WithHTTPGet(), // Set idempotency in handler or schema ) ``` ``` -------------------------------- ### Creating a Client Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/INDEX.md Demonstrates how to create a new Connect client with optional configurations like protocol and interceptors. ```APIDOC ## Creating a Client ```go import "connectrpc.com/connect" client := connect.NewClient[Request, Response]( httpClient, "http://example.com/", connect.WithGRPC(), // Protocol (optional) connect.WithInterceptors(logger), // Interceptors (optional) ) ``` ``` -------------------------------- ### Create Client Context and Set Headers Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/context-callinfo.md Demonstrates creating a client context and setting request headers before making an RPC. Headers are set on the CallInfo object obtained from NewClientContext. ```go import "connectrpc.com/connect" ctx, callInfo := connect.NewClientContext(context.Background()) // Set headers before RPC callInfo.RequestHeader().Set("Authorization", "Bearer token123") callInfo.RequestHeader().Set("X-Custom", "value") // Make RPC resp, err := client.CallUnary(ctx, req) if err == nil { // Access response metadata log.Printf("Headers: %v", callInfo.ResponseHeader()) log.Printf("Trailers: %v", callInfo.ResponseTrailer()) } ``` -------------------------------- ### Initializing and Using ErrorWriter (Go) Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/http-integration.md Shows how to create an ErrorWriter with options like requiring the Connect protocol header or specifying compression. It includes checking if a request is supported and writing an RPC error. ```go errWriter := connect.NewErrorWriter( connect.WithRequireConnectProtocolHeader(), connect.WithCompression("gzip", ...), ) // Check if request is an RPC request if !errWriter.IsSupported(request) { // Not an RPC request; use standard HTTP error handling http.Error(w, "Not Found", http.StatusNotFound) return } // It's an RPC request; format error appropriately err := connect.NewError(connect.CodeNotFound, errors.New("resource not found")) errWriter.Write(w, request, err) ``` -------------------------------- ### Create a Connect Client Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/INDEX.md Instantiate a new connect client with optional configurations for protocol and interceptors. Requires an HTTP client, URL, and optionally protocol and interceptor settings. ```go import "connectrpc.com/connect" client := connect.NewClient[Request, Response]( httpClient, "http://example.com/", connect.WithGRPC(), // Protocol (optional) connect.WithInterceptors(logger), // Interceptors (optional) ) ``` -------------------------------- ### Functional Options Pattern for Client Configuration Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/README.md Demonstrates how to use functional options to configure a Connect-Go client, including protocol, compression, and interceptors. ```go client := connect.NewClient( httpClient, url, connect.WithGRPC(), // Protocol connect.WithSendGzip(), // Compression connect.WithInterceptors(log), // Middleware ) ``` -------------------------------- ### Client Constructor Signature Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/README.md Illustrates the generic type parameters and variadic options pattern for client constructors. ```go func NewClient[Req, Res any](httpClient HTTPClient, url string, options ...ClientOption) *Client[Req, Res] ``` -------------------------------- ### Register Acceptable Compression Algorithm for Client Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/options-api.md Use `WithAcceptCompression` to make a compression algorithm available for receiving compressed responses. The algorithm name and factory functions for decompressors and compressors are required. Gzip is registered by default. ```go import "compress/gzip" client := connect.NewClient( httpClient, url, connect.WithAcceptCompression( "gzip", func() connect.Decompressor { return gzip.NewReader() }, func() connect.Compressor { return gzip.NewWriter() }, ), ) ``` -------------------------------- ### Handler Example: Invalid Argument Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/errors.md Illustrates returning a `CodeInvalidArgument` error when a request parameter fails validation, such as a negative age. ```go if req.Age < 0 { return connect.NewError( connect.CodeInvalidArgument, errors.New("age must be non-negative"), ) } ``` -------------------------------- ### Construct a New Connect Go Client Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/client-api.md Use `NewClient` to create a reusable, concurrency-safe client for a specific procedure. Configure protocol, codec, compression, and interceptors using `ClientOption`s. Errors during construction are deferred to the first RPC call. ```go package main import ( "context" "net/http" "connectrpc.com/connect" pingv1 "example.com/ping/v1" pingv1connect "example.com/ping/v1/pingv1connect" ) func main() { client := pingv1connect.NewPingServiceClient( http.DefaultClient, "http://localhost:8080/", connect.WithGRPC(), ) req := connect.NewRequest(&pingv1.PingRequest{Number: 42}) resp, err := client.Ping(context.Background(), req) if err != nil { // Handle error } // Use resp.Msg } ``` -------------------------------- ### Client Protocol Selection Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/http-integration.md Configure a Connect client to use the default Connect protocol, gRPC, or gRPC-Web. gRPC requires HTTP/2. ```go client := connect.NewClient(httpClient, url) client := connect.NewClient(httpClient, url, connect.WithGRPC()) client := connect.NewClient(httpClient, url, connect.WithGRPCWeb()) ``` -------------------------------- ### Extract Connect Error Code Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/errors.md Use CodeOf to get the status code from any error. It defaults to CodeUnknown if the error is not a Connect error. ```go func CodeOf(err error) Code ``` ```go code := connect.CodeOf(err) log.Printf("Error code: %v", code) ``` -------------------------------- ### Client Context with Timeout Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/context-callinfo.md Demonstrates creating a context with a timeout for an RPC call and checking for deadline exceeded or cancellation errors. ```go import "context" // Create context with timeout ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() // Call RPC resp, err := client.CallUnary(ctx, req) if err != nil { if ctx.Err() == context.DeadlineExceeded { log.Printf("RPC timeout") } else if ctx.Err() == context.Canceled { log.Printf("RPC canceled") } } ``` -------------------------------- ### NewNotModifiedError Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/errors.md Creates a new NotModifiedError, representing an HTTP 304 Not Modified response for conditional GET requests within the Connect protocol. ```APIDOC ## NewNotModifiedError ### Description Indicates HTTP 304 Not Modified for conditional GET requests in Connect protocol. ### Usage Only for Connect-protocol conditional GETs; equivalent to `CodeUnknown` for gRPC/gRPC-Web. ### Headers Should include ETag, Cache-Control, etc. ### Example ```go if req.Header().Get("If-None-Match") == currentETag { headers := http.Header{} headers.Set("ETag", currentETag) headers.Set("Cache-Control", "max-age=3600") return connect.NewNotModifiedError(headers) } ``` ### Check `IsNotModifiedError(err)` returns true. ``` -------------------------------- ### Handler Example: Canceled Operation Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/errors.md Shows how a handler can detect and return a `CodeCanceled` error when the context is canceled, typically due to client-side cancellation. ```go if ctx.Err() == context.Canceled { return connect.NewError(connect.CodeCanceled, ctx.Err()) } ``` -------------------------------- ### Initialize Response Messages with Initializer Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/options-api.md Use WithResponseInitializer to provide a function that initializes new response messages on the client side. ```go func WithResponseInitializer(initializer func(spec Spec, message any) error) ClientOption ``` -------------------------------- ### Configure Client to Send Compressed Requests Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/options-api.md Use `WithSendCompression` to enable compression for outgoing requests using a previously registered algorithm. The algorithm must be registered via `WithAcceptCompression` to avoid runtime errors. Clients send uncompressed requests by default. ```go client := connect.NewClient( httpClient, url, connect.WithAcceptCompression("gzip", ...), connect.WithSendCompression("gzip"), ) ``` -------------------------------- ### Implement Logging Interceptor in Connect-Go Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/INDEX.md Example of creating a custom unary interceptor to log outgoing RPC procedure calls. This can be used for debugging or monitoring. ```go logger := connect.UnaryInterceptorFunc(func(next connect.UnaryFunc) connect.UnaryFunc { return func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) { log.Printf("→ %v", req.Spec().Procedure) return next(ctx, req) } }) ``` -------------------------------- ### Import All Public Connect APIs Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/README.md Use this import path to access all public APIs provided by the Connect library. ```go import "connectrpc.com/connect" ``` -------------------------------- ### Handler Example: Aborted Operation Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/errors.md Demonstrates returning a `CodeAborted` error when an operation is interrupted, often due to concurrency issues like optimistic lock failures. ```go if row.Version != expectedVersion { return connect.NewError(connect.CodeAborted, errors.New("concurrent modification detected")) } ``` -------------------------------- ### Handle Connect Errors with errors.As Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/INDEX.md Illustrates how to check for and handle specific Connect RPC errors by using errors.As to cast the error to a *connect.Error type and checking its code. ```go if err != nil { var connectErr *connect.Error if errors.As(err, &connectErr) { switch connectErr.Code() { case connect.CodeNotFound: // ... } } } ``` -------------------------------- ### Standard Library Imports Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/README.md These are common standard library packages used alongside Connect-Go for context management, HTTP operations, and Protocol Buffers. ```go import ( "context" "net/http" "google.golang.org/protobuf/proto" ) ``` -------------------------------- ### Configure Client with gRPC-Web Protocol Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/options-api.md Use WithGRPCWeb to configure a client for gRPC-Web protocol compatibility. This is ideal for browser clients and works with HTTP/1.1 and HTTP/2. ```go client := connect.NewClient(httpClient, url, connect.WithGRPCWeb()) ``` -------------------------------- ### Making a Unary RPC Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/INDEX.md Shows how to make a unary RPC call using the created client, including context management and basic error handling. ```APIDOC ## Making a Unary RPC ```go ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() req := connect.NewRequest(&MyRequest{Msg: "hello"}) resp, err := client.CallUnary(ctx, req) if err != nil { var connectErr *connect.Error if errors.As(err, &connectErr) { log.Printf("Error code: %v", connectErr.Code()) } } ``` ``` -------------------------------- ### Logging Interceptor for Unary RPCs Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/interceptors.md Logs the start and end of unary RPCs, including procedure name, duration, and error codes if applicable. This interceptor is useful for debugging and monitoring. ```go type LoggingInterceptor struct{} func (li *LoggingInterceptor) WrapUnary(next connect.UnaryFunc) connect.UnaryFunc { return func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) { start := time.Now() log.Printf("→ %v", req.Spec().Procedure) resp, err := next(ctx, req) duration := time.Since(start) if err != nil { var connectErr *connect.Error if errors.As(err, &connectErr) { log.Printf("← %v in %v: %v", req.Spec().Procedure, duration, connectErr.Code()) } else { log.Printf("← %v in %v: %v", req.Spec().Procedure, duration, err) } } else { log.Printf("← %v in %v: OK", req.Spec().Procedure, duration) } return resp, err } } func (li *LoggingInterceptor) WrapStreamingClient(next connect.StreamingClientFunc) connect.StreamingClientFunc { return next // Pass through } func (li *LoggingInterceptor) WrapStreamingHandler(next connect.StreamingHandlerFunc) connect.StreamingHandlerFunc { return next // Pass through } ``` -------------------------------- ### Configure HTTPS Server TLS Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/http-integration.md Set up TLS configuration for an HTTP server to enable HTTPS. Ensure you provide valid paths to your certificate and key files. ```go server := &http.Server{ Addr: ":8443", TLSConfig: // Your TLS config, Handler: mux, } if err := server.ListenAndServeTLS("cert.pem", "key.pem"); err != nil { log.Fatal(err) } ``` -------------------------------- ### Setting Timeouts and Deadlines in Go Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/context-callinfo.md Create a context with a timeout or an absolute deadline for RPC calls using context.WithTimeout and context.WithDeadline. ```go // Timeout-based deadline ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() // Deadline-based (absolute time) ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(10*time.Second)) defer cancel() // Make RPC resp, err := client.CallUnary(ctx, req) ``` -------------------------------- ### Update Version Constant for Release Source: https://github.com/connectrpc/connect-go/blob/main/RELEASE.md Modify the Version constant in connect.go to reflect the new semantic version for a release. This example shows updating from a development version to a stable release version. ```diff -const Version = "1.14.0-dev" +const Version = "1.14.0" ``` -------------------------------- ### Accessing Spec and Peer Information Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/context-callinfo.md Demonstrates how to inspect the RPC specification (procedure, stream type) and peer details (server address, protocol) using the CallInfo object. ```go ctx, callInfo := connect.NewClientContext(context.Background()) resp, err := client.CallUnary(ctx, req) // Inspect RPC specification spec := callInfo.Spec() log.Printf("Procedure: %v", spec.Procedure) log.Printf("Stream type: %v", spec.StreamType) // Inspect server/peer peer := callInfo.Peer() log.Printf("Server: %v", peer.Addr) log.Printf("Protocol: %v", peer.Protocol) ``` -------------------------------- ### Create Not Modified Error in Go Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/errors.md Use NewNotModifiedError to indicate an HTTP 304 Not Modified response for conditional GET requests. This function requires an http.Header containing ETag, Cache-Control, etc. ```go func NewNotModifiedError(headers http.Header) *Error ``` ```go if req.Header().Get("If-None-Match") == currentETag { headers := http.Header{} headers.Set("ETag", currentETag) headers.Set("Cache-Control", "max-age=3600") return connect.NewNotModifiedError(headers) } ``` -------------------------------- ### Configure Client with Protobuf JSON Encoding Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/options-api.md Use WithProtoJSON to configure a client to use JSON encoding based on Protobuf JSON mapping. This results in human-readable messages over the wire. ```go client := connect.NewClient(httpClient, url, connect.WithProtoJSON()) ``` -------------------------------- ### ServerStream Methods Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/handler-api.md Represents the server-side view of a server streaming RPC. Use these methods to get stream specifications, peer information, send messages to the client, and manage response headers/trailers. ```go func (s *ServerStream[Res]) Spec() Spec func (s *ServerStream[Res]) Peer() Peer func (s *ServerStream[Res]) Send(msg *Res) error func (s *ServerStream[Res]) ResponseHeader() http.Header func (s *ServerStream[Res]) ResponseTrailer() http.Header ``` -------------------------------- ### Manage Header Values in Go Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/context-callinfo.md Use `CallInfo.RequestHeader()` and `CallInfo.ResponseHeader()` to access headers. Methods like `Set`, `Add`, `Get`, `Values`, and `Del` allow manipulation of single or multiple header values. ```go // Set a single value (replaces existing) callInfo.RequestHeader().Set("X-Custom", "value1") // Add a value (appends) callInfo.RequestHeader().Add("X-Custom", "value2") // Get first value first := callInfo.RequestHeader().Get("X-Custom") // "value1" // Get all values all := callInfo.RequestHeader().Values("X-Custom") // ["value1", "value2"] // Delete all values for a key callInfo.RequestHeader().Del("X-Custom") ``` -------------------------------- ### Call Bidirectional Streaming RPC Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/client-api.md Use CallBidiStream for concurrent sending and receiving of multiple messages. Start a separate goroutine for sending to avoid blocking receive operations. Request headers are set on the stream writer. ```go stream := client.CallBidiStream(ctx) stream.RequestHeader().Set("custom-header", "value") // Send messages go func() { stream.Send(&pingv1.PingRequest{Number: 1}) stream.Send(&pingv1.PingRequest{Number: 2}) stream.CloseRequest() }() // Receive messages for stream.Receive() { log.Printf("Received: %v", stream.Msg()) } if err := stream.Err(); err != nil { log.Fatal(err) } ``` -------------------------------- ### Initialize Handler with Schema Option Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/options-api.md Use WithSchema to provide parsed schema metadata to interceptors and clients. This is typically set by generated code. ```go handler := connect.NewUnaryHandler( "/foo.Service/Bar", handler, connect.WithSchema(fooconnect.FooService_Bar_SchemaDescriptor), ) ``` -------------------------------- ### Client-side Server Streaming RPC Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/streaming.md Use `Client.CallServerStream()` to initiate a server streaming RPC. Loop using `stream.Receive()` to get messages, access them with `stream.Msg()`, and check for errors after the loop with `stream.Err()`. Response headers and trailers can be accessed via `ResponseHeader()` and `ResponseTrailer()`. ```go type ServerStreamForClient[Res any] struct { // Private fields } func (s *ServerStreamForClient[Res]) Spec() Spec func (s *ServerStreamForClient[Res]) Peer() Peer func (s *ServerStreamForClient[Res]) Receive() bool func (s *ServerStreamForClient[Res]) Msg() *Res func (s *ServerStreamForClient[Res]) Err() error func (s *ServerStreamForClient[Res]) ResponseHeader() http.Header func (s *ServerStreamForClient[Res]) ResponseTrailer() http.Header ``` ```go req := connect.NewRequest(&MyRequest{}) stream, err := client.CallServerStream(ctx, req) if err != nil { log.Fatal(err) } for stream.Receive() { msg := stream.Msg() log.Printf("Received: %v", msg) } if err := stream.Err(); err != nil { log.Fatal(err) } log.Printf("Headers: %v", stream.ResponseHeader()) log.Printf("Trailers: %v", stream.ResponseTrailer()) ``` -------------------------------- ### Adding Details and Metadata to Connect Errors Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/errors.md Demonstrates how to add arbitrary Protobuf details and custom metadata to a `connect.Error`. This is useful for providing clients with additional context or retry information. ```go err := connect.NewError(connect.CodeUnknown, fmt.Errorf("database failed")) detail, _ := connect.NewErrorDetail(someProtoMessage) err.AddDetail(detail) err.Meta().Set("x-retry-after", "30") ``` -------------------------------- ### Bidirectional Streaming Handler - BidiStream[Req, Res] Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/streaming.md Server-side interface for bidirectional streaming RPCs. Allows interleaving receives and sends, potentially using goroutines for concurrent processing. Use `Receive` to get incoming messages and `Send` to send responses. Check `Err` for stream errors. ```go type BidiStream[Req, Res any] struct { // Private fields } func (s *BidiStream[Req, Res]) Spec() Spec func (s *BidiStream[Req, Res]) Peer() Peer func (s *BidiStream[Req, Res]) Receive() bool func (s *BidiStream[Req, Res]) Msg() *Req func (s *BidiStream[Req, Res]) Err() error func (s *BidiStream[Req, Res]) Send(msg *Res) error func (s *BidiStream[Req, Res]) ResponseHeader() http.Header func (s *BidiStream[Req, Res]) ResponseTrailer() http.Header ``` ```go func (h *Handler) Echo(ctx context.Context, stream *connect.BidiStream[Message]) error { // Simple echo: receive and immediately send back for stream.Receive() { msg := stream.Msg() if err := stream.Send(&Message{Text: "Echo: " + msg.Text}); err != nil { return err } } return stream.Err() } func (h *Handler) ComplexBidi(ctx context.Context, stream *connect.BidiStream[Message]) error { // Set headers on first Send stream.ResponseHeader().Set("X-Stream-Start", time.Now().Format(time.RFC3339)) // Send responses in a goroutine based on receives go func() { for stream.Receive() { msg := stream.Msg() // Process asynchronously } }() // Send a summary after delay time.Sleep(1 * time.Second) return stream.Send(&Message{Text: "Summary: processed messages"}) } ``` -------------------------------- ### Setting and Accessing Stream Metadata Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/streaming.md Demonstrates how to set request headers on the client and response headers/trailers on both client and handler sides. Protocol-specific headers are reserved. ```go // Client side (request headers) stream.RequestHeader().Set("Authorization", "Bearer token") stream.RequestHeader().Set("X-Custom", "value") // Client side (response headers/trailers) log.Printf("Response headers: %v", stream.ResponseHeader()) log.Printf("Response trailers: %v", stream.ResponseTrailer()) // Handler side (response headers set before first Send) stream.ResponseHeader().Set("X-Stream-ID", uuid.New().String()) // Handler side (response trailers set anytime) stream.ResponseTrailer().Set("X-Total-Count", "42") ``` -------------------------------- ### Writing Response Headers and Trailers in Streaming Handlers Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/context-callinfo.md Illustrates how to set response headers and trailers for streaming handlers using the ServerStream interface. ```APIDOC **Streaming handlers** (via stream): ```go func (h *Handler) StreamRPC(ctx context.Context, stream *connect.ServerStream[Output]) error { stream.ResponseHeader().Set("X-Stream-ID", uuid.New().String()) // Send messages stream.Send(&Output{}) // Set trailers stream.ResponseTrailer().Set("X-Total-Count", "42") return nil } ``` ``` -------------------------------- ### WithResponseInitializer Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/options-api.md Provides a function to initialize new response messages on the client side. ```APIDOC ## WithResponseInitializer ### Description Provides a function to initialize new response messages on the client side. ### Signature ```go func WithResponseInitializer(initializer func(spec Spec, message any) error) ClientOption ``` ``` -------------------------------- ### Store and Retrieve Custom Values in Context Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/context-callinfo.md Illustrates how to add custom key-value pairs to a context on the client side and retrieve them within the server handler. It's crucial to use a custom type for context keys to prevent potential collisions. ```go // Client side: Add custom values to context type userKey string ctx := context.WithValue(context.Background(), userKey("user"), "alice") // Handler can retrieve the value func (h *Handler) MyRPC(ctx context.Context, req *connect.Request[Input]) (*connect.Response[Output], error) { user := ctx.Value(userKey("user")).(string) log.Printf("User: %v", user) return connect.NewResponse(&Output{}), nil } ``` -------------------------------- ### Enable HTTP/2 without TLS (h2c) Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/http-integration.md Use this to create an HTTP/2 server without TLS encryption. Ensure you import the necessary packages for HTTP/2 and h2c. ```go import "golang.org/x/net/http2" import "golang.org/x/net/http2/h2c" // Create an HTTP/2 server without TLS handler := mux // Your Connect handlers server := &http.Server{ Addr: ":8080", Handler: h2c.NewHandler(handler, &http2.Server{}), } if err := server.ListenAndServe(); err != nil { log.Fatal(err) } ``` -------------------------------- ### Writing Response Headers and Trailers via CallInfo Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/context-callinfo.md Demonstrates how to set custom response headers and trailers using the CallInfo interface within a handler. ```APIDOC ## Writing Response Headers and Trailers **Via CallInfo** (simple API): ```go func (h *Handler) MyRPC(ctx context.Context, req *connect.Request[Input]) (*connect.Response[Output], error) { callInfo, ok := connect.CallInfoForHandlerContext(ctx) if ok { callInfo.ResponseHeader().Set("X-Custom-Header", "value") callInfo.ResponseTrailer().Set("X-Summary", "42") } return connect.NewResponse(&Output{}), nil } ``` ``` -------------------------------- ### Creating a Handler Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/INDEX.md Illustrates how to create a unary RPC handler for a specific service method, including optional interceptors. ```APIDOC ## Creating a Handler ```go handler := connect.NewUnaryHandler( "/myservice.MyService/MyMethod", func(ctx context.Context, req *connect.Request[Input]) (*connect.Response[Output], error) { return connect.NewResponse(&Output{Result: "ok"}), nil }, connect.WithInterceptors(logger), ) ``` ``` -------------------------------- ### Make a Unary RPC Call Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/INDEX.md Execute a unary RPC call using the created client. Includes context management with a timeout and basic error handling to inspect connect errors. ```go ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) deferr cancel() req := connect.NewRequest(&MyRequest{Msg: "hello"}) resp, err := client.CallUnary(ctx, req) if err != nil { var connectErr *connect.Error if errors.As(err, &connectErr) { log.Printf("Error code: %v", connectErr.Code()) } } ``` -------------------------------- ### Write Streaming Response Headers and Trailers Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/context-callinfo.md For streaming handlers, set response headers and trailers directly on the `connect.ServerStream` object. This allows for dynamic metadata updates during the stream. ```go func (h *Handler) StreamRPC(ctx context.Context, stream *connect.ServerStream[Output]) error { stream.ResponseHeader().Set("X-Stream-ID", uuid.New().String()) // Send messages stream.Send(&Output{}) // Set trailers stream.ResponseTrailer().Set("X-Total-Count", "42") return nil } ``` -------------------------------- ### Configure Client TLS Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/http-integration.md Configure TLS settings for an HTTP client to establish secure connections. This involves creating a tls.Config and setting it on the http.Transport. ```go tlsConfig := &tls.Config{ // Your TLS configuration } transport := &http.Transport{ TLSClientConfig: tlsConfig, } httpClient := &http.Client{ Transport: transport, } client := connect.NewClient(httpClient, "https://example.com:8443") ``` -------------------------------- ### Connect-Go API Surface Overview Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/MANIFEST.md This section outlines the scope of the Connect-Go API documentation, highlighting what is covered, such as exported functions, types, methods, configuration, error codes, and protocols. ```APIDOC ## Connect-Go API Documentation Scope This documentation covers the following aspects of the Connect-Go library: ### Exported Functions - Constructors (e.g., `NewClient`, `NewUnaryHandler`) - RPC call methods (e.g., `CallUnary`, `CallClientStream`) - Utility functions (e.g., `CodeOf`, `EncodeBinaryHeader`) ### Exported Types - Structs: `Request[T]`, `Response[T]`, `Error`, `Spec`, `Peer` - Interfaces: `Interceptor`, `Codec`, `StreamingHandlerConn`, `StreamingClientConn`, `CallInfo` - Type aliases: `Code`, `StreamType`, `IdempotencyLevel` ### Methods - Client methods - Handler methods - Stream methods - Error methods ### Configuration - Functional options with parameter tables - Default values and use cases ### Error Codes - All 16 standard codes, trigger conditions, and usage examples ### Protocols - Connect, gRPC, gRPC-Web - Protocol negotiation and selection - Content-Type mappings ``` -------------------------------- ### Writing Response Headers and Trailers via Response Wrapper Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/context-callinfo.md Shows the standard method of setting response headers and trailers by directly manipulating the Response wrapper object. ```APIDOC **Via Response wrapper** (standard API): ```go func (h *Handler) MyRPC(ctx context.Context, req *connect.Request[Input]) (*connect.Response[Output], error) { resp := connect.NewResponse(&Output{}) resp.Header().Set("X-Custom-Header", "value") resp.Trailer().Set("X-Summary", "42") return resp, nil } ``` ``` -------------------------------- ### Limit Client Uploads and Server Responses Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/http-integration.md Configure message size limits for both client uploads and server responses. Use `connect.WithReadMaxBytes` for handler-level or client-level configurations. ```go // Handler: limit client uploads handler := connect.NewUnaryHandler( "/foo.FooService/Upload", handler, connect.WithReadMaxBytes(100*1024*1024), // 100MB per message ) // Client: limit server responses client := connect.NewClient( httpClient, url, connect.WithReadMaxBytes(50*1024*1024), // 50MB per message ) ``` -------------------------------- ### Handler Context Awareness Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/context-callinfo.md Shows how a handler can check for RPC deadlines and respect context cancellation signals to gracefully handle ongoing operations. ```go func (h *Handler) MyRPC(ctx context.Context, req *connect.Request[Input]) (*connect.Response[Output], error) { // Check if context has deadline if deadline, ok := ctx.Deadline(); ok { remaining := time.Until(deadline) log.Printf("RPC deadline in %v", remaining) } // Respect context cancellation select { case <-ctx.Done(): return nil, ctx.Err() default: // Proceed } // Long-running operation with context awareness result, err := doWork(ctx) return connect.NewResponse(result), err } ``` -------------------------------- ### Register Compression Algorithm for Handler Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/options-api.md Use `WithCompression` to register a compression algorithm on a handler, enabling it to receive compressed requests and send compressed responses. Pass nil for decompressor and compressor factories to deregister an algorithm. Gzip support is enabled by default. ```go func WithCompression( name string, newDecompressor func() Decompressor, newCompressor func() Compressor, ) HandlerOption ``` -------------------------------- ### Chaining Client Interceptors in Go Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/interceptors.md Demonstrates how to chain multiple interceptors for a Connect-Go client. The order of interceptors in the `WithInterceptors` option determines the execution flow for requests and responses. ```go client := connect.NewClient( httpClient, url, connect.WithInterceptors( &AuthInterceptor{token: "bearer abc123"}, &LoggingInterceptor{}, &RetryInterceptor{maxAttempts: 3, backoff: 100*time.Millisecond}, &MetricsInterceptor{}, ), ) // Execution order: // Request: Auth -> Logging -> Retry -> Metrics -> network // Response: Metrics -> Retry -> Logging -> Auth -> caller ``` -------------------------------- ### WithClientOptions Source: https://github.com/connectrpc/connect-go/blob/main/_autodocs/options-api.md Composes multiple ClientOption instances into a single ClientOption. This is useful for library authors who want to bundle related options together. ```APIDOC ## WithClientOptions ### Description Composes multiple `ClientOption`s into a single option. **Used by**: Library authors bundling related options. ### Signature ```go func WithClientOptions(options ...ClientOption) ClientOption ``` ```