graphql-engine-1.0.0: GraphQL API over Postgres
Safe HaskellNone
LanguageHaskell2010

Hasura.GraphQL.Analyse

Description

Tools to analyze the structure of a GraphQL request.

Synopsis

Documentation

data Structure Source #

Overall structure of a given query. We extract the tree of fields in the output, and the graph of input variables.

Constructors

Structure 

Fields

data FieldInfo Source #

Information about the type of an output field; whether the base type is an object or a scalar, we store the correspoding GType to keep track of the modifiers applied to it (list or non-nullability).

data ScalarInfo Source #

Constructors

ScalarInfo 

Fields

data EnumInfo Source #

Constructors

EnumInfo 

Fields

data ObjectInfo Source #

Constructors

ObjectInfo 

Fields

data VariableInfo Source #

Information about a single variable of the query.

Constructors

VariableInfo 

Fields

data InputFieldInfo Source #

Information about the type of an input field; whether the base type is an object or a scalar, we store the correspoding GType to keep track of the modifiers applied to it (list or non-nullability).

data InputObjectInfo Source #

Constructors

InputObjectInfo 

Fields

diagnoseGraphQLQuery :: SchemaIntrospection -> TypedOperationDefinition NoFragments Name -> Maybe [Text] Source #

Given the schema's definition, and a query, validate that the query is consistent. We do this by running the analysis, but discarding the result: we do not care about the structure, only about the validity of the query.

Returns Nothing if the query is valid, or a list of messages otherwise.

analyzeGraphQLQuery :: SchemaIntrospection -> TypedOperationDefinition NoFragments Name -> (Maybe Structure, [Text]) Source #

Given the schema's definition, and a query, run the analysis.

We process all possible fields, and return a partially filled structure if necessary. Given the following query:

query {
  foo {
    bar
  }
  does_not_exist {
    ghsdflgh
  }
}

We would return a structure containing:

foo: {
  bar: {
  }
}

AND an error about "does_not_exist" not existing.

In some cases, however, we might not be able to produce a structure at all, in which case we return Nothing. This either indicates that something was fundamentally wrong with the structure of the query (such as not finding an object at the top level), or that a recoverable error was not caught properly (see withCatchAndRecord).

analyzeObjectSelectionSet :: ObjectTypeDefinition InputValueDefinition -> SelectionSet NoFragments Name -> Analysis (HashMap Name FieldInfo) Source #

Analyze the fields of an object selection set against its definition, and emit the corresponding Selection. We ignore the fields that fail, and we continue accumulating the others.

analyzeField :: GType -> TypeDefinition [Name] InputValueDefinition -> Field NoFragments Name -> Analysis (Maybe FieldInfo) Source #

Analyze a given field, and attempt to build a corresponding FieldInfo.

analyzeVariables :: [VariableDefinition] -> Analysis (HashMap Name VariableInfo) Source #

Analyzes the variables in the given query. This builds the graph of input types associated with the variable. This process is, like any GraphQL schema operation, inherently self-recursive, and we use CircularT (a lesser SchemaT) to tie the knot.

analyzeInputField :: Name -> TypeDefinition [Name] InputValueDefinition -> CircularT Name InputFieldInfo Analysis InputFieldInfo Source #

Builds an InputFieldInfo for a given typename.

This function is "memoized" using withCircular to prevent processing the same type more than once in case the input types are self-recursive.

newtype Analysis a Source #

The monad in which we run our analysis.

Has three capabilities: - reader carries the current path, and the full schema for lookups - writer logs all errors we have caught - except allows for short-circuiting errors

Constructors

Analysis (ExceptT AnalysisError (ReaderT (Path, SchemaIntrospection) (Writer [AnalysisError])) a) 

runAnalysis :: SchemaIntrospection -> Analysis a -> (Maybe a, [Text]) Source #

lookupType :: MonadReader (Path, SchemaIntrospection) m => Name -> m (Maybe (TypeDefinition [Name] InputValueDefinition)) Source #

Look up a type in the schema.

withField :: MonadReader (Path, SchemaIntrospection) m => Name -> m a -> m a Source #

Add the current field to the error path.

throwDiagnosis :: (MonadReader (Path, SchemaIntrospection) m, MonadError AnalysisError m) => Diagnosis -> m a Source #

Throws an AnalysisError by combining the given diagnosis with the current path. This interrupts the computation in the given branch, and must be caught for the analysis to resume.

withCatchAndRecord :: (MonadReader (Path, SchemaIntrospection) m, MonadWriter [AnalysisError] m, MonadError AnalysisError m) => m a -> m (Maybe a) Source #

Runs the given computation. if it fails, cacthes the error, records it in the monad, and return Nothing. This allows for a clean recovery.

type Path = Seq Text Source #

typenameField :: FieldDefinition InputValueDefinition Source #

schemaField :: FieldDefinition InputValueDefinition Source #

typeField :: FieldDefinition InputValueDefinition Source #

mkReservedField :: Name -> Name -> FieldDefinition InputValueDefinition Source #