Создайте API GraphQL с вашим любимым функциональным языком!
Morpheus GraphQL (сервер и клиент) помогает вам создавать API GraphQL в Haskell с собственными типами Haskell. Morpheus преобразует ваши типы Haskell в схему GraphQL, и все ваши резолюры - это просто нативные функции Haskell. Morpheus GraphQL также может преобразовать вашу схему GraphQL или запрос типам Haskell и проверять их во время компиляции.
Морфеус все еще находится на ранней стадии разработки, поэтому любые отзывы более чем приветствуются, и мы ценим любой вклад! Просто откройте проблему здесь, на Github, или присоединяйтесь к нашему каналу Slack, чтобы связаться.
Обратите внимание, что этот файл Readme содержит только краткое введение в библиотеку. Если вы заинтересованы в более продвинутых темах, посетите документы.
Со времени версии v0.28.0, Morpheus GraphQL реализует [https://github.com/enisdenjo/graphql-ws/blob/master/protocol.md^(graphql-ws GraphQl по протоколу WebSocket) и больше не использует https://github.com/apollographql/subscriptions-transport-ws/blob/master/protocol.md Protocol.
Чтобы начать работу с Morpheus, вам сначала нужно добавить его в зависимости вашего проекта, следующим образом (при условии, что вы используете HPACK):
Package.yml
dependencies :
- morpheus-graphql
- morpheus-graphql-core
- morpheus-graphql-subscriptionsКроме того, вы должны сообщить Stack, какую версию выбрать:
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.0Schema.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 Шаблон Haskell генерирует типы: Query , Deity , DeityArgs , которые могут использоваться rootResolver
descriptions и deprecations будут отображаться при самоанализе.
importGQLDocumentWithNamespace будет генерировать типы с полями с имен. Если вам не нужно пространство имен используйте importGQLDocument
Чтобы определить API GraphQL с Morpheus, мы начинаем с определения схемы API как нативного типа данных Haskell, который получает Generic класс типа. Используя расширение языка DeriveAnyClass , мы также выбираем экземпляры для класса типа GQLType . Лзико разрешаемые поля на этом типе Query определяются через a -> ResolverQ () IO b , представляющие разрешение набора аргументов a до конкретного значения 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 ) Для каждого поля в типе Query , определенном через a -> mb (как deity ), мы определим реализацию резолей, которая предоставляет значения во время выполнения, ссылаясь на какой -то источник данных, например, базу данных или другой API. Поля, которые определены без a -> mb вы можете просто предоставить значение.
В приведенном выше примере поля DeityArgs также можно назвать с использованием зарезервированных идентичностей (таких как: type , where и т. Д.), Чтобы избежать конфликта, должен быть прикреплен основной символ ( ' ). Например, вы можете иметь:
data DeityArgs = DeityArgs
{ name :: Text -- Required Argument
, mythology :: Maybe Text -- Optional Argument
, type' :: Text
} deriving ( Generic , GQLType ) Имя поля в последнем запросе будет type вместо type' . Парсер запроса Morpheus преобразует каждую из зарезервированных идентификаторов в Haskell 2010 в их соответствующие имена внутренне. Это также относится к выбору.
resolveDeity :: DeityArgs -> ResolverQ () IO Deity
resolveDeity DeityArgs { name, mythology } = liftEither $ dbDeity name mythology
askDB :: Text -> Maybe Text -> IO ( Either String Deity )
askDB = ... Чтобы сделать этот тип Query доступным в качестве API, мы определяем RootResolver и подаем его interpreter Morpheus. RootResolver состоит из определений query , mutation и subscription , в то время как мы опускаем последний для этого примера:
rootResolver :: RootResolver IO () Query Undefined Undefined
rootResolver =
RootResolver
{ queryResolver = Query {deity = resolveDeity}
, mutationResolver = Undefined
, subscriptionResolver = Undefined
}
gqlApi :: ByteString -> IO ByteString
gqlApi = interpreter rootResolver Как вы можете видеть, API определяется как ByteString -> IO ByteString , который мы можем либо вызвать напрямую, либо использовать в произвольной веб -структуре, такой как scotty или serverless-haskell . В этом примере мы пойдем на scotty :
main :: IO ()
main = scotty 3000 $ post " /api " $ raw =<< (liftIO . gqlApi =<< body) Если мы теперь отправим запрос на сообщение по http://localhost:3000/api с запросом graphql, как корпус, например, в инструменте, как Insomnia :
query GetDeity {
deity ( name : " Morpheus " ) {
fullName
power
}
}Наш запрос будет разрешен!
{
"data" : {
"deity" : {
"fullName" : " Morpheus " ,
"power" : " Shapeshifting "
}
}
} Если вы заинтересованы в создании API Morpheus GraphQL с Serverless , вам следует взглянуть на наш пример в этом репозитории: Mythology API, это наша пример сборка проекта с Morpheus GraphQL и Serverless-Haskell , где вы можете запросить различные символы мифологии с помощью GraphiQL .
Mythology API развернута на: api.morpheusgraphql.com , где вы можете проверить его с помощью GraphiQL
Ниже приведен список проектов с использованием Morpheus GraphQL. Если вы хотите начать использовать Morpheus GraphQL, это хорошие шаблоны для начала.
Отредактируйте этот раздел и отправьте PR, если вы хотите поделиться своим проектом .
Морфеус - греческий бог сна и снов, чье имя происходит от греческого слова μορφή , означающая форму или форму. Говорят, что он способен имитировать различные формы, и GraphQL хорошо выполняет это: преобразование данных в форме многих различных API.
Морфеус написан и поддерживается Налчеванидзе