Documentation
¶
Index ¶
- Constants
- Variables
- func ConnectCodeToHTTPStatus(code connect.Code) int
- func HTTPStatusToConnectCode(statusCode int) connect.Code
- func LoadOperationsForService(serviceName string, operationFiles []string, logger *zap.Logger) (map[string]*schemaloader.Operation, error)
- type DiscoveredService
- type GraphQLError
- type GraphQLErrorLocation
- type GraphQLRequest
- type GraphQLResponse
- type HandlerConfig
- type MethodDefinition
- type OperationRegistry
- func (r *OperationRegistry) Count() int
- func (r *OperationRegistry) CountForService(serviceName string) int
- func (r *OperationRegistry) GetAllOperations() []schemaloader.Operation
- func (r *OperationRegistry) GetAllOperationsForService(serviceName string) []schemaloader.Operation
- func (r *OperationRegistry) GetOperationForService(serviceName, operationName string) *schemaloader.Operation
- func (r *OperationRegistry) GetServiceNames() []string
- func (r *OperationRegistry) HasOperationForService(serviceName, operationName string) bool
- type ProtoLoader
- func (pl *ProtoLoader) GetFiles() *protoregistry.Files
- func (pl *ProtoLoader) GetMethod(serviceName, methodName string) (*MethodDefinition, error)
- func (pl *ProtoLoader) GetService(fullName string) (*ServiceDefinition, bool)
- func (pl *ProtoLoader) GetServices() map[string]*ServiceDefinition
- func (pl *ProtoLoader) LoadFromDirectories(dirs []string) error
- func (pl *ProtoLoader) LoadFromDirectory(dir string) error
- type RPCHandler
- type Server
- type ServerConfig
- type ServiceDefinition
- type ServiceDiscoveryConfig
- type ServiceInfo
- type VanguardService
- func (vs *VanguardService) GetFileDescriptors() []protoreflect.FileDescriptor
- func (vs *VanguardService) GetMethodInfo(serviceName, methodName string) (*MethodDefinition, error)
- func (vs *VanguardService) GetServiceCount() int
- func (vs *VanguardService) GetServiceInfo(serviceName string) (*ServiceInfo, error)
- func (vs *VanguardService) GetServiceNames() []string
- func (vs *VanguardService) GetServices() []*vanguard.Service
- func (vs *VanguardService) ValidateMethod(serviceName, methodName string) error
- func (vs *VanguardService) ValidateService(serviceName string) error
- type VanguardServiceConfig
Constants ¶
const ( MetaKeyHTTPStatus = "http-status" MetaKeyErrorClassification = "error-classification" MetaKeyGraphQLErrors = "graphql-errors" MetaKeyGraphQLPartialData = "graphql-partial-data" MetaKeyHTTPResponseBody = "http-response-body" )
Metadata keys for Connect error metadata
const ( ErrorClassificationCritical = "CRITICAL" ErrorClassificationPartial = "PARTIAL" )
Error classification values
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 ¶
var (
ErrInternalServer = errors.New("internal server error")
)
Functions ¶
func ConnectCodeToHTTPStatus ¶
ConnectCodeToHTTPStatus maps Connect error codes to HTTP status codes. Based on the Connect RPC specification: https://connectrpc.com/docs/protocol/#error-codes
func HTTPStatusToConnectCode ¶
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 ¶
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) GetOperationCount ¶
GetOperationCount returns the number of operations/methods available
func (*Server) GetServiceCount ¶
GetServiceCount returns the number of registered services
func (*Server) GetServiceNames ¶
GetServiceNames returns the names of all registered services
func (*Server) Reload ¶
Reload reloads the server configuration and operations. This creates entirely new instances of all components for atomic hot-reload.
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