Créez des API GraphQL avec votre langage fonctionnel préféré!
Morpheus GraphQL (serveur et client) vous aide à créer des API GraphQL dans Haskell avec des types de Haskell natifs. Morpheus convertira vos types Haskell en un schéma GraphQL et tous vos résolveurs ne sont que des fonctions Haskell natives. Morpheus GraphQL peut également convertir votre schéma GraphQL ou requête en types Haskell et les valider en temps de compilation.
Morpheus est encore à un stade précoce du développement, donc toute rétroaction est plus que bienvenue, et nous apprécions toute contribution! Ouvrez simplement un problème ici sur GitHub, ou rejoignez notre canal Slack pour contacter.
Veuillez noter que ce fichier ReadMe ne fournit qu'une brève introduction à la bibliothèque. Si vous êtes intéressé par des sujets plus avancés, visitez les documents.
Depuis la version V0.28.0, Morpheus GraphQL implémente le [https://github.com/enisdenjo/graphql-ws/blob/master/protocol.md https://github.com/apollographql/subscriptions-transport-ws/blob/master/protocol.md protocole.
Pour commencer avec Morpheus, vous devez d'abord l'ajouter aux dépendances de votre projet, comme suit (en supposant que vous utilisez HPACK):
package.yml
dependencies :
- morpheus-graphql
- morpheus-graphql-core
- morpheus-graphql-subscriptionsDe plus, vous devez dire Stack quelle version choisir:
stack.yml
resolver : lts-16.2
extra-deps :
- morpheus-graphql-0.28.0
- morpheus-graphql-core-0.28.0
- morpheus-graphql-app-0.28.0
- morpheus-graphql-code-gen-0.28.0
- morpheus-graphql-code-gen-utils-0.28.0
- morpheus-graphql-server-0.28.0
- morpheus-graphql-client-0.28.0
- morpheus-graphql-subscriptions-0.28.0schéma.gql
type Query {
deity ( name : String ! = " Morpheus " ): Deity !
}
"""
Description for Deity
"""
type Deity {
"""
Description for name
"""
name : String !
power : String @deprecated ( reason : " some reason for " )
}Api.hs
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
module API ( api ) where
import Data.ByteString.Lazy.Char8 ( ByteString )
import Data.Morpheus ( interpreter )
import Data.Morpheus.Document ( importGQLDocument )
import Data.Morpheus.Types ( RootResolver ( .. ), Undefined ( .. ))
import Data.Text ( Text )
importGQLDocument " schema.gql "
rootResolver :: RootResolver IO () Query Undefined Undefined
rootResolver =
RootResolver
{ queryResolver = Query {deity},
mutationResolver = Undefined ,
subscriptionResolver = Undefined
}
where
deity DeityArgs {name} =
pure
Deity
{ name = pure name,
power = pure ( Just " Shapeshifting " )
}
api :: ByteString -> IO ByteString
api = interpreter rootResolver Modèle Haskell génère des types: Query , Deity , DeityArgs , qui peut être utilisé par rootResolver
descriptions et deprecations seront affichées dans l'introspection.
importGQLDocumentWithNamespace générera des types avec des champs dans les noms de noms. Si vous n'avez pas besoin d'espace de noms, utilisez importGQLDocument
Pour définir une API GraphQL avec Morpheus, nous commençons par définir le schéma API en tant que type de données Haskell natif, qui dérive la classe de type Generic . En utilisant l'extension de la langue DeriveAnyClass , nous dérivons ensuite également des instances pour la classe GQLType . Les champs paresseusement résolus sur ce type Query sont définis via a -> ResolverQ () IO b , représentant la résolution d'un ensemble d'arguments a à une valeur en béton b .
data Query m = Query
{ deity :: DeityArgs -> m Deity
} deriving ( Generic , GQLType )
data Deity = Deity
{ fullName :: Text -- Non-Nullable Field
, power :: Maybe Text -- Nullable Field
} deriving ( Generic , GQLType )
data DeityArgs = DeityArgs
{ name :: Text -- Required Argument
, mythology :: Maybe Text -- Optional Argument
} deriving ( Generic , GQLType ) Pour chaque champ du type Query défini via a -> mb (comme deity ), nous définirons une implémentation de résolveur qui fournit les valeurs pendant l'exécution en se référant à une source de données, par exemple une base de données ou une autre API. Champs définis sans a -> mb vous pouvez simplement fournir une valeur.
Dans l'exemple ci-dessus, le domaine de DeityArgs pourrait également être nommé en utilisant des identités réservées (telles que: type , where , etc.), afin d'éviter les conflits, un symbole principal ( ' ) doit être attaché. Par exemple, vous pouvez avoir:
data DeityArgs = DeityArgs
{ name :: Text -- Required Argument
, mythology :: Maybe Text -- Optional Argument
, type' :: Text
} deriving ( Generic , GQLType ) Le nom de champ dans la demande finale sera type au lieu du type' . L'analyseur de la demande Morpheus convertit chacune des identités réservées dans Haskell 2010 en leurs noms correspondants en interne. Cela s'applique également aux sélections.
resolveDeity :: DeityArgs -> ResolverQ () IO Deity
resolveDeity DeityArgs { name, mythology } = liftEither $ dbDeity name mythology
askDB :: Text -> Maybe Text -> IO ( Either String Deity )
askDB = ... Pour rendre ce type Query disponible en tant qu'API, nous définissons un RootResolver et l'alimentons à l' interpreter Morpheus. Un RootResolver se compose de définitions query , mutation et subscription , tandis que nous omettons ce dernier pour cet exemple:
rootResolver :: RootResolver IO () Query Undefined Undefined
rootResolver =
RootResolver
{ queryResolver = Query {deity = resolveDeity}
, mutationResolver = Undefined
, subscriptionResolver = Undefined
}
gqlApi :: ByteString -> IO ByteString
gqlApi = interpreter rootResolver Comme vous pouvez le voir, l'API est définie comme ByteString -> IO ByteString que nous pouvons invoquer directement ou utiliser dans un cadre Web arbitraire tel que scotty ou serverless-haskell . Nous irons pour scotty dans cet exemple:
main :: IO ()
main = scotty 3000 $ post " /api " $ raw =<< (liftIO . gqlApi =<< body) Si nous envoyons maintenant une demande de poste à http://localhost:3000/api avec une requête GraphQL comme corps par exemple dans un outil comme Insomnia :
query GetDeity {
deity ( name : " Morpheus " ) {
fullName
power
}
}Notre requête sera résolue!
{
"data" : {
"deity" : {
"fullName" : " Morpheus " ,
"power" : " Shapeshifting "
}
}
} Si vous êtes intéressé à créer une API Morpheus GraphQL avec Serverless , vous devriez jeter un œil à notre exemple dans cette API Repository: Mythology Il s'agit de notre exemple de construction de projet avec Morpheus GraphQL et Serverless-Haskell , où vous pouvez interroger différents caractères de mythologie avec GraphiQL .
Mythology API est déployé sur: api.morpheusgraphql.com où vous pouvez le tester avec GraphiQL
Vous trouverez ci-dessous la liste des projets utilisant Morpheus GraphQL. Si vous souhaitez commencer à utiliser Morpheus GraphQL, ce sont de bons modèles pour commencer.
Modifiez cette section et envoyez des PR si vous souhaitez partager votre projet .
Morpheus est le dieu grec du sommeil et des rêves dont le nom vient du mot grec μορφή sens ou forme de sens. Il pourrait imiter différentes formes et GraphQL est bon pour faire exactement cela: transformer des données sous la forme de nombreuses API différentes.
Morpheus est écrit et maintenu par Nalchevanidze