mu-rpc-0.5.0.0: src/Mu/Rpc/Examples.hs
{-# language DataKinds #-}
{-# language DeriveAnyClass #-}
{-# language DeriveGeneric #-}
{-# language DerivingVia #-}
{-# language FlexibleContexts #-}
{-# language FlexibleInstances #-}
{-# language GADTs #-}
{-# language MultiParamTypeClasses #-}
{-# language OverloadedStrings #-}
{-# language PartialTypeSignatures #-}
{-# language PolyKinds #-}
{-# language ScopedTypeVariables #-}
{-# language TypeApplications #-}
{-# language TypeFamilies #-}
{-# language TypeOperators #-}
{-# OPTIONS_GHC -fno-warn-partial-type-signatures #-}
{-|
Description : Examples for service and server definitions
Look at the source code of this module.
-}
module Mu.Rpc.Examples where
import qualified Data.Aeson as J
import Data.Conduit
import Data.Conduit.Combinators as C
import qualified Data.Text as T
import GHC.Generics
import GHC.TypeLits
import Mu.Adapter.Json ()
import Mu.Rpc
import Mu.Schema
import Mu.Server
-- Defines the service from gRPC Quickstart
-- https://grpc.io/docs/quickstart/python/
type QuickstartSchema
= '[ 'DRecord "HelloRequest"
'[ 'FieldDef "name" ('TPrimitive T.Text) ]
, 'DRecord "HelloResponse"
'[ 'FieldDef "message" ('TPrimitive T.Text) ]
, 'DRecord "HiRequest"
'[ 'FieldDef "number" ('TPrimitive Int) ]
]
type QuickStartService
= ('Package ('Just "helloworld")
'[ 'Service "Greeter"
'[ 'Method "SayHello"
'[ 'ArgSingle ('Nothing :: Maybe Symbol) ('SchemaRef QuickstartSchema "HelloRequest") ]
('RetSingle ('SchemaRef QuickstartSchema "HelloResponse"))
, 'Method "SayHi"
'[ 'ArgSingle ('Nothing :: Maybe Symbol) ('SchemaRef QuickstartSchema "HiRequest")]
('RetStream ('SchemaRef QuickstartSchema "HelloResponse"))
, 'Method "SayManyHellos"
'[ 'ArgStream ('Nothing :: Maybe Symbol) ('SchemaRef QuickstartSchema "HelloRequest")]
('RetStream ('SchemaRef QuickstartSchema "HelloResponse")) ] ] :: Package')
newtype HelloRequest = HelloRequest { name :: T.Text }
deriving ( Show, Eq, Generic
, ToSchema QuickstartSchema "HelloRequest"
, FromSchema QuickstartSchema "HelloRequest" )
deriving (J.ToJSON, J.FromJSON)
via (WithSchema QuickstartSchema "HelloRequest" HelloRequest)
newtype HelloResponse = HelloResponse { message :: T.Text }
deriving ( Show, Eq, Generic
, ToSchema QuickstartSchema "HelloResponse"
, FromSchema QuickstartSchema "HelloResponse" )
deriving (J.ToJSON, J.FromJSON)
via (WithSchema QuickstartSchema "HelloResponse" HelloResponse)
newtype HiRequest = HiRequest { number :: Int }
deriving ( Show, Eq, Generic
, ToSchema QuickstartSchema "HiRequest"
, FromSchema QuickstartSchema "HiRequest" )
deriving (J.ToJSON, J.FromJSON)
via (WithSchema QuickstartSchema "HiRequest" HiRequest)
quickstartServer :: forall m i. (MonadServer m)
=> ServerT '[] i QuickStartService m _
quickstartServer
-- = Server (sayHello :<|>: sayHi :<|>: sayManyHellos :<|>: H0)
= singleService ( method @"SayHello" sayHello
, method @"SayManyHellos" sayManyHellos
, method @"SayHi" sayHi )
where
sayHello :: HelloRequest -> m HelloResponse
sayHello (HelloRequest nm)
= pure $ HelloResponse $ "hi, " <> nm
sayHi :: HiRequest
-> ConduitT HelloResponse Void m ()
-> m ()
sayHi (HiRequest n) sink
= runConduit $ C.replicate n (HelloResponse "hi!") .| sink
sayManyHellos :: ConduitT () HelloRequest m ()
-> ConduitT HelloResponse Void m ()
-> m ()
sayManyHellos source sink
= runConduit $ source .| C.mapM sayHello .| sink
-- From https://www.apollographql.com/docs/apollo-server/schema/schema/
type ApolloService
= 'Package ('Just "apollo")
'[ Object "Book"
'[ ObjectField "title" '[] ('RetSingle ('PrimitiveRef String))
, ObjectField "author" '[] ('RetSingle ('ObjectRef "Author"))
]
, Object "Paper"
'[ ObjectField "title" '[] ('RetSingle ('PrimitiveRef String))
, ObjectField "author" '[] ('RetSingle ('ObjectRef "Author"))
]
, Union "Writing" ["Book", "Paper"]
, Object "Author"
'[ ObjectField "name" '[] ('RetSingle ('PrimitiveRef String))
, ObjectField "writings" '[] ('RetSingle ('ListRef ('ObjectRef "Writing")))
]
]
type ApolloBookAuthor = '[
"Book" ':-> (String, Integer)
, "Paper" ':-> (String, Integer)
, "Writing" ':-> Either (String, Integer) (String, Integer)
, "Author" ':-> Integer
]
apolloServer :: forall m i. (MonadServer m)
=> ServerT ApolloBookAuthor i ApolloService m _
apolloServer
= resolver
( object @"Author" ( field @"name" authorName
, field @"writings" authorWrs )
, object @"Book" ( field @"author" (pure . snd)
, field @"title" (pure . fst) )
, object @"Paper" ( field @"author" (pure . snd)
, field @"title" (pure . fst) )
, union @"Writing" writing )
where
authorName :: Integer -> m String
authorName _ = pure "alex" -- this would run in the DB
authorWrs :: Integer -> m [Either (String, Integer) (String, Integer)]
authorWrs _ = pure []
writing (Left c) = pure $ unionChoice @"Book" c
writing (Right c) = pure $ unionChoice @"Paper" c