Wrapper around Handler Server to avoid ambiguous types
Constructors
ServerHandler :: SupportsStreamingType rpc styp => Handler 'Server styp m rpc -> ServerHandler' styp m rpc
:: a typeCtrl KGHC 9.10.3 · lts/ghc-9.10.x · 248f8f0 · 2026-10-05
Modulegrapesy-1.1.1Haskell2010
Server handlers
Wrapper around Handler Server to avoid ambiguous types
ServerHandler :: SupportsStreamingType rpc styp => Handler 'Server styp m rpc -> ServerHandler' styp m rpctype ServerHandler (m :: Type -> Type) (rpc :: k) = ServerHandler' (RpcStreamingType rpc) m rpcAlias for ServerHandler' with the streaming type determined by the rpc
Declare handlers for a set of RPCs
See also simpleMethods for an alternative API if you only need the Method constructor.
Example that provides methods for the gRPC RouteGuide API:
handlers :: [Feature] -> Methods IO (ProtobufMethodsOf RouteGuide)
handlers db =
Method (mkNonStreaming $ getFeature db)
$ Method (mkServerStreaming $ listFeatures db)
$ Method (mkClientStreaming $ recordRoute db)
$ Method (mkBiDiStreaming $ routeChat db)
$ NoMoreMethodsIt is also possibly to define your own list of RPC, instead of computing it
using ProtobufMethodsOf (indeed, there is no need to use Protobuf at all).
Provided that you give a top-level type annotation, then type inference can guide this definition:
handlers :: [Feature] -> Methods IO (ProtobufMethodsOf RouteGuide)
handlers db = _methodsThis will reveal that we need four methods:
_methods :: Methods IO '[
Protobuf RouteGuide "getFeature"
, Protobuf RouteGuide "listFeatures"
, Protobuf RouteGuide "recordRoute"
, Protobuf RouteGuide "routeChat"
]We can use this to make a skeleton definition, with holes for each handler:
handlers :: [Feature] -> Methods IO (ProtobufMethodsOf RouteGuide)
handlers db =
Method _getFeature
$ Method _listFeatures
$ Method _recordRoute
$ Method _routeChar
$ NoMoreMethodsThis will reveal types such as this:
_getFeature :: ServerHandler' NonStreaming IO (Protobuf RouteGuide "getFeature")which we can simplify to
_getFeature :: ServerHandler IO (Protobuf RouteGuide "getFeature")(the non-primed version of ServerHandler infers the streaming type from the RPC, when possible). Finally, if we then refine the skeleton to
Method (mkNonStreaming $ _getFeature)ghc will tell us
_getFeature :: Proto Point -> IO (Proto Feature)NoMoreMethods :: Methods m '[]All methods of the service handled
Method :: (SupportsServerRpc rpc, Default (ResponseInitialMetadata rpc), Default (ResponseTrailingMetadata rpc), SupportsStreamingType rpc styp) => ServerHandler' styp m rpc -> Methods m rpcs1 -> Methods m (rpc ': rpcs1)Define the next method of the service, inferring the streaming type
In the most common case (Protobuf), the streaming type can be inferred from the method. In this case, it is convenient to use Method, as type inference will tell you what kind of handler you need to define (see also the example above).
RawMethod :: SupportsServerRpc rpc => RpcHandler m rpc -> Methods m rpcs1 -> Methods m (rpc ': rpcs1)Define a method that uses uses the raw (core) API instead
This is useful when the communication pattern does not fall neatly into the four streaming types (non-streaming, client-side streaming, server-side streaming, or bidirectional streaming), or when you need access to lower level features such as request or response metadata, compression options, etc.
UnsupportedMethod :: Methods m rpcs1 -> Methods m (rpc ': rpcs1)Declare that this particular rpc method is not supported by this server
SimpleMethods m '[] rpcs (Methods m rpcs)Defined in grapesy-1.1.1 · Network.GRPC.Server.StreamTypeDeclare handlers for a set of services
See also fromServices.
Example usage:
services :: [Feature] -> Services IO (ProtobufServices '[Greeter, RouteGuide])
services db =
Service Greeter.handlers
$ Service (RouteGuide.handlers db)
$ NoMoreServicesConstruct SomeRpcHandler from a streaming handler
Most users will not need to call this function, but it can occassionally be
useful when using the lower-level API. Depending on usage you may need to
provide a type argument to fix the rpc, for example
Server.fromMethod @EmptyCall $ ServerHandler $ \(_ ::Empty) ->
return (defMessage :: Empty)If the streaming type cannot be deduced, you might need to specify that also:
Server.fromMethod @Ping @NonStreaming $ ServerHandler $ ..Alternatively, use one of the handler construction functions, such as
Server.fromMethod @Ping $ Server.mkNonStreaming $ ..List handlers for all methods of a given service.
This can be used to verify at the type level that all methods of the given service are handled. A typical definition of the Methods might have a type such as this:
methods :: Methods IO (ProtobufMethodsOf RouteGuide)See also fromServices if you are defining more than one service.
List handlers for all methods of all services.
This can be used to verify at the type level that all methods of all services are handled. A typical definition of the Services might have a type such as this:
services :: Services IO (ProtobufServices '[Greeter, RouteGuide])See also fromMethods if you are only defining one service.
Alternative way to construct Methods
Listing the handlers for the gRPC routeguide server using Methods directly looks like this:
Method (mkNonStreaming $ getFeature db)
$ Method (mkServerStreaming $ listFeatures db)
$ Method (mkClientStreaming $ recordRoute db)
$ Method (mkBiDiStreaming $ routeChat db)
$ NoMoreMethodsSince we only use Method here, we can instead write this as
simpleMethods
(mkNonStreaming $ getFeature db)
(mkServerStreaming $ listFeatures db)
(mkClientStreaming $ recordRoute db)
(mkBiDiStreaming $ routeChat db)Which API you prefer is mostly just a matter of taste.