morpheus-graphql icon indicating copy to clipboard operation
morpheus-graphql copied to clipboard

feature: Directives api for SDL

Open nalchevanidze opened this issue 6 years ago • 4 comments

directives api for SDL

GraphQL implementations that support the type system definition language must provide the @deprecated directive if representing deprecated portions of the schema.

https://graphql.github.io/graphql-spec/June2018/#sec-Type-System.Directives

TypeSystemDirectiveLocation: one of

  • SCHEMA
  • SCALAR
  • OBJECT
  • FIELD_DEFINITION
  • ARGUMENT_DEFINITION
  • INTERFACE
  • UNION
  • ENUM
  • ENUM_VALUE
  • INPUT_OBJECT
  • INPUT_FIELD_DEFINITION

TODO

  • [ ] SDL parser supports directive definition
  • [ ] morpheus applies this directives to morpheus schema
  • [ ] user has api to define directives with plain Haskell, without any TH

apollo api

https://www.apollographql.com/docs/graphql-tools/schema-directives/

To implement a schema directive using SchemaDirectiveVisitor, simply create a subclass of SchemaDirectiveVisitor that overrides one or more of the following visitor methods:

visitSchema(schema: GraphQLSchema)
visitScalar(scalar: GraphQLScalarType)
visitObject(object: GraphQLObjectType)
visitFieldDefinition(field: GraphQLField<any, any>)
visitArgumentDefinition(argument: GraphQLArgument)
visitInterface(iface: GraphQLInterfaceType)
visitUnion(union: GraphQLUnionType)
visitEnum(type: GraphQLEnumType)
visitEnumValue(value: GraphQLEnumValue)
visitInputObject(object: GraphQLInputObjectType)
visitInputFieldDefinition(field: GraphQLInputField)

probable morpheus api

type family ValueBy  ( loc :: TypeSystemDirectiveLocation) :: * 
type instance FIELD_DEFINITION = DataField
type ... 

class TypeSystemDirective (location:: TypeSystemDirectiveLocation ) directive where
        applyDSL :: directive -> ValueBy location -> Validation (ValueBy location)

so user can define

data Deprecation = Deprecation  { reason :: Maybe Text }

instance  TypeSystemDirective (location:: TypeSystemDirectiveLocation ) MyDeprecation where
        applyDSL Deprecation { reason } field = field { fieldDeprecationReason  = reason }

nalchevanidze avatar Jan 07 '20 21:01 nalchevanidze

goal

https://www.apollographql.com/docs/graphql-tools/schema-directives/

const typeDefs = `
directive @rest(url: String) on FIELD_DEFINITION

type Query {
  people: [Person] @rest(url: "/api/v1/people")
}`;

class RestDirective extends SchemaDirectiveVisitor {
  public visitFieldDefinition(field) {
    const { url } = this.args;
    field.resolve = () => fetch(url);
  }
}

const schema = makeExecutableSchema({
  typeDefs,
  schemaDirectives: {
    rest: RestDirective
  }
});

nalchevanidze avatar May 28 '20 13:05 nalchevanidze

Explore supporting extension fields on AST.

data TypeDefinition (a :: TypeCategory) (s :: Stage) = TypeDefinition
  { ....
    typeExtensions :: Maybe JSON.Value
  }
  deriving (Show, Lift, Eq)


data FieldDefinition (cat :: TypeCategory) (s :: Stage) = FieldDefinition
  {  ....
   fieldExtensions ::  Maybe JSON.Value
  }
  deriving (Show, Lift, Eq)

nalchevanidze avatar Dec 31 '20 19:12 nalchevanidze

https://www.graphql-tools.com/docs/schema-directives/

nalchevanidze avatar Jan 02 '21 22:01 nalchevanidze

we can define type class DIRECTIVE_LOCATION to allow specific Locations to Directive resolvers

type family DIRECTIVE_LOCATION a (l :: DIrectiveLocation) :: Bool

for example

type instance DIRECTIVE_LOCATION User 'FIELD = 'True
type instance DIRECTIVE_LOCATION User 'TYPE = 'False

that way we can restrict writing resolver function for TYPE on User

type family DIrRes a  (l :: Bool)  where
   DirRes a 'True = a -> GQLResult a
   DirRes a 'False = ()

finally

class GQLDirective a where
    mapType :: a -> DirRes TypeDefinition (DIRECTIVE_LOCATION 'TYPE)
    mapField :: a -> DirRes FieldDefinition (DIRECTIVE_LOCATION 'FIELD)

nalchevanidze avatar Aug 22 '21 18:08 nalchevanidze