Changelog for morpheus-graphql-0.9.0
Changelog
[0.9.0] - 02.01.2020
Added
WithOperationconstraint for Generic Resolvers (#347) thanks @dandoh
Fixed
-
liftEither support in MutResolver (#351)
-
selection of
__typenameon object und union objects (#337) -
auto inferece of external types in gql document (#343)
th will generate field
m (Type m)if type has an argumente.g for this types and DSL
data Type1 = Type1 { ... } type Type2 m = SomeType m data Type3 m = Type2 { bla :: m Text } deriving ...type Query { field1 : Type1! field2 : Type2! field3 : Type3! }morpheus generates
data Query m = Query { field1 :: m Type1 field2 :: m (Type2 m) field3 :: m (Type3 m) } deriving ...now you can combine multiple gql documents:
importDocumentWithNamespace `coreTypes.gql` importDocumentWithNamespace `operations.gql`
Changed
-
support of resolver fields
m typefor the fields without argumentsdata Diety m = Deity { name :: m Text } -- is equal to data Diety m = Deity { name :: () -> m Text } -
template haskell generates
m typeinsead of() -> m typefor fields without argument (#334)data Diety m = Deity { name :: (Arrow () (m Text)), power :: (Arrow () (m (Maybe Text))) } -- changed to data Diety m = Deity { name :: m Text, power :: m (Maybe Text) }
[0.8.0] - 15.12.2019
Changed
-
deprecated:
INPUT_OBJECT,OBJECT,UNION,- use
INPUTinstead ofINPUT_OBJECT - use
deriving(GQLType)insead ofOBJECTorUNION
- use
-
only namespaced Unions generate regular graphql Union, other attempts will be wrapped inside an object with constructor name :
e.g:
data Character = CharacterDeity Deity SomeDeity Deity deriving (GQLType)where
Deityis Object. will generateunion CHaracter = Deity | SomeDeity type SomeDeity { _0: Deity }
Added
failResfor resolver failures- added kind: INPUT , OUTPUT
- Automatic Type Inference (only for Object, Union and Enum)
- More general stateful resolvers which accept instances of MonadIO (Authored by Sebastian Pulido [sebashack])
- Utility to create web-socket applications with custom MonadIO instances (Authored by Sebastian Pulido [sebashack])
data Realm =
Sky
| Sea
| Underworld
deriving (Generic, GQLType)
data Deity = Deity{
fullName:: Text,
realm:: Realm
} deriving (Generic, GQLType)
data Character =
CharacterDeity Deity -- Only <tyconName><conName> should generate direct link
-- RECORDS
| Creature { creatureName :: Text, creatureAge :: Int }
--- Types
| SomeDeity Deity
| CharacterInt Int
| SomeMutli Int Text
--- ENUMS
| Zeus
| Cronus deriving (Generic, GQLType)
will generate schema:
enum Realm {
Sky
Sea
Underworld
}
type Deity {
fullName: String!
realm: Realm!
}
union Character =
Deity
| Creature
| SomeDeity
| CharacterInt
| SomeMutli
| CharacterEnumObject
type Creature {
creatureName: String!
creatureAge: Int!
}
type SomeDeity {
_0: Deity!
}
type CharacterInt {
_0: Int!
}
type SomeMutli {
_0: Int!
_1: String!
}
# enum
type CharacterEnumObject {
enum: CharacterEnum!
}
enum CharacterEnum {
Zeus
Cronus
}
rules:
-
haskell union type with only empty constructors (e.g
Realm), will generate graphqlenum -
haskell record without union (e.g
Deity), will generate graphqlobject -
namespaced Unions:
CharacterDeitywhereCharacteris TypeConstructor andDeityreferenced object (not scalar) type: will be generate regular graphql Unionunion Character = Deity | ... -
for union recrods (
Creature { creatureName :: Text, creatureAge :: Int }) will be referenced in union type, plus typeCreaturewill be added in schema.e.g
union Character = ... | Creature | ... type Creature { creatureName : String! creatureAge: Int! }-
all empty constructors in union will be summed in type
<tyConName>Enum(e.gCharacterEnum), this enum will be wrapped inCharacterEnumObjectand this type will be added to unionCharacter. as in example above -
there is only types left with form
TypeName Type1 2Type ..(e.gSomeDeity Deity,CharacterInt Int,SomeMutli Int Text),morpheus will generate objet type from it:
type TypeName { _0: Type1! _1: Type2! ... }
-
Removed
- removed kind: INPUT_UNION
Fixed
- on filed resolver was displayed. unexhausted case exception of graphql error
- support of signed numbers (e.g
-4) - support of round floats (e.g
1.000) - validation checks undefined fields on inputObject
- variables are supported inside input values
[0.7.1] - 26.11.2019
- max bound icludes: support-megaparsec-8.0
[0.7.0] - 24.11.2019
Removed
toMorpheusHaskellAPifromData.Morpheus.Documentfunctionality will be migrated inmorpheus-graphql-cli
Changed
-
liftMtoMonadTransinstance methodlift -
liftEitherMtoliftEither -
Resolver operation m event value->Resolver operation event m value, monad trans needs that last 2 type arguments are monad and value that why it was necessary -
exposed
Data.Morpheus.Types.Internal.AST -
Mutation Resolver was changed from
resolver :: () -> ResolveM EVENT IO Address
resolver = MutResolver {
mutEvents = [someEventForSubscription],
mutResolver = lift setDBAddress
}
-- Mutation Wit Event Triggering : sends events to subscription
resolver :: () -> ResolveM EVENT IO Address
resolver = MutResolver \$ do
value <- lift setDBAddress
pure ([someEventForSubscription], value)
-- or
-- Mutation Without Event Triggering
resolver :: () -> ResolveM EVENT IO Address
resolver _args = lift setDBAddress
Added
-
added
parseDSLtoData.Morpheus.Document -
GraphQL SDL support fully supports descriptions: onTypes, fields , args ... with (enums, inputObjects , union, object) for example :
""" Description for Type Address """ type Address { """ Description for Field city """ city: String! street( """ Description argument id """ id: ID! ): Int! }GraphQL SDL
type User { name: String! @deprecated(reason: "some reason") }will displayed in introspection
introspection.json
{ "data": { "__type": { "fields": [ { "name": "city", "isDeprecated": true, "deprecationReason": "test deprecation field with reason" } ] } } } -
basic support of directive
@deprecatedonenumValueand objectfield, only on introspection -
GraphQL Client deprecation warnings
on type
type Human { humanName: String! lifetime: Lifetime! @deprecated(reason: "some reason") profession: Profession }compiler output:
warning: Morpheus Client Warning: { "message":"the field \"Human.lifetime\" is deprecated. some reason", "locations":[{"line":24,"column":15}] } -
new helper resolver types aliases:
- ResolveQ : for Query
- ResolveM : for Mutation
- ResolveS : for Subscription
ResolveM EVENT IO Addressis same asMutRes EVENT IO (Address (MutRes EVENT IO))is helpfull wenn you want to resolve GraphQL object
Fixed
- added missing Monad instance for Mutation resolver
defineByIntrospectionFiledoes not breaks if schema contains interfaces- Morpheus Client supports
SubscriptionandMutationoperations
[0.6.2] - 2.11.2019
Added
- support of ghc 8.8.1
[0.6.0] - 1.11.2019
Removed
-
removed
morpheuscli for code generating, if you need cli you should use morpheus-graphql-cli -
example
APIexecutable is removed from Production build
Added
-
helper functions:
liftEitherM,liftMliftM :: m a -> Resolver o m e a liftEitherM :: m (Either String a) -> Resolver o m e a
[0.5.0] - 31.10.2019
Added
- dummy support of
directives, only parsing not actual implementation
Fixed
-
can be parsed
implementswith multiple interfaces separated by& -
can be parsed default value on
inputobject -
Parser supports anonymous Operation:
query,mutation,subscriptionfor example:mutation { name } -
Morpheus client does not breaks on
Booleantype, converts every GraphQL typeBooleanto haskellBooland GQLStringtoText
Changed
-
Reduced
GQLRootResolversignature :GQLRootResolver IO () () Query () ()->GQLRootResolver IO () Query () ()GQLRootResolver IO Channel Content Query Mutation Subscription->GQLRootResolver IO APIEvent Query Mutation Subscriptionwhere
APIEvent = Event Channel Content -
GQLRootResolverautomatically assigns corresponding monad to GraphQL Types.you can write just:
GQLRootResolver IO APIEvent Query Mutation Subscriptioninstead of:
GQLRootResolver IO APIEvent (Query (Resolver IO)) (Mutation (MutResolver IO ApiEvent) (Subscription (SubResolver IO ApiEvent))where operations are generated by
importGQLDocumentor have form :data Query m = Query { field1 :: Args -> m Field1, .... } -
()was replaced withUndefinedinGQLRootResolverfor empty operationsmutation,subscriptionrootResolver :: GQLRootResolver IO () Query Undefined Undefined -
Root Operations
Query,Mutation,Subscriptionare passed to root resolvers without boxing inside a monad. -
there are only 3 kind of resolvers
MutResolver,SubResolver,QueryResolverdefined by GADTResolver
[0.4.0] - 09.10.2019
Changed
-
support of Default Value:
- on query: Parsing Validating and resolving
- on Document: only Parsing
-
'lens' is removed from Library, client field collision can be handled with GraphQL
alias:{ user { name friend { friendName: name } } }
Fixed:
-
Data.Morpheus.Document.toGraphQLDocumentgenerates only my user defined types. #259 -
Morpheus Client Namespaces Input Type Fields, they don't collide anymore: example: schema:
input Person { name: String! }query:
query GetUser (parent: Person!) { .... }wil generate:
data GetUserArgs = GetUserArgs { getUserArgsParent: Person } deriving ... data Person = Person { personName: Person } deriving ... -
Morpheus Client Generated Output Object And Union Types don't collide:
type Person { name: String! parent: Person! friend: Person! }And we select
{ user { name friend { name } parent { name } bestFriend: friend { name parent { name } } } }client will Generate:
UserPersonfrom{userUserFriendPerson: from{user{freindUserParentPerson: from{user{parentUserBestFriendPerson: from{user{bestFrendUserBestFriendParentPerson: from{user{bestFrend{parent
-
GraphQL Client Defines enums and Input Types only once per query and they don't collide
[0.3.1] - 05.10.2019
Changed
- removed dependencies: attoparsec , utf8-string
- updated aeson lower bound up to: 1.4.4.0
[0.3.0] - 04.10.2019
Added
-
user can import GraphQL Document and generate types with it.
importGQLDocument "API.gql"this will generate types defined in
API.gql
Fixed
-
Stringdefined in GQLDcoument will be converted toTextby template haskell -
importGQLDocumentandgqlDocumentsupports Mutation, Subscription and Resolvers with custom Monadfor example. if we have:
type Deity { name: String! power: Power! }where
Poweris another object defined by gql schema. template haskell will represent this type as:data Deity m = Deity { name :: () -> m Text, power :: () -> m (Power m) }where
mis resolver Monad. -
importGQLDocumentWithNamespacegenerates namespaced haskell records. so that you have no more problem with name collision. from this gql type:type Deity { name: (id:Int)String! power: Power! }will be generated.
data Deity m = Deity { deityName :: DeityNameArgs -> m Text, deityPower :: () -> m (Power m) } data DeityNameArgs = DeityNameArgs { deityNameArgsId :: Int }
Changed
-
GQLTypeis mandatory for every GQL Type (including Query, Mutation and Subscription) -
subscription Resolver changed
from:
Subscription {newDeity = \args -> Event {channels = [ChannelA], content = newDeityResolver } }to:
Subscription {newDeity = \args -> SubResolver {subChannels = [ChannelA], subResolver = newDeityResolver } }
[0.2.2] - 30.08.2019
Fixed
-
Parser Supports GraphQL multiline comments
-
Morpheus GraphQL Client: Support GraphQL Alias
-
Support of GraphQL Interfaces on GraphQL Document:
# simple.gql interface Node { nodeId: ID! } type SimpleType implements Node { nodeId: ID! name: String! }morpheus compiler will read interfaces and validate implements. template haskell will generate haskell types only for types not for interfaces.
haskell type from
simple.gql:data SimpleType = SimpleType { nodeId :: ID! name :: Text! } deriving (Generic)at the time compiler does not validates field Arguments by interface
[0.2.1] - 23.08.2019
- assets are added to cabal source files
[0.2.0] - 23.08.2019
Added
-
Parser Supports GraphQL comments
-
Enhanced Subscription: mutation can trigger subscription with arguments
-
Experimental Support of Input Unions
-
GraphQL schema generating with:
Data.Morpheus.Document.toGraphQLDocument -
Generating dummy Morpheus Api from
schema.gql:morpheus build schema/mythology.gql src/MythologyApi.hs -
convertToJSONName&convertToHaskellNamehas been extended to support all Haskell 2010 reserved identities. details -
GraphQL Clientwith Template haskell QuasiQuotes (Experimental, Not fully Implemented)defineQuery [gql| query GetHero ($byRealm: Realm) { deity (realm:$byRealm) { power fullName } } |]will Generate:
- response type
GetHero,DeitywithLensInstances - input types:
GetHeroArgs,Realm - instance for
FetchtypeClass
so that
fetchHero :: Args GetHero -> m (Either String GetHero) fetchHero = fetch jsonRes args where args = GetHeroArgs {byRealm = Just Realm {owner = "Zeus", surface = Just 10}} jsonRes :: ByteString -> m ByteString jsonRes = <fetch query from server>resolves well typed response
GetHero. - response type
-
Ability to define
GQLSchemawith GraphQL syntax , so that with this schema[gqlDocument| type Query { deity (uid: Text! ) : Deity! } type Deity { name : Text! power : Text } |] rootResolver :: GQLRootResolver IO () () Query () () rootResolver = GQLRootResolver {queryResolver = return Query {deity}, mutationResolver = pure (), subscriptionResolver = pure ()} where deity DeityArgs {uid} = pure Deity {name, power} where name _ = pure "Morpheus" power _ = pure (Just "Shapeshifting")Template Haskell Generates types:
Query,Deity,DeityArgs, that can be used byrootResolvergenerated types are not compatible with
Mutation,Subscription, they can be used only inQuery, but this issue will be fixed in next release
Fixed:
- Parser supports enums inside input Object
- fulfilled fragment Validation (added: unusedFragment,nameConflict)
- correct decoding of Enums with more than 3 constructor #201
Changed
-
WebSocket subProtocol changed from
graphql-subscriptionstographql-ws -
type familiy
KINDis moved into typeClassesGQLType, so you should replacetype instance KIND Deity = OBJECT instance GQLType Deity where description = const "Custom Description for Client Defined User Type" data Deity = Deity { fullName :: Text } deriving (Generic)with
instance GQLType Deity where type KIND Deity = OBJECT description = const "Custom Description for Client Defined User Type" data Deity = Deity { fullName :: Text } deriving (Generic) -
Duplicated variable names in Http requests are validated using
Aeson'sjsonNoDupfunction. So the following request will result in a parsing error{"query":"...", "variables":{"email":"foo@mail.net", "email":"bar@mail.net",...}}
[0.1.1] - 1.07.2019
Fixed:
- () as Subscription or Mutation does not defines Operator without fields
[0.1.0] - 30.06.2019
thanks for contributing to: @krisajenkins, @hovind, @vmchale, @msvbg
Added
-
support for Union Types:
type instance KIND <type> = UNION -
support of haskell Types:
Map,Set, and Pair(a,b) -
GraphQL Resolver supports custom Monad
-
add
Interpreterclass with instances:ByteString -> m ByteStringand LazyByteString, wheremis resolver monadText -> m Textand LazyText, wheremis resolver monadGQLRequest -> m GQLResponse, When you using it inside another Component that have ManualToJSONderiving, you have to ensure thatGQLResponsewill be encoded withtoEncoding, and not withtoJSON.
-
Schema Validation:
- Name Collision
-
support of Parsing input values:
Objects,Arrays -
support scalar type:
ID -
scalar Types are validated by
GQLScalarinstance functionparseValue -
TypeFamily
KINDwith:SCALAROBJECT,ENUMINPUT_OBJECTUNION
-
inline Fragments
-
GraphQL Aliases
-
Subscriptions:
GQLSubscriptiona -> EffectM boperation: is resolver that contains side effect inEffectM. is used for Mutation and Subscribe communicationgqlEffectResolver ["CHANNEL_ID"]: packs as effect Resolver. if mutation and subscription resolver have same channel then every call of mutation will trigger subscription resolverGQLState: shared state betweenhttpandwebsocketservergqlSocketApp:convertsinterpretertowebsocketapplicationgraphql-subscriptions:Apollo GraphQLsubProtocol
-
language:
- Query supports :
__type(name:"type") - On every Object can be selected :
__typename
- Query supports :
Changed
GQLRootResolver,GQLType(..),GQLScalar(..)are moved inData.Morpheus.TypesGQLRoot { query, mutation, subscription }toGQLRootResolver {queryResolver, mutationResolver, subscriptionResolver}interpreter: can be used inhttpandwebsocketserverGQLKindrenamed asGQLType- types can be derived just with
(Generic,GQLType) - haskell record field
type'will generate GQL Object fieldtype - public API (all other modules are hidden):
- Data.Morpheus
- Data.Morpheus.Kind
- Data.Morpheus.Types
- Data.Morpheus.Execution.Subscription
Fixed:
- parser can read fields with digits like: a1 , _1
- you can use Wrapped type and Wrapped Primitive Types issue #136:
- wrapped TypesNames will be separated with "_" : typeName(Either A B) -> "Either_A_B"
- introspection:
- argument supports
Non-NullandList - every field has correct kind
- argument supports
Removed
GQLArgs: you can derive arguments just withGenericwithoutGQLArgsGQLObject: replaced with instancetype instance KIND <Type> = OBJECTGQLEnum: replaced with instancetype instance KIND <Type> = ENUMGQLInput: replaced with instancetype instance KIND <Type> = INPUT_OBJECTTypeable: with new deriving it is not required anymoreWrapper: with TypeFamilies there is no need forWrappera ::-> bis Replaced bya -> ResM bwhereResMis alias forResolver IO aGQLMutation,GQLQuery: with new deriving it is not required anymoreResolverconstructor replaced by functions:gqlResolver: packsm Either String atoResolver m agqlEffectResolver: resolver constructor for effectedResolverliftEffectResolver: lifts normal resolver to Effect Resolver.