connectrpc

package
v0.0.0-...-81f9724 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 18, 2026 License: Apache-2.0 Imports: 29 Imported by: 1

Documentation

Index

Constants

View Source
const (
	MetaKeyHTTPStatus          = "http-status"
	MetaKeyErrorClassification = "error-classification"
	MetaKeyGraphQLErrors       = "graphql-errors"
	MetaKeyGraphQLPartialData  = "graphql-partial-data"
	MetaKeyHTTPResponseBody    = "http-response-body"
)

Metadata keys for Connect error metadata

View Source
const (
	ErrorClassificationCritical = "CRITICAL"
	ErrorClassificationPartial  = "PARTIAL"
)

Error classification values

View Source
const GraphQLVariableNameFieldNumber protoreflect.FieldNumber = 50001

GraphQLVariableNameFieldNumber is the field number for the graphql_variable_name option.

This option specifies the exact GraphQL variable name to use for a protobuf field when the GraphQL variable name doesn't match the expected protobuf JSON format (camelCase of snake_case field name).

The extension can be declared locally in any package for portability:

package employee.v1;

extend google.protobuf.FieldOptions {
  string graphql_variable_name = 50001;
}

message FindEmployeesByCriteriaRequest {
  bool has_pets = 1 [(employee.v1.graphql_variable_name) = "HAS_PETS"];
}

Or imported from the canonical annotations.proto:

import "com/wundergraph/connectrpc/options/v1/annotations.proto";

message FindEmployeesByCriteriaRequest {
  bool has_pets = 1 [(com.wundergraph.connectrpc.options.v1.graphql_variable_name) = "HAS_PETS"];
}

Variables

View Source
var (
	ErrInternalServer = errors.New("internal server error")
)

Functions

func ConnectCodeToHTTPStatus

func ConnectCodeToHTTPStatus(code connect.Code) int

ConnectCodeToHTTPStatus maps Connect error codes to HTTP status codes. Based on the Connect RPC specification: https://connectrpc.com/docs/protocol/#error-codes

func HTTPStatusToConnectCode

func HTTPStatusToConnectCode(statusCode int) connect.Code

HTTPStatusToConnectCode maps HTTP status codes to Connect error codes. Only the cases explicitly listed in the Connect RPC specification are mapped; all other status codes (including 500) fall through to CodeUnknown per spec. See: https://connectrpc.com/docs/protocol/#error-codes

func LoadOperationsForService

func LoadOperationsForService(serviceName string, operationFiles []string, logger *zap.Logger) (map[string]*schemaloader.Operation, error)

LoadOperationsForService loads GraphQL operations for a specific service from operation files. Operations are scoped to the service's fully qualified name (package.service). Returns a map of operation name -> Operation for the service.

Types

type DiscoveredService

type DiscoveredService struct {
	// ServiceDir is the directory containing the service's proto and operation files
	ServiceDir string
	// ProtoFiles are the proto files found in this service directory
	ProtoFiles []string
	// OperationFiles are the GraphQL operation files found recursively in this service directory
	OperationFiles []string
	// Package is the proto package name extracted from proto files
	Package string
	// ServiceName is the service name extracted from proto files
	ServiceName string
	// FullName is the fully qualified service name (package.service)
	FullName string
}

DiscoveredService represents a service found during directory scanning

func DiscoverServices

func DiscoverServices(config ServiceDiscoveryConfig) ([]DiscoveredService, error)

DiscoverServices scans a services directory and discovers all services based on convention. It looks for subdirectories containing .proto files and returns information about each service.

Directory structure can be: - Flat: services/employee.v1/*.proto - Nested: services/company/employee.v1/*.proto

Each service directory must contain at least one .proto file. All .proto files in a service directory must declare the same package. The service name is extracted from the proto files, not the directory name.

type GraphQLError

type GraphQLError struct {
	Message    string                 `json:"message"`
	Path       []any                  `json:"path,omitempty"`
	Locations  []GraphQLErrorLocation `json:"locations,omitempty"`
	Extensions map[string]any         `json:"extensions,omitempty"`
}

GraphQLError represents an error returned in a GraphQL response

type GraphQLErrorLocation

type GraphQLErrorLocation struct {
	Line   int `json:"line"`
	Column int `json:"column"`
}

GraphQLErrorLocation represents the location of an error in the GraphQL query

type GraphQLRequest

type GraphQLRequest struct {
	Query     string          `json:"query"`
	Variables json.RawMessage `json:"variables,omitempty"`
}

GraphQLRequest represents a GraphQL request structure

type GraphQLResponse

type GraphQLResponse struct {
	Errors []GraphQLError  `json:"errors,omitempty"`
	Data   json.RawMessage `json:"data,omitempty"`
}

GraphQLResponse represents a GraphQL response structure

type HandlerConfig

type HandlerConfig struct {
	GraphQLEndpoint   string
	HTTPClient        *http.Client
	Logger            *zap.Logger
	OperationRegistry *OperationRegistry
	ProtoLoader       *ProtoLoader
}

HandlerConfig contains configuration for the RPC handler

type MethodDefinition

type MethodDefinition struct {
	// Name is the method name (e.g., "GetUser")
	Name string
	// FullName is the fully qualified method name
	FullName string
	// InputType is the fully qualified input message type
	InputType string
	// OutputType is the fully qualified output message type
	OutputType string
	// InputMessageDescriptor is the descriptor for the input message
	InputMessageDescriptor protoreflect.MessageDescriptor
	// OutputMessageDescriptor is the descriptor for the output message
	OutputMessageDescriptor protoreflect.MessageDescriptor
	// IsClientStreaming indicates if this is a client streaming RPC
	IsClientStreaming bool
	// IsServerStreaming indicates if this is a server streaming RPC
	IsServerStreaming bool
}

MethodDefinition represents a parsed RPC method

type OperationRegistry

type OperationRegistry struct {
	// contains filtered or unexported fields
}

OperationRegistry manages pre-defined GraphQL operations for ConnectRPC. Operations are scoped to their service (package.service) and cached in memory for fast access during request handling.

Thread-safety: This registry is immutable after creation, making it safe for concurrent reads without any locking overhead. To update operations, create a new registry instance with the updated data.

func NewOperationRegistry

func NewOperationRegistry(operations map[string]map[string]*schemaloader.Operation) *OperationRegistry

NewOperationRegistry creates a new immutable operation registry with pre-built operations. The operations map is used as-is without copying, so callers should not modify it after passing.

func (*OperationRegistry) Count

func (r *OperationRegistry) Count() int

Count returns the total number of operations across all services. This method is safe for concurrent use (no locking needed due to immutability).

func (*OperationRegistry) CountForService

func (r *OperationRegistry) CountForService(serviceName string) int

CountForService returns the number of operations for a specific service. This method is safe for concurrent use (no locking needed due to immutability).

func (*OperationRegistry) GetAllOperations

func (r *OperationRegistry) GetAllOperations() []schemaloader.Operation

GetAllOperations returns all operations across all services. The returned slice is a copy to prevent external modification. This method is safe for concurrent use (no locking needed due to immutability).

func (*OperationRegistry) GetAllOperationsForService

func (r *OperationRegistry) GetAllOperationsForService(serviceName string) []schemaloader.Operation

GetAllOperationsForService returns all operations for a specific service. The returned slice is a copy to prevent external modification. Returns an empty slice if the service doesn't exist. This method is safe for concurrent use (no locking needed due to immutability).

func (*OperationRegistry) GetOperationForService

func (r *OperationRegistry) GetOperationForService(serviceName, operationName string) *schemaloader.Operation

GetOperationForService retrieves an operation for a specific service. Returns nil if the service or operation is not found. This method is safe for concurrent use (no locking needed due to immutability).

func (*OperationRegistry) GetServiceNames

func (r *OperationRegistry) GetServiceNames() []string

GetServiceNames returns all service names that have operations registered. This method is safe for concurrent use (no locking needed due to immutability).

func (*OperationRegistry) HasOperationForService

func (r *OperationRegistry) HasOperationForService(serviceName, operationName string) bool

HasOperationForService checks if an operation exists for a specific service. This method is safe for concurrent use (no locking needed due to immutability).

type ProtoLoader

type ProtoLoader struct {
	// contains filtered or unexported fields
}

ProtoLoader handles loading and parsing of protobuf files

func NewProtoLoader

func NewProtoLoader(logger *zap.Logger) *ProtoLoader

NewProtoLoader creates a new proto loader

func (*ProtoLoader) GetFiles

func (pl *ProtoLoader) GetFiles() *protoregistry.Files

GetFiles returns the custom Files registry containing all loaded file descriptors This is used to create a custom type resolver

func (*ProtoLoader) GetMethod

func (pl *ProtoLoader) GetMethod(serviceName, methodName string) (*MethodDefinition, error)

GetMethod finds a method by service and method name

func (*ProtoLoader) GetService

func (pl *ProtoLoader) GetService(fullName string) (*ServiceDefinition, bool)

GetService returns a specific service definition by full name

func (*ProtoLoader) GetServices

func (pl *ProtoLoader) GetServices() map[string]*ServiceDefinition

GetServices returns all loaded service definitions. The returned map should be treated as read-only to prevent accidental mutation.

func (*ProtoLoader) LoadFromDirectories

func (pl *ProtoLoader) LoadFromDirectories(dirs []string) error

LoadFromDirectories loads all .proto files from multiple directories and validates that proto package names are unique across all directories. The proto package name acts as a namespace, so duplicate packages are not allowed.

func (*ProtoLoader) LoadFromDirectory

func (pl *ProtoLoader) LoadFromDirectory(dir string) error

LoadFromDirectory loads all .proto files from a directory

type RPCHandler

type RPCHandler struct {
	// contains filtered or unexported fields
}

RPCHandler handles RPC requests and orchestrates GraphQL execution

func NewRPCHandler

func NewRPCHandler(config HandlerConfig) (*RPCHandler, error)

NewRPCHandler creates a new RPC handler

func (*RPCHandler) GetOperationCount

func (h *RPCHandler) GetOperationCount() int

GetOperationCount returns the number of operations available

func (*RPCHandler) HandleRPC

func (h *RPCHandler) HandleRPC(ctx context.Context, serviceName, methodName string, requestJSON []byte) ([]byte, error)

HandleRPC processes an RPC request and returns a response serviceName: fully qualified service name (e.g., "mypackage.MyService") methodName: the RPC method name (e.g., "GetUser" or "QueryGetUser") requestJSON: the JSON-encoded request body ctx: request context with headers

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server is the main ConnectRPC server that handles gRPC/Connect/gRPC-Web requests

func NewServer

func NewServer(config ServerConfig) (*Server, error)

NewServer creates a new ConnectRPC server and loads all services

func (*Server) Addr

func (s *Server) Addr() net.Addr

Addr returns the server's actual listening address

func (*Server) GetOperationCount

func (s *Server) GetOperationCount() int

GetOperationCount returns the number of operations/methods available

func (*Server) GetServiceCount

func (s *Server) GetServiceCount() int

GetServiceCount returns the number of registered services

func (*Server) GetServiceNames

func (s *Server) GetServiceNames() []string

GetServiceNames returns the names of all registered services

func (*Server) Reload

func (s *Server) Reload() error

Reload reloads the server configuration and operations. This creates entirely new instances of all components for atomic hot-reload.

func (*Server) Start

func (s *Server) Start() error

Start starts the HTTP server (services must already be loaded via NewServer)

func (*Server) Stop

func (s *Server) Stop(ctx context.Context) error

Stop gracefully shuts down the server

type ServerConfig

type ServerConfig struct {
	// ServicesDir is the root directory containing all service subdirectories
	// Each service directory should contain proto files and GraphQL operations
	ServicesDir string
	// ListenAddr is the address to listen on
	ListenAddr string
	// GraphQLEndpoint is the router's GraphQL endpoint
	GraphQLEndpoint string
	// Logger for structured logging
	Logger *zap.Logger
	// RequestTimeout for HTTP requests
	RequestTimeout time.Duration
	// CorsConfig is the CORS configuration for the ConnectRPC server
	CorsConfig *cors.Config
}

ServerConfig holds configuration for the ConnectRPC server

type ServiceDefinition

type ServiceDefinition struct {
	// FullName is the fully qualified service name (e.g., "mypackage.MyService")
	FullName string
	// Package is the protobuf package name
	Package string
	// ServiceName is the simple service name
	ServiceName string
	// Methods contains all RPC methods in this service
	Methods []MethodDefinition
	// FileDescriptor is the proto file descriptor
	FileDescriptor protoreflect.FileDescriptor
	// ServiceDescriptor is the service descriptor
	ServiceDescriptor protoreflect.ServiceDescriptor
}

ServiceDefinition represents a parsed protobuf service

type ServiceDiscoveryConfig

type ServiceDiscoveryConfig struct {
	// ServicesDir is the root directory containing all service subdirectories
	ServicesDir string
	// Logger for structured logging
	Logger *zap.Logger
}

ServiceDiscoveryConfig holds configuration for service discovery

type ServiceInfo

type ServiceInfo struct {
	FullName    string   `json:"fullName"`
	ServiceName string   `json:"serviceName"`
	Methods     []string `json:"methods"`
}

ServiceInfo contains metadata about a service

type VanguardService

type VanguardService struct {
	// contains filtered or unexported fields
}

VanguardService wraps the RPC handler and creates Vanguard services that enable protocol-agnostic RPC handling. It uses the connectrpc.com/vanguard package to provide automatic transcoding between different RPC protocols (gRPC, gRPC-Web, Connect, and REST) and message formats (Protocol Buffers binary, JSON, etc.).

The service acts as a protocol adapter that:

  • Accepts requests in any supported RPC protocol (gRPC, gRPC-Web, Connect, REST)
  • Transcodes incoming requests to Connect protocol with JSON encoding
  • Forwards the normalized request to the underlying RPCHandler for GraphQL execution
  • Transcodes the response back to the client's original protocol and format

This allows clients to use their preferred RPC protocol while the router internally processes all requests uniformly as Connect+JSON, simplifying the handler implementation and enabling protocol interoperability.

func NewVanguardService

func NewVanguardService(config VanguardServiceConfig) (*VanguardService, error)

NewVanguardService creates a new Vanguard service wrapper

func (*VanguardService) GetFileDescriptors

func (vs *VanguardService) GetFileDescriptors() []protoreflect.FileDescriptor

GetFileDescriptors returns all unique file descriptors from the proto loader

func (*VanguardService) GetMethodInfo

func (vs *VanguardService) GetMethodInfo(serviceName, methodName string) (*MethodDefinition, error)

GetMethodInfo returns information about a specific method

func (*VanguardService) GetServiceCount

func (vs *VanguardService) GetServiceCount() int

GetServiceCount returns the number of registered services

func (*VanguardService) GetServiceInfo

func (vs *VanguardService) GetServiceInfo(serviceName string) (*ServiceInfo, error)

GetServiceInfo returns information about a specific service

func (*VanguardService) GetServiceNames

func (vs *VanguardService) GetServiceNames() []string

GetServiceNames returns the names of all registered services

func (*VanguardService) GetServices

func (vs *VanguardService) GetServices() []*vanguard.Service

GetServices returns all registered Vanguard services

func (*VanguardService) ValidateMethod

func (vs *VanguardService) ValidateMethod(serviceName, methodName string) error

ValidateMethod checks if a method exists in a service

func (*VanguardService) ValidateService

func (vs *VanguardService) ValidateService(serviceName string) error

ValidateService checks if a service exists

type VanguardServiceConfig

type VanguardServiceConfig struct {
	Handler     *RPCHandler
	ProtoLoader *ProtoLoader
	Logger      *zap.Logger
}

VanguardServiceConfig holds configuration for creating a Vanguard service

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL