¡Construya API GraphQL con su idioma funcional favorito!
Morpheus GraphQL (servidor y cliente) lo ayuda a construir API GraphQL en Haskell con tipos de Haskell nativos. Morpheus convertirá sus tipos de Haskell en un esquema GraphQL y todos sus resonedores son solo funciones nativas de Haskell. Morpheus GraphQL también puede convertir su esquema o consulta GraphQL a tipos de Haskell y validarlos en tiempo de compilación.
Morpheus todavía está en una etapa temprana de desarrollo, por lo que cualquier comentario es más que bienvenido, ¡y apreciamos cualquier contribución! Simplemente abra un problema aquí en Github, o únase a nuestro canal Slack para ponerse en contacto.
Tenga en cuenta que este archivo ReadMe solo proporciona una breve introducción a la biblioteca. Si está interesado en temas más avanzados, visite los documentos.
Desde la versión v0.28.0, Morpheus GraphQL implementa el [https://github.com/enisdenjo/graphql-ws/blob/master/protocol.md(graphql-ws GraphQl sobre el protocolo de WebSocket), y ya no usa el https://github.com/apollographql/subscriptions-transport-ws/blob/master/protocol.md Protocol.
Para comenzar con Morpheus, primero debe agregarlo a las dependencias de su proyecto, de la siguiente manera (suponiendo que esté usando HPACK):
paquete.yml
dependencies :
- morpheus-graphql
- morpheus-graphql-core
- morpheus-graphql-subscriptionsAdemás, debe decirle a Stack qué versión elegir:
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.0esquema.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 La plantilla Haskell genera tipos: Query , Deity , DeityArgs , que puede ser utilizado por rootResolver
descriptions y deprecations se mostrarán en la introspección.
importGQLDocumentWithNamespace generará tipos con campos atacados. Si no necesita espacio de nombres, use importGQLDocument
Para definir una API GraphQL con Morpheus, comenzamos definiendo el esquema API como un tipo de datos de Haskell nativo, que deriva la clase de tipo Generic . Usando la extensión del lenguaje DeriveAnyClass , también derivamos instancias para la clase de tipo GQLType . Los campos de resolución perezoso en este tipo Query se definen a través de a -> ResolverQ () IO b , que representa la resolución de un conjunto de argumentos a a un valor concreto 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 ) Para cada campo en el tipo Query definido a través de a -> mb (como deity ) definiremos una implementación de resolución que proporcione los valores durante el tiempo de ejecución al referirse a alguna fuente de datos, por ejemplo, una base de datos u otra API. Campos que se definen sin a -> mb Puede proporcionar un valor.
En el ejemplo anterior, el campo de DeityArgs también podría nombrarse utilizando identidades reservadas (como: type , where , etc.), para evitar conflictos, se debe adjuntar un símbolo principal ( ' ). Por ejemplo, puede tener:
data DeityArgs = DeityArgs
{ name :: Text -- Required Argument
, mythology :: Maybe Text -- Optional Argument
, type' :: Text
} deriving ( Generic , GQLType ) El nombre de campo en la solicitud final será type en lugar de type' . El analizador de solicitud de Morpheus convierte cada una de las identidades reservadas en Haskell 2010 a sus nombres correspondientes internamente. Esto también se aplica a las selecciones.
resolveDeity :: DeityArgs -> ResolverQ () IO Deity
resolveDeity DeityArgs { name, mythology } = liftEither $ dbDeity name mythology
askDB :: Text -> Maybe Text -> IO ( Either String Deity )
askDB = ... Para que este tipo Query esté disponible como API, definimos un RootResolver y la alimentamos al interpreter Morpheus. Un RootResolver consiste en definiciones de query , mutation y subscription , mientras omitimos este último para este ejemplo:
rootResolver :: RootResolver IO () Query Undefined Undefined
rootResolver =
RootResolver
{ queryResolver = Query {deity = resolveDeity}
, mutationResolver = Undefined
, subscriptionResolver = Undefined
}
gqlApi :: ByteString -> IO ByteString
gqlApi = interpreter rootResolver Como puede ver, la API se define como ByteString -> IO ByteString que podemos invocar directamente o usar dentro de un marco web arbitrario como scotty o serverless-haskell . Iremos por scotty en este ejemplo:
main :: IO ()
main = scotty 3000 $ post " /api " $ raw =<< (liftIO . gqlApi =<< body) Si ahora enviamos una solicitud de publicación a http://localhost:3000/api con una consulta GraphQL como cuerpo, por ejemplo, en una herramienta como Insomnia :
query GetDeity {
deity ( name : " Morpheus " ) {
fullName
power
}
}¡Nuestra consulta se resolverá!
{
"data" : {
"deity" : {
"fullName" : " Morpheus " ,
"power" : " Shapeshifting "
}
}
} Si está interesado en crear una API Morpheus GraphQL con Serverless , debe echar un vistazo a nuestro ejemplo en este repositorio: API de mitología Es nuestra construcción de proyecto de ejemplo con Morpheus GraphQL y Serverless-Haskell , donde puede consultar diferentes caracteres de mitología con GraphiQL .
Mythology API se implementa en: API.Morpheusgraphql.com donde puede probarlo con GraphiQL
A continuación se muestran la lista de proyectos utilizando Morpheus GraphQL. Si desea comenzar a usar Morpheus GraphQL, son buenas plantillas para empezar.
Edite esta sección y envíe PR si desea compartir su proyecto .
Morpheus es el dios griego del sueño y los sueños cuyo nombre proviene de la palabra griega μορφή que significa forma o forma. Se dice que puede imitar diferentes formas y GraphQL es bueno para hacer exactamente eso: transformar datos en forma de muchas API diferentes.
Morpheus está escrito y mantenido por Nalchevanidze