1 {-# LANGUAGE DeriveAnyClass #-}
2 {-# LANGUAGE DuplicateRecordFields #-} -- permit duplications for field names in multiple constructors
3 {-# LANGUAGE KindSignatures #-} -- for use of Endpoint (name :: Symbol)
4 {-# LANGUAGE PartialTypeSignatures #-} -- to automatically use suggested type hole signatures during compilation
5 {-# LANGUAGE TypeOperators #-}
7 {-# OPTIONS_GHC -fno-warn-unused-imports #-}
9 module Gargantext.API.GraphQL where
11 import Control.Monad.Base (liftBase)
12 import Control.Monad.IO.Class (liftIO)
13 import Data.ByteString.Lazy.Char8
16 import Data.List.NonEmpty (NonEmpty ((:|)))
20 import Data.Morpheus.App.Internal.Resolving
22 import Data.Morpheus.Server
25 import Data.Morpheus.Subscriptions
33 import Data.Morpheus.Types
45 import Data.Morpheus.Types.Internal.AST
47 import Data.Text (Text)
48 import qualified Data.Text.Lazy as LT
49 import Data.Text.Lazy.Encoding (decodeUtf8)
50 import Data.Typeable (Typeable)
51 import Gargantext.API.Prelude (GargServer)
52 import Gargantext.Database.Prelude (Cmd)
53 import Gargantext.Database.Query.Table.User (getUsersWithId)
54 import Gargantext.Database.Schema.User (UserPoly(..), UserLight)
55 import GHC.Generics (Generic)
57 import Network.HTTP.Media ((//), (/:))
58 import Network.WebSockets
75 -- | Represents possible GraphQL queries.
78 { user :: UserArgs -> m UserLight
79 } deriving (Generic, GQLType)
81 -- | Arguments to the "user" query.
85 } deriving (Generic, GQLType)
87 -- | Possible GraphQL Events, i.e. here we describe how we will
88 -- manipulate the data.
89 type EVENT = Event Channel Contet
91 -- | Channels are possible actions to call when manipulating the data.
95 deriving (Eq, Show, Generic, Hashable)
97 -- | This type describes what data we will operate on.
99 = UserContet UserLight
102 -- | The main GraphQL resolver: how queries, mutations and
103 -- subscriptions are handled.
104 rootResolver :: RootResolver _ EVENT Query Undefined Undefined
107 { queryResolver = Query { user = resolveUser }
108 , mutationResolver = Undefined
109 , subscriptionResolver = Undefined }
111 -- | Function to resolve user from a query.
112 resolveUser :: UserArgs -> ResolverQ e _ UserLight
113 resolveUser UserArgs { user_id } = do
114 liftEither $ dbUser user_id
115 -- user <- lift $ dbUser user_id
117 -- --Left err -> failure $ msg err
118 -- Left err -> error "fail"
121 -- | Inner function to fetch the user from DB.
122 dbUser :: Int -> Cmd err (Either String UserLight)
124 users <- getUsersWithId user_id
126 [] -> pure $ Left "User not found"
127 (user:_) -> pure $ Right user
129 -- | Main GraphQL "app".
131 app = deriveApp rootResolver
133 ----------------------------------------------
135 -- Now for some boilerplate to integrate the above GraphQL app with
138 -- | HTML type is needed for the GraphQL Playground.
139 data HTML deriving (Typeable)
140 instance Accept HTML where
141 contentTypes _ = "text" // "html" /: ("charset", "utf-8") :| ["text" // "html"]
142 instance MimeRender HTML ByteString where
143 mimeRender _ = Prelude.id
145 -- | Servant route for the app we defined above.
146 type GQAPI = ReqBody '[JSON] GQLRequest :> Post '[JSON] GQLResponse
147 -- type Schema = "schema" :> Get '[PlainText] Text
148 -- | Servant route for the playground.
149 type Playground = Get '[HTML] ByteString
150 -- type API' (name :: Symbol) = name :> (GQAPI :<|> Schema :<|> Playground)
151 -- | Our API consists of `GQAPI` and `Playground`.
152 type API = "gql" :> (GQAPI :<|> Playground)
155 -- ( SubApp ServerApp e
161 -- serveEndpoint publish app' = (liftIO . httpPubApp publish app') :<|> withSchema app' :<|> pure httpPlayground
163 -- withSchema :: (Applicative f) => App e m -> f Text
164 -- withSchema = pure . LT.toStrict . decodeUtf8 . render
166 -- | Implementation of our API.
168 api :: GargServer API
170 --(wsApp, publish') <- liftIO $ webSocketsApp app
171 --(liftIO . httpPubApp [] app) :<|> pure httpPlayground
172 (liftBase . httpPubApp [] app) :<|> pure httpPlayground