{-# 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