Skip to content

Instantly share code, notes, and snippets.

@intolerable
Last active June 10, 2025 11:48
Show Gist options
  • Save intolerable/dbba53168b70a4bc6f72c1835de02674 to your computer and use it in GitHub Desktop.
Save intolerable/dbba53168b70a4bc6f72c1835de02674 to your computer and use it in GitHub Desktop.
HasServer instances for records of routes using TemplateHaskell instead of Generic
data NamedRoutesTH api
class ToServantApiTH routes where
type ServantApiTH routes :: Type
toServantTH :: routes (AsServerT m) -> ServerT (ServantApiTH routes) m
fromServantTH :: ServerT (ServantApiTH routes) m -> routes (AsServerT m)
instance
( ToServantApiTH api
, HasServer (ServantApiTH api) context
) => HasServer (NamedRoutesTH api) context where
type ServerT (NamedRoutesTH api) m = api (AsServerT m)
route
:: Proxy (NamedRoutesTH api)
-> Context context
-> Delayed env (api (AsServerT Handler))
-> Router env
route _p ctx delayed =
route (Proxy @(ServantApiTH api)) ctx (toServantTH <$> delayed)
hoistServerWithContext _ pctx nat server =
fromServantTH $
hoistServerWithContext (Proxy @(ServantApiTH api)) pctx nat $
toServantTH server
-- mkNamedRoutesTH :: Name -> DecsQ
-- mkNamedRoutesTH = undefined -- exercise for reader
data RoutesRecord mode = RoutesRecord
{ routeA :: mode :- "a" :> Get '[JSON] [Int]
, routeB :: mode :- "b" :> Get '[JSON] String
}
-- mkNamedRoutesTH ''RoutesRecord
-- this is the instance that `mkNamedRoutesTH` should generate
instance ToServantApiTH RoutesRecord where
type ServantApiTH RoutesRecord =
"a" :> Get '[JSON] [Int] :<|>
"b" :> Get '[JSON] String
toServantTH (RoutesRecord a b) = a :<|> b
fromServantTH (a :<|> b) = RoutesRecord a b
type API = NamedRoutesTH RoutesRecord
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment