diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -9,10 +9,9 @@
 ## Build GraphQL api with Core
 
 ```hs
-getSchema :: Monad m => ResponseStream e m Schema
-getSchema =
-  fromList
-    [dsl|
+schema :: Schema VALID
+schema =
+  [dsl|
   type Query {
     deity(name: String): Deity!
   }
@@ -45,7 +44,5 @@
       ]
 
 api :: GQLRequest -> ResponseStream e Identity (Value VALID)
-api request = do
-  schema <- getSchema
-  runApi schema resolver request
+api = runApi schema resolver
 ```
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,6 +1,85 @@
 # Changelog
 
-## 0.13.0 - Unreleased Changes
+## 0.14.0 - 15.08.2020
+
+### new features
+
+- query validation supports interfaces
+- exposed: `Data.Morpheus.Types.SelectionTree`
+- configurable api: `Data.Morpheus.Core` exports
+
+  - `Config`
+  - `defaultConfig`
+  - `debugConfig`
+
+- for better debuging, internal errors messages will display resolving state:
+  - `current TypeName`
+  - `current Selection`
+  - `OperationDefinition`
+  - `SchemaDefinition`
+- rendering graphql "AST". e.g `render ( slection :: Selection VALID)` will render
+
+```graphql
+{
+  user(arg1: 1) {
+    name
+  }
+}
+```
+
+- quasiqouter `[dsl| <type definitions> |]` generates `Schema VALID`.
+- parser supports custom directive definition. e.g
+
+```graphql
+directive @MyDirective on FIELD_DEFINITION | OBJECT
+```
+
+- directive Validation for Document (TypeSystem).
+- supports of block string values. e.g:
+
+  ```graphql
+  query {
+    createDeity(
+      name: """
+      powerqwe
+      bla \n sd
+      blu \\ dete
+      """
+    ) {
+      name
+    }
+  }
+  ```
+
+- support of `schema`. issue #412
+
+  ```graphql
+  schema {
+    query: MyQuery
+  }
+  ```
+
+### Breaking Changes
+
+- `Context' renamed to`ResolverContext'
+- removed : `EventCon` from `Data.Morpheus.Core`
+- internal refactoring: changed AST.
+  Schema AST Types now need parameter `stage = RAW | CONST | VALID`.
+  - `Schema VALID`
+  - `TypeDefinition VALID`
+  - `FieldDefinition IN VALID`
+  - ...
+- runApi requires argument config
+  ```hs
+    runApi ::
+      Schema s ->
+      RootResModel event m ->
+      Config ->
+      GQLRequest ->
+      ResponseStream event m (Value VALID)
+  ```
+
+## 0.13.0 - 22.06.2020
 
 ### new features
 
diff --git a/morpheus-graphql-core.cabal b/morpheus-graphql-core.cabal
--- a/morpheus-graphql-core.cabal
+++ b/morpheus-graphql-core.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: b13e1668b9269ab28dfdd66f04b342a5bdbec82e6ba59c98c0467604df7270a6
+-- hash: b767cd6b24899f096032a5231c2edb2e7fb1e5d3c29e1a8b775ecbb1ca730ebd
 
 name:           morpheus-graphql-core
-version:        0.13.0
+version:        0.14.0
 synopsis:       Morpheus GraphQL Core
 description:    Build GraphQL APIs with your favourite functional language!
 category:       web, graphql
@@ -23,8 +23,28 @@
     changelog.md
     README.md
 data-files:
-    test/api/interface/query.gql
-    test/api/simple/query.gql
+    test/api/deity/interface/query.gql
+    test/api/deity/schema.gql
+    test/api/deity/simple/query.gql
+    test/api/validation/fragment/fail-unknown-field-on-interface/query.gql
+    test/api/validation/fragment/on-interface-fail-without-casting/query.gql
+    test/api/validation/fragment/on-interface-inline/query.gql
+    test/api/validation/fragment/on-interface-type-casting-inline/query.gql
+    test/api/validation/fragment/on-interface-type-casting/query.gql
+    test/api/validation/fragment/on-interface/query.gql
+    test/api/validation/fragment/on-type/query.gql
+    test/api/validation/fragment/on-union-type/query.gql
+    test/api/validation/fragment/schema.gql
+    test/schema/parsing/directive/ok/simple/schema.gql
+    test/schema/parsing/directive/ok/sophisticated/schema.gql
+    test/schema/parsing/schema-definition/fail/dupplicate-field/query-mutation-subscription/schema.gql
+    test/schema/parsing/schema-definition/fail/dupplicate-field/query/schema.gql
+    test/schema/parsing/schema-definition/fail/dupplicate-schema-definition/schema.gql
+    test/schema/parsing/schema-definition/fail/unknown-fields/bla/schema.gql
+    test/schema/parsing/schema-definition/fail/unknown-fields/uppercase/schema.gql
+    test/schema/parsing/schema-definition/ok/query-mutation-subscription/schema.gql
+    test/schema/parsing/schema-definition/ok/query-mutation/schema.gql
+    test/schema/parsing/schema-definition/ok/query/schema.gql
     test/schema/validation/default-value/argument/compound-ok/schema.gql
     test/schema/validation/default-value/argument/missing-field/schema.gql
     test/schema/validation/default-value/argument/unexpected-value/schema.gql
@@ -33,12 +53,47 @@
     test/schema/validation/default-value/field/missing-field/schema.gql
     test/schema/validation/default-value/field/unexpected-value/schema.gql
     test/schema/validation/default-value/field/unknown-field/schema.gql
+    test/schema/validation/directive/fail/at-invalid-place/schema.gql
+    test/schema/validation/directive/fail/missing-argument/schema.gql
+    test/schema/validation/directive/fail/sopthisticated/schema.gql
+    test/schema/validation/directive/fail/unexpected-value/schema.gql
+    test/schema/validation/directive/fail/unknown-directive/schema.gql
+    test/schema/validation/directive/ok/deprecated/custom-directive/schema.gql
+    test/schema/validation/directive/ok/deprecated/schema.gql
     test/schema/validation/interface/field-args/fail/schema.gql
     test/schema/validation/interface/field-args/ok/schema.gql
     test/schema/validation/interface/field-type/fail/schema.gql
     test/schema/validation/interface/field-type/ok/schema.gql
-    test/api/interface/response.json
-    test/api/simple/response.json
+    test/schema/validation/schema-definition/fail/non-object-kind/from-schema/schema.gql
+    test/schema/validation/schema-definition/fail/non-object-kind/without-schema/schema.gql
+    "test/schema/validation/schema-definition/fail/required query/empty/schema.gql"
+    "test/schema/validation/schema-definition/fail/required query/no-query/schema.gql"
+    "test/schema/validation/schema-definition/fail/required query/no-schema-no-query/schema.gql"
+    "test/schema/validation/schema-definition/fail/required query/schema-with-query/schema.gql"
+    test/schema/validation/schema-definition/fail/unknown-type/unknown/schema.gql
+    test/schema/validation/schema-definition/ok/full/schema.gql
+    test/api/deity/interface/response.json
+    test/api/deity/resolvers.json
+    test/api/deity/simple/response.json
+    test/api/validation/fragment/fail-unknown-field-on-interface/response.json
+    test/api/validation/fragment/on-interface-fail-without-casting/response.json
+    test/api/validation/fragment/on-interface-inline/response.json
+    test/api/validation/fragment/on-interface-type-casting-inline/response.json
+    test/api/validation/fragment/on-interface-type-casting/response.json
+    test/api/validation/fragment/on-interface/response.json
+    test/api/validation/fragment/on-type/response.json
+    test/api/validation/fragment/on-union-type/response.json
+    test/api/validation/fragment/resolvers.json
+    test/schema/parsing/directive/ok/simple/response.json
+    test/schema/parsing/directive/ok/sophisticated/response.json
+    test/schema/parsing/schema-definition/fail/dupplicate-field/query-mutation-subscription/response.json
+    test/schema/parsing/schema-definition/fail/dupplicate-field/query/response.json
+    test/schema/parsing/schema-definition/fail/dupplicate-schema-definition/response.json
+    test/schema/parsing/schema-definition/fail/unknown-fields/bla/response.json
+    test/schema/parsing/schema-definition/fail/unknown-fields/uppercase/response.json
+    test/schema/parsing/schema-definition/ok/query-mutation-subscription/response.json
+    test/schema/parsing/schema-definition/ok/query-mutation/response.json
+    test/schema/parsing/schema-definition/ok/query/response.json
     test/schema/validation/default-value/argument/compound-ok/response.json
     test/schema/validation/default-value/argument/missing-field/response.json
     test/schema/validation/default-value/argument/unexpected-value/response.json
@@ -47,10 +102,25 @@
     test/schema/validation/default-value/field/missing-field/response.json
     test/schema/validation/default-value/field/unexpected-value/response.json
     test/schema/validation/default-value/field/unknown-field/response.json
+    test/schema/validation/directive/fail/at-invalid-place/response.json
+    test/schema/validation/directive/fail/missing-argument/response.json
+    test/schema/validation/directive/fail/sopthisticated/response.json
+    test/schema/validation/directive/fail/unexpected-value/response.json
+    test/schema/validation/directive/fail/unknown-directive/response.json
+    test/schema/validation/directive/ok/deprecated/custom-directive/response.json
+    test/schema/validation/directive/ok/deprecated/response.json
     test/schema/validation/interface/field-args/fail/response.json
     test/schema/validation/interface/field-args/ok/response.json
     test/schema/validation/interface/field-type/fail/response.json
     test/schema/validation/interface/field-type/ok/response.json
+    test/schema/validation/schema-definition/fail/non-object-kind/from-schema/response.json
+    test/schema/validation/schema-definition/fail/non-object-kind/without-schema/response.json
+    "test/schema/validation/schema-definition/fail/required query/empty/response.json"
+    "test/schema/validation/schema-definition/fail/required query/no-query/response.json"
+    "test/schema/validation/schema-definition/fail/required query/no-schema-no-query/response.json"
+    "test/schema/validation/schema-definition/fail/required query/schema-with-query/response.json"
+    test/schema/validation/schema-definition/fail/unknown-type/unknown/response.json
+    test/schema/validation/schema-definition/ok/full/response.json
 
 source-repository head
   type: git
@@ -68,11 +138,11 @@
       Data.Morpheus.Types.Internal.Resolving
       Data.Morpheus.Types.GQLScalar
       Data.Morpheus.Types.ID
+      Data.Morpheus.Types.SelectionTree
   other-modules:
       Data.Morpheus.Error.Document.Interface
       Data.Morpheus.Error.Fragment
       Data.Morpheus.Error.Input
-      Data.Morpheus.Error.Internal
       Data.Morpheus.Error.NameCollision
       Data.Morpheus.Error.Operation
       Data.Morpheus.Error.Schema
@@ -80,6 +150,7 @@
       Data.Morpheus.Error.Utils
       Data.Morpheus.Error.Variable
       Data.Morpheus.Error.Warning
+      Data.Morpheus.Internal.Graph
       Data.Morpheus.Parser
       Data.Morpheus.Parsing.Document.TypeSystem
       Data.Morpheus.Parsing.Internal.Arguments
@@ -87,38 +158,42 @@
       Data.Morpheus.Parsing.Internal.Pattern
       Data.Morpheus.Parsing.Internal.Terms
       Data.Morpheus.Parsing.Internal.Value
-      Data.Morpheus.Parsing.JSONSchema.Parse
-      Data.Morpheus.Parsing.JSONSchema.Types
       Data.Morpheus.Parsing.Request.Operation
       Data.Morpheus.Parsing.Request.Parser
       Data.Morpheus.Parsing.Request.Selection
       Data.Morpheus.Rendering.RenderGQL
       Data.Morpheus.Rendering.RenderIntrospection
-      Data.Morpheus.Schema.Directives
       Data.Morpheus.Schema.DSL
       Data.Morpheus.Schema.Schema
       Data.Morpheus.Schema.SchemaAPI
-      Data.Morpheus.Schema.TypeKind
       Data.Morpheus.Types.Internal.AST.Base
       Data.Morpheus.Types.Internal.AST.DirectiveLocation
+      Data.Morpheus.Types.Internal.AST.Fields
       Data.Morpheus.Types.Internal.AST.MergeSet
-      Data.Morpheus.Types.Internal.AST.OrderedMap
+      Data.Morpheus.Types.Internal.AST.OrdMap
+      Data.Morpheus.Types.Internal.AST.SafeHashMap
       Data.Morpheus.Types.Internal.AST.Selection
+      Data.Morpheus.Types.Internal.AST.Stage
       Data.Morpheus.Types.Internal.AST.TH
+      Data.Morpheus.Types.Internal.AST.TypeCategory
       Data.Morpheus.Types.Internal.AST.TypeSystem
       Data.Morpheus.Types.Internal.AST.Value
+      Data.Morpheus.Types.Internal.Config
       Data.Morpheus.Types.Internal.Resolving.Core
+      Data.Morpheus.Types.Internal.Resolving.Event
       Data.Morpheus.Types.Internal.Resolving.Resolver
+      Data.Morpheus.Types.Internal.Resolving.ResolverState
       Data.Morpheus.Types.Internal.Validation
       Data.Morpheus.Types.Internal.Validation.Error
+      Data.Morpheus.Types.Internal.Validation.Internal
       Data.Morpheus.Types.Internal.Validation.SchemaValidator
       Data.Morpheus.Types.Internal.Validation.Validator
-      Data.Morpheus.Types.SelectionTree
       Data.Morpheus.Validation.Document.Validation
+      Data.Morpheus.Validation.Internal.Arguments
       Data.Morpheus.Validation.Internal.Directive
       Data.Morpheus.Validation.Internal.Value
-      Data.Morpheus.Validation.Query.Arguments
       Data.Morpheus.Validation.Query.Fragment
+      Data.Morpheus.Validation.Query.FragmentPreconditions
       Data.Morpheus.Validation.Query.Selection
       Data.Morpheus.Validation.Query.UnionSelection
       Data.Morpheus.Validation.Query.Validation
@@ -148,7 +223,8 @@
   main-is: Spec.hs
   other-modules:
       Lib
-      Schema
+      Utils.Api
+      Utils.Schema
       Paths_morpheus_graphql_core
   hs-source-dirs:
       test
diff --git a/src/Data/Morpheus/Core.hs b/src/Data/Morpheus/Core.hs
--- a/src/Data/Morpheus/Core.hs
+++ b/src/Data/Morpheus/Core.hs
@@ -9,11 +9,9 @@
 
 module Data.Morpheus.Core
   ( runApi,
-    EventCon,
     parseDSL,
     parseFullGQLDocument,
     parseGQLDocument,
-    decodeIntrospection,
     parseTypeSystemDefinition,
     parseTypeDefinitions,
     validateRequest,
@@ -22,6 +20,10 @@
     parseRequest,
     RenderGQL (..),
     SelectionTree (..),
+    Config (..),
+    VALIDATION_MODE (..),
+    defaultConfig,
+    debugConfig,
   )
 where
 
@@ -31,7 +33,8 @@
   ( ByteString,
   )
 import Data.Morpheus.Internal.Utils
-  ( empty,
+  ( (<:>),
+    empty,
   )
 import Data.Morpheus.Parser
   ( parseRequest,
@@ -39,13 +42,10 @@
     parseTypeDefinitions,
     parseTypeSystemDefinition,
   )
-import Data.Morpheus.Parsing.JSONSchema.Parse
-  ( decodeIntrospection,
-  )
 import Data.Morpheus.Rendering.RenderGQL
   ( RenderGQL (..),
   )
-import Data.Morpheus.Schema.Schema (withSystemTypes)
+import Data.Morpheus.Schema.Schema (internalSchema)
 import Data.Morpheus.Schema.SchemaAPI (withSystemFields)
 import Data.Morpheus.Types.IO
   ( GQLRequest (..),
@@ -58,10 +58,15 @@
     VALID,
     Value,
   )
+import Data.Morpheus.Types.Internal.Config
+  ( Config (..),
+    VALIDATION_MODE (..),
+    debugConfig,
+    defaultConfig,
+  )
 import Data.Morpheus.Types.Internal.Resolving
-  ( Context (..),
-    Eventless,
-    GQLChannel (..),
+  ( Eventless,
+    ResolverContext (..),
     ResponseStream,
     ResultT (..),
     RootResModel,
@@ -70,7 +75,7 @@
     runRootResModel,
   )
 import Data.Morpheus.Types.SelectionTree (SelectionTree (..))
-import Data.Morpheus.Validation.Document.Validation (validateSchema)
+import Data.Morpheus.Validation.Document.Validation (ValidateSchema (..))
 import Data.Morpheus.Validation.Query.Validation
   ( validateRequest,
   )
@@ -78,50 +83,54 @@
   ( toStrict,
   )
 import Data.Text.Lazy.Encoding (decodeUtf8)
-import Data.Typeable (Typeable)
 
-type EventCon event =
-  (Eq (StreamChannel event), Typeable event, GQLChannel event)
-
 runApi ::
-  forall event m.
-  (Monad m) =>
-  Schema ->
+  forall event m s.
+  (Monad m, ValidateSchema s) =>
+  Schema s ->
   RootResModel event m ->
+  Config ->
   GQLRequest ->
   ResponseStream event m (Value VALID)
-runApi inputSchema resModel request = do
-  ctx <- validRequest
-  model <- withSystemFields (schema ctx) resModel
-  runRootResModel model ctx
-  where
-    validRequest ::
-      Monad m => ResponseStream event m Context
-    validRequest = cleanEvents $ ResultT $ pure $ do
-      validSchema <- validateSchema inputSchema
-      schema <- withSystemTypes validSchema
-      operation <- parseRequestWith schema request
-      pure $
-        Context
-          { schema,
-            operation,
-            currentTypeName = "Root",
-            currentSelection =
-              Selection
-                { selectionName = "Root",
-                  selectionArguments = empty,
-                  selectionPosition = operationPosition operation,
-                  selectionAlias = Nothing,
-                  selectionContent = SelectionSet (operationSelection operation),
-                  selectionDirectives = []
-                }
-          }
+runApi inputSchema resModel config request = do
+  validRequest <- validateReq inputSchema config request
+  resovers <- withSystemFields (schema validRequest) resModel
+  runRootResModel resovers validRequest
 
-parseDSL :: ByteString -> Either String Schema
+validateReq ::
+  ( Monad m,
+    ValidateSchema s
+  ) =>
+  Schema s ->
+  Config ->
+  GQLRequest ->
+  ResponseStream event m ResolverContext
+validateReq inputSchema config request = cleanEvents $ ResultT $ pure $ do
+  validSchema <- validateSchema True config inputSchema
+  schema <- internalSchema <:> validSchema
+  operation <- parseRequestWith config schema request
+  pure $
+    ResolverContext
+      { schema,
+        config,
+        operation,
+        currentTypeName = "Root",
+        currentSelection =
+          Selection
+            { selectionName = "Root",
+              selectionArguments = empty,
+              selectionPosition = operationPosition operation,
+              selectionAlias = Nothing,
+              selectionContent = SelectionSet (operationSelection operation),
+              selectionDirectives = []
+            }
+      }
+
+parseDSL :: ByteString -> Either String (Schema VALID)
 parseDSL = resultOr (Left . show) pure . parseGQLDocument
 
-parseGQLDocument :: ByteString -> Eventless Schema
+parseGQLDocument :: ByteString -> Eventless (Schema VALID)
 parseGQLDocument = parseTypeSystemDefinition . LT.toStrict . decodeUtf8
 
-parseFullGQLDocument :: ByteString -> Eventless Schema
-parseFullGQLDocument = parseGQLDocument >=> withSystemTypes
+parseFullGQLDocument :: ByteString -> Eventless (Schema VALID)
+parseFullGQLDocument = parseGQLDocument >=> (internalSchema <:>)
diff --git a/src/Data/Morpheus/Error.hs b/src/Data/Morpheus/Error.hs
--- a/src/Data/Morpheus/Error.hs
+++ b/src/Data/Morpheus/Error.hs
@@ -1,15 +1,12 @@
 module Data.Morpheus.Error
   ( errorMessage,
     globalErrorMessage,
-    internalError,
-    internalTypeMismatch,
     gqlWarnings,
     renderGQLErrors,
     deprecatedField,
   )
 where
 
-import Data.Morpheus.Error.Internal
 import Data.Morpheus.Error.Utils
 import Data.Morpheus.Error.Warning
   ( deprecatedField,
diff --git a/src/Data/Morpheus/Error/Document/Interface.hs b/src/Data/Morpheus/Error/Document/Interface.hs
--- a/src/Data/Morpheus/Error/Document/Interface.hs
+++ b/src/Data/Morpheus/Error/Document/Interface.hs
@@ -1,6 +1,7 @@
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Error.Document.Interface
   ( unknownInterface,
@@ -10,14 +11,13 @@
   )
 where
 
-import Data.Morpheus.Error.Utils (globalErrorMessage)
+import Data.Maybe (Maybe (..))
 import Data.Morpheus.Types.Internal.AST.Base
   ( FieldName (..),
-    GQLError (..),
-    GQLErrors,
     TypeName (..),
     TypeRef,
-    msg,
+    ValidationError,
+    msgValidation,
   )
 import Data.Morpheus.Types.Internal.Validation.SchemaValidator
   ( Field (..),
@@ -26,10 +26,8 @@
   )
 import Data.Semigroup ((<>))
 
-unknownInterface :: TypeName -> GQLErrors
-unknownInterface name = globalErrorMessage message
-  where
-    message = "Unknown Interface " <> msg name <> "."
+unknownInterface :: TypeName -> ValidationError
+unknownInterface name = "Unknown Interface " <> msgValidation name <> "."
 
 data ImplementsError
   = UnexpectedType
@@ -45,31 +43,25 @@
   }
 
 class PartialImplements ctx where
-  partialImplements :: ctx -> ImplementsError -> GQLErrors
+  partialImplements :: ctx -> ImplementsError -> ValidationError
 
 instance PartialImplements (Interface, FieldName) where
   partialImplements (Interface interfaceName typename, fieldname) errorType =
-    [ GQLError
-        { message = message,
-          locations = []
-        }
-    ]
+    "Interface field "
+      <> renderField interfaceName fieldname Nothing
+      <> detailedMessage errorType
     where
-      message =
-        "Interface field "
-          <> renderField interfaceName fieldname Nothing
-          <> detailedMessage errorType
       detailedMessage UnexpectedType {expectedType, foundType} =
         " expects type "
-          <> msg expectedType
+          <> msgValidation expectedType
           <> " but "
           <> renderField typename fieldname Nothing
           <> " is type "
-          <> msg foundType
+          <> msgValidation foundType
           <> "."
       detailedMessage Missing =
         " expected but "
-          <> msg typename
+          <> msgValidation typename
           <> " does not provide it."
 
 -- Interface field TestInterface.name expected but User does not provide it.
@@ -77,24 +69,17 @@
 
 instance PartialImplements (Interface, Field) where
   partialImplements (Interface interfaceName typename, Field fieldname argName) errorType =
-    [ GQLError
-        { message = message,
-          locations = []
-        }
-    ]
+    "Interface field argument "
+      <> renderField interfaceName fieldname (Just argName)
+      <> detailedMessage errorType
     where
-      --
-      message =
-        "Interface field argument "
-          <> renderField interfaceName fieldname (Just argName)
-          <> detailedMessage errorType
       detailedMessage UnexpectedType {expectedType, foundType} =
         " expects type"
-          <> msg expectedType
+          <> msgValidation expectedType
           <> " but "
           <> renderField typename fieldname (Just argName)
           <> " is type "
-          <> msg foundType
+          <> msgValidation foundType
           <> "."
       detailedMessage Missing =
         " expected but "
diff --git a/src/Data/Morpheus/Error/Fragment.hs b/src/Data/Morpheus/Error/Fragment.hs
--- a/src/Data/Morpheus/Error/Fragment.hs
+++ b/src/Data/Morpheus/Error/Fragment.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Error.Fragment
   ( cannotSpreadWithinItself,
@@ -7,18 +8,20 @@
 where
 
 -- MORPHEUS
-import Data.Morpheus.Error.Utils (errorMessage)
+
+import Data.Maybe (Maybe (..))
+import Data.Morpheus.Error.Utils (validationErrorMessage)
 import Data.Morpheus.Types.Internal.AST.Base
   ( FieldName,
-    GQLError (..),
-    GQLErrors,
     Position,
     Ref (..),
     TypeName,
+    ValidationError (..),
     msg,
     msgSepBy,
   )
 import Data.Semigroup ((<>))
+import Prelude (($), fmap, head)
 
 {-
   FRAGMENT:
@@ -32,21 +35,21 @@
     {...H} -> "Unknown fragment \"H\"."
 -}
 
-cannotSpreadWithinItself :: [Ref] -> GQLErrors
-cannotSpreadWithinItself fragments = [GQLError {message = text, locations = map refPosition fragments}]
+cannotSpreadWithinItself :: [Ref] -> ValidationError
+cannotSpreadWithinItself fragments = ValidationError text (fmap refPosition fragments)
   where
     text =
       "Cannot spread fragment "
         <> msg (refName $ head fragments)
         <> " within itself via "
-        <> msgSepBy ", " (map refName fragments)
+        <> msgSepBy ", " (fmap refName fragments)
         <> "."
 
 -- Fragment type mismatch -> "Fragment \"H\" cannot be spread here as objects of type \"Hobby\" can never be of type \"Experience\"."
-cannotBeSpreadOnType :: Maybe FieldName -> TypeName -> Position -> [TypeName] -> GQLErrors
+cannotBeSpreadOnType :: Maybe FieldName -> TypeName -> Position -> [TypeName] -> ValidationError
 cannotBeSpreadOnType key fragmentType position typeMembers =
-  errorMessage
-    position
+  validationErrorMessage
+    (Just position)
     text
   where
     text =
diff --git a/src/Data/Morpheus/Error/Input.hs b/src/Data/Morpheus/Error/Input.hs
--- a/src/Data/Morpheus/Error/Input.hs
+++ b/src/Data/Morpheus/Error/Input.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Error.Input
   ( typeViolation,
@@ -6,19 +7,19 @@
 where
 
 import Data.Morpheus.Types.Internal.AST
-  ( Message,
-    ResolvedValue,
-    TypeRef (..),
-    msg,
+  ( TypeRef (..),
+    ValidationError,
+    Value,
+    msgValidation,
   )
 import Data.Semigroup ((<>))
 
-typeViolation :: TypeRef -> ResolvedValue -> Message
+typeViolation :: TypeRef -> Value s -> ValidationError
 typeViolation expected found =
   "Expected type "
-    <> msg expected
+    <> msgValidation expected
     <> " found "
-    <> msg found
+    <> msgValidation found
     <> "."
 
 {-
diff --git a/src/Data/Morpheus/Error/Internal.hs b/src/Data/Morpheus/Error/Internal.hs
deleted file mode 100644
--- a/src/Data/Morpheus/Error/Internal.hs
+++ /dev/null
@@ -1,37 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-
-module Data.Morpheus.Error.Internal
-  ( internalTypeMismatch,
-    internalError,
-    internalResolvingError,
-  )
-where
-
--- MORPHEUS
-import Data.Morpheus.Error.Utils (globalErrorMessage)
-import Data.Morpheus.Types.Internal.AST.Base
-  ( GQLErrors,
-    Message,
-    msg,
-  )
-import Data.Morpheus.Types.Internal.AST.Value
-  ( ValidValue,
-  )
-import Data.Morpheus.Types.Internal.Resolving.Core
-  ( Eventless,
-    Failure (..),
-  )
-import Data.Semigroup ((<>))
-
--- GQL:: if no mutation defined -> "Schema is not configured for mutations."
--- all kind internal error in development
-internalError :: Message -> Eventless a
-internalError x = failure $ globalErrorMessage $ "INTERNAL ERROR: " <> x
-
-internalResolvingError :: Message -> GQLErrors
-internalResolvingError = globalErrorMessage . ("INTERNAL ERROR:" <>)
-
--- if value is already validated but value has different type
-internalTypeMismatch :: Message -> ValidValue -> Eventless a
-internalTypeMismatch text jsType =
-  internalError $ "Type mismatch " <> text <> msg jsType
diff --git a/src/Data/Morpheus/Error/NameCollision.hs b/src/Data/Morpheus/Error/NameCollision.hs
--- a/src/Data/Morpheus/Error/NameCollision.hs
+++ b/src/Data/Morpheus/Error/NameCollision.hs
@@ -1,12 +1,13 @@
+{-# LANGUAGE NoImplicitPrelude #-}
+
 module Data.Morpheus.Error.NameCollision
   ( NameCollision (..),
   )
 where
 
-import Data.Morpheus.Internal.Utils (KeyOf (..))
 import Data.Morpheus.Types.Internal.AST.Base
-  ( GQLError (..),
+  ( ValidationError,
   )
 
 class NameCollision a where
-  nameCollision :: KEY a -> a -> GQLError
+  nameCollision :: a -> ValidationError
diff --git a/src/Data/Morpheus/Error/Operation.hs b/src/Data/Morpheus/Error/Operation.hs
--- a/src/Data/Morpheus/Error/Operation.hs
+++ b/src/Data/Morpheus/Error/Operation.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Error.Operation
   ( mutationIsNotDefined,
@@ -6,16 +7,19 @@
   )
 where
 
-import Data.Morpheus.Error.Utils (errorMessage)
 import Data.Morpheus.Types.Internal.AST.Base
-  ( GQLErrors,
-    Position,
+  ( Position,
+    ValidationError (..),
   )
 
-mutationIsNotDefined :: Position -> GQLErrors
+mutationIsNotDefined :: Position -> ValidationError
 mutationIsNotDefined position =
-  errorMessage position "Schema is not configured for mutations."
+  ValidationError
+    "Schema is not configured for mutations."
+    [position]
 
-subscriptionIsNotDefined :: Position -> GQLErrors
+subscriptionIsNotDefined :: Position -> ValidationError
 subscriptionIsNotDefined position =
-  errorMessage position "Schema is not configured for subscriptions."
+  ValidationError
+    "Schema is not configured for subscriptions."
+    [position]
diff --git a/src/Data/Morpheus/Error/Schema.hs b/src/Data/Morpheus/Error/Schema.hs
--- a/src/Data/Morpheus/Error/Schema.hs
+++ b/src/Data/Morpheus/Error/Schema.hs
@@ -1,27 +1,25 @@
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Error.Schema
   ( nameCollisionError,
-    schemaValidationError,
   )
 where
 
-import Data.Morpheus.Error.Utils (globalErrorMessage)
 import Data.Morpheus.Types.Internal.AST.Base
-  ( GQLErrors,
-    Message,
-    TypeName,
-    msg,
+  ( TypeName,
+    ValidationError,
+    msgValidation,
   )
 import Data.Semigroup ((<>))
+import Prelude (($))
 
-schemaValidationError :: Message -> GQLErrors
-schemaValidationError error' =
-  globalErrorMessage $ "Schema Validation Error, " <> error'
+schemaValidationError :: ValidationError -> ValidationError
+schemaValidationError error = "Schema Validation Error, " <> error
 
-nameCollisionError :: TypeName -> GQLErrors
+nameCollisionError :: TypeName -> ValidationError
 nameCollisionError typeName =
   schemaValidationError $
     "Name collision: "
-      <> msg typeName
+      <> msgValidation typeName
       <> " is used for different dataTypes in two separate modules"
diff --git a/src/Data/Morpheus/Error/Selection.hs b/src/Data/Morpheus/Error/Selection.hs
--- a/src/Data/Morpheus/Error/Selection.hs
+++ b/src/Data/Morpheus/Error/Selection.hs
@@ -1,5 +1,6 @@
 {-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Error.Selection
   ( unknownSelectionField,
@@ -8,20 +9,21 @@
   )
 where
 
-import Data.Morpheus.Error.Utils (errorMessage)
-import Data.Morpheus.Types.Internal.AST.Base
+import Data.Morpheus.Types.Internal.AST
   ( FieldName,
-    GQLErrors,
     Position,
     Ref (..),
+    TypeDefinition (..),
     TypeName,
+    VALID,
+    ValidationError (..),
     msg,
   )
 import Data.Semigroup ((<>))
 
 -- GQL: "Field \"default\" must not have a selection since type \"String!\" has no subfields."
-hasNoSubfields :: Ref -> TypeName -> GQLErrors
-hasNoSubfields (Ref selectionName position) typeName = errorMessage position text
+hasNoSubfields :: Ref -> TypeDefinition s VALID -> ValidationError
+hasNoSubfields (Ref selectionName position) TypeDefinition {typeName} = ValidationError text [position]
   where
     text =
       "Field "
@@ -30,8 +32,8 @@
         <> msg typeName
         <> " has no subfields."
 
-unknownSelectionField :: TypeName -> Ref -> GQLErrors
-unknownSelectionField typeName Ref {refName, refPosition} = errorMessage refPosition text
+unknownSelectionField :: TypeName -> Ref -> ValidationError
+unknownSelectionField typeName Ref {refName, refPosition} = ValidationError text [refPosition]
   where
     text =
       "Cannot query field " <> msg refName
@@ -40,8 +42,8 @@
         <> "."
 
 -- GQL:: Field \"hobby\" of type \"Hobby!\" must have a selection of subfields. Did you mean \"hobby { ... }\"?
-subfieldsNotSelected :: FieldName -> TypeName -> Position -> GQLErrors
-subfieldsNotSelected fieldName typeName position = errorMessage position text
+subfieldsNotSelected :: FieldName -> TypeName -> Position -> ValidationError
+subfieldsNotSelected fieldName typeName position = ValidationError text [position]
   where
     text =
       "Field " <> msg fieldName <> " of type "
diff --git a/src/Data/Morpheus/Error/Utils.hs b/src/Data/Morpheus/Error/Utils.hs
--- a/src/Data/Morpheus/Error/Utils.hs
+++ b/src/Data/Morpheus/Error/Utils.hs
@@ -1,10 +1,12 @@
 {-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Error.Utils
   ( errorMessage,
     globalErrorMessage,
     badRequestError,
+    validationErrorMessage,
   )
 where
 
@@ -12,13 +14,19 @@
   ( ByteString,
     pack,
   )
+import Data.Maybe (Maybe, maybeToList)
 import Data.Morpheus.Types.Internal.AST.Base
   ( GQLError (..),
     GQLErrors,
     Message,
     Position (..),
+    ValidationError (..),
   )
 import Data.Semigroup ((<>))
+import Prelude ((.), String)
+
+validationErrorMessage :: Maybe Position -> Message -> ValidationError
+validationErrorMessage pos message = ValidationError message (maybeToList pos)
 
 errorMessage :: Position -> Message -> GQLErrors
 errorMessage position message = [GQLError {message, locations = [position]}]
diff --git a/src/Data/Morpheus/Error/Variable.hs b/src/Data/Morpheus/Error/Variable.hs
--- a/src/Data/Morpheus/Error/Variable.hs
+++ b/src/Data/Morpheus/Error/Variable.hs
@@ -1,5 +1,6 @@
 {-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Error.Variable
   ( uninitializedVariable,
@@ -7,23 +8,24 @@
   )
 where
 
-import Data.Morpheus.Error.Utils (errorMessage)
+import Data.Morpheus.Error.Utils (validationErrorMessage)
 import Data.Morpheus.Types.Internal.AST
-  ( GQLErrors,
-    Ref (..),
+  ( Ref (..),
     TypeRef,
+    ValidationError,
     Variable (..),
     msg,
   )
 import Data.Semigroup ((<>))
+import Prelude (($), Maybe (..))
 
 -- query M ( $v : String ) { a(p:$v) } -> "Variable \"$v\" of type \"String\" used in position expecting type \"LANGUAGE\"."
-incompatibleVariableType :: Ref -> Variable s -> TypeRef -> GQLErrors
+incompatibleVariableType :: Ref -> Variable s -> TypeRef -> ValidationError
 incompatibleVariableType
   (Ref variableName argPosition)
   Variable {variableType}
   argumentType =
-    errorMessage argPosition text
+    validationErrorMessage (Just argPosition) text
     where
       text =
         "Variable "
@@ -34,10 +36,10 @@
           <> msg argumentType
           <> "."
 
-uninitializedVariable :: Variable s -> GQLErrors
+uninitializedVariable :: Variable s -> ValidationError
 uninitializedVariable Variable {variableName, variableType, variablePosition} =
-  errorMessage
-    variablePosition
+  validationErrorMessage
+    (Just variablePosition)
     $ "Variable "
       <> msg ("$" <> variableName)
       <> " of required type "
diff --git a/src/Data/Morpheus/Error/Warning.hs b/src/Data/Morpheus/Error/Warning.hs
--- a/src/Data/Morpheus/Error/Warning.hs
+++ b/src/Data/Morpheus/Error/Warning.hs
@@ -1,5 +1,6 @@
 {-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Error.Warning
   ( renderGQLErrors,
@@ -13,6 +14,8 @@
 import Data.ByteString.Lazy.Char8 (unpack)
 import Data.Foldable (traverse_)
 -- MORPHEUS
+
+import Data.Maybe (Maybe (..), maybe)
 import Data.Morpheus.Error.Utils (errorMessage)
 import Data.Morpheus.Types.Internal.AST.Base
   ( Description,
@@ -25,6 +28,12 @@
 import Language.Haskell.TH
   ( Q,
     reportWarning,
+  )
+import Prelude
+  ( ($),
+    (.),
+    String,
+    pure,
   )
 
 renderGQLErrors :: GQLErrors -> String
diff --git a/src/Data/Morpheus/Internal/Graph.hs b/src/Data/Morpheus/Internal/Graph.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Morpheus/Internal/Graph.hs
@@ -0,0 +1,62 @@
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+module Data.Morpheus.Internal.Graph
+  ( cycleChecking,
+    Node,
+    Graph,
+    Edges,
+  )
+where
+
+import Control.Applicative (Applicative, pure)
+import Data.Foldable (traverse_)
+import Data.List (elem, lookup)
+import Data.Maybe (Maybe (..))
+-- MORPHEUS
+import Data.Morpheus.Types.Internal.AST
+  ( Ref (..),
+  )
+import Data.Semigroup ((<>))
+import Prelude
+  ( otherwise,
+  )
+
+type Node = Ref
+
+type Edges = (Ref, [Ref])
+
+type Graph = [Edges]
+
+cycleChecking ::
+  Applicative m =>
+  ([Ref] -> m ()) ->
+  Graph ->
+  m ()
+cycleChecking fail graph = traverse_ checkNode graph
+  where
+    checkNode (node, _) = cycleCheckingWith graph node [node] fail
+
+cycleCheckingWith ::
+  Applicative m =>
+  Graph ->
+  Ref ->
+  [Ref] ->
+  ([Ref] -> m ()) ->
+  m ()
+cycleCheckingWith graph parentNode history fail =
+  case lookup parentNode graph of
+    Just node -> traverse_ checkNode node
+    Nothing -> pure ()
+  where
+    checkNode node
+      | node `elem` history =
+        fail (node : history)
+      | otherwise =
+        cycleCheckingWith
+          graph
+          node
+          (history <> [node])
+          fail
diff --git a/src/Data/Morpheus/Internal/TH.hs b/src/Data/Morpheus/Internal/TH.hs
--- a/src/Data/Morpheus/Internal/TH.hs
+++ b/src/Data/Morpheus/Internal/TH.hs
@@ -1,78 +1,117 @@
 {-# LANGUAGE CPP #-}
 {-# LANGUAGE DataKinds #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE GADTs #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE QuasiQuotes #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE TemplateHaskellQuotes #-}
-{-# LANGUAGE TypeApplications #-}
+-- MORPHEUS
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Internal.TH
-  ( tyConArgs,
+  ( _',
     apply,
-    applyT,
-    typeT,
-    instanceHeadT,
-    instanceProxyFunD,
-    instanceFunD,
-    instanceHeadMultiT,
-    destructRecord,
-    typeInstanceDec,
-    infoTyVars,
+    applyCons,
+    applyVars,
     decArgs,
-    nameLitP,
-    nameStringE,
-    nameStringL,
-    nameConT,
-    nameVarE,
-    nameVarT,
-    nameConType,
-    nameConE,
-    nameVarP,
-    mkTypeName,
-    mkFieldName,
     declareTypeRef,
+    destructRecord,
+    funDProxy,
+    funDSimple,
+    infoTyVars,
+    isEnum,
+    m',
+    m_,
+    mkFieldsE,
     nameSpaceField,
     nameSpaceType,
-    m_,
-    m',
-    isEnum,
+    toCon,
+    toConE,
+    toConT,
+    ToName (..),
+    toString,
+    toVarE,
+    toVarT,
+    tyConArgs,
+    typeInstanceDec,
+    v',
+    cat',
+    _2',
+    o',
+    e',
+    vars,
+    decodeObjectE,
+    matchWith,
   )
 where
 
--- MORPHEUS
+import Control.Applicative ((<*>), pure)
+import Control.Monad.Fail (fail)
+import Data.Foldable (foldl, foldr1)
+import Data.Functor ((<$>))
+import Data.Maybe (Maybe (..))
 import Data.Morpheus.Internal.Utils
   ( nameSpaceField,
     nameSpaceType,
   )
 import Data.Morpheus.Types.Internal.AST
-  ( FieldName,
-    TypeKind (..),
+  ( FieldDefinition (..),
+    FieldName (..),
     TypeKind (..),
     TypeName (..),
     TypeRef (..),
     TypeWrapper (..),
     convertToHaskellName,
     isEnum,
+    isNullable,
     isOutputObject,
     readName,
   )
-import Data.Morpheus.Types.Internal.Resolving
-  ( UnSubResolver,
-  )
+import Data.Semigroup ((<>))
 import Data.Text (unpack)
 import Language.Haskell.TH
-
-m' :: Type
-m' = VarT $ mkTypeName m_
+import Prelude
+  ( ($),
+    (.),
+    (==),
+    Bool (..),
+    id,
+    map,
+    otherwise,
+    show,
+    (||),
+  )
 
 m_ :: TypeName
 m_ = "m"
 
-declareTypeRef :: Bool -> TypeRef -> Type
-declareTypeRef isSub TypeRef {typeConName, typeWrappers, typeArgs} =
+m' :: Type
+m' = VarT (mkName "m")
+
+o' :: Type
+o' = VarT (mkName "o")
+
+e' :: Type
+e' = VarT (mkName "event")
+
+_' :: PatQ
+_' = toVar (mkName "_")
+
+_2' :: PatQ
+_2' = toVar (mkName "_2")
+
+v' :: ToVar Name a => a
+v' = toVar (mkName "v")
+
+cat' :: Type
+cat' = VarT (mkName "cat")
+
+declareTypeRef :: TypeRef -> Type
+declareTypeRef TypeRef {typeConName, typeWrappers, typeArgs} =
   wrappedT
     typeWrappers
   where
@@ -80,63 +119,133 @@
     wrappedT (TypeList : xs) = AppT (ConT ''[]) $ wrappedT xs
     wrappedT (TypeMaybe : xs) = AppT (ConT ''Maybe) $ wrappedT xs
     wrappedT [] = decType typeArgs
-    ------------------------------------------------------
-    typeName = nameConType typeConName
     --------------------------------------------
-    decType _
-      | isSub =
-        AppT typeName (AppT (ConT ''UnSubResolver) m')
-    decType (Just par) = AppT typeName (VarT $ mkTypeName par)
-    decType _ = typeName
+    decType (Just par) = apply typeConName [toVar par]
+    decType _ = toCon typeConName
 
 tyConArgs :: TypeKind -> [TypeName]
 tyConArgs kindD
   | isOutputObject kindD || kindD == KindUnion = [m_]
   | otherwise = []
 
-apply :: Name -> [Q Exp] -> Q Exp
-apply n = foldl appE (conE n)
+cons :: ToCon a b => [a] -> [b]
+cons = map toCon
 
-applyT :: Name -> [Q Type] -> Q Type
-applyT name = foldl appT (conT name)
+vars :: ToVar a b => [a] -> [b]
+vars = map toVar
 
-typeT :: Name -> [TypeName] -> Q Type
-typeT name li = applyT name (map (varT . mkTypeName) li)
+class ToName a where
+  toName :: a -> Name
 
-instanceHeadT :: Name -> TypeName -> [TypeName] -> Q Type
-instanceHeadT cName iType tArgs = applyT cName [applyT (mkTypeName iType) (map (varT . mkTypeName) tArgs)]
+instance ToName Name where
+  toName = id
 
-instanceProxyFunD :: (Name, ExpQ) -> DecQ
-instanceProxyFunD (name, body) = instanceFunD name ["_"] body
+instance ToName TypeName where
+  toName = mkName . unpack . readTypeName
 
-instanceFunD :: Name -> [TypeName] -> ExpQ -> Q Dec
-instanceFunD name args body = funD name [clause (map (varP . mkTypeName) args) (normalB body) []]
+instance ToName FieldName where
+  toName = mkName . unpack . readName . convertToHaskellName
 
-instanceHeadMultiT :: Name -> Q Type -> [Q Type] -> Q Type
-instanceHeadMultiT className iType li = applyT className (iType : li)
+class ToString a b where
+  toString :: a -> b
 
--- "User" -> ["name","id"] -> (User name id)
-destructRecord :: TypeName -> [FieldName] -> PatQ
-destructRecord conName fields = conP (mkTypeName conName) (map (varP . mkFieldName) fields)
+instance ToString a b => ToString a (Q b) where
+  toString = pure . toString
 
-typeInstanceDec :: Name -> Type -> Type -> Dec
+instance ToString TypeName Lit where
+  toString = stringL . unpack . readTypeName
 
-nameLitP :: TypeName -> PatQ
-nameLitP = litP . nameStringL
+instance ToString TypeName Pat where
+  toString = LitP . toString
 
-nameStringL :: TypeName -> Lit
-nameStringL = stringL . unpack . readTypeName
+instance ToString FieldName Lit where
+  toString (FieldName x) = stringL (unpack x)
 
-nameStringE :: TypeName -> ExpQ
-nameStringE = stringE . (unpack . readTypeName)
+instance ToString TypeName Exp where
+  toString = LitE . toString
 
-#if MIN_VERSION_template_haskell(2,15,0)
--- fix breaking changes
-typeInstanceDec typeFamily arg res = TySynInstD (TySynEqn Nothing (AppT (ConT typeFamily) arg) res)
-#else
+instance ToString FieldName Exp where
+  toString = LitE . toString
+
+class ToCon a b where
+  toCon :: a -> b
+
+instance ToCon a b => ToCon a (Q b) where
+  toCon = pure . toCon
+
+instance (ToName a) => ToCon a Type where
+  toCon = ConT . toName
+
+instance (ToName a) => ToCon a Exp where
+  toCon = ConE . toName
+
+class ToVar a b where
+  toVar :: a -> b
+
+instance ToVar a b => ToVar a (Q b) where
+  toVar = pure . toVar
+
+instance (ToName a) => ToVar a Type where
+  toVar = VarT . toName
+
+instance (ToName a) => ToVar a Exp where
+  toVar = VarE . toName
+
+instance (ToName a) => ToVar a Pat where
+  toVar = VarP . toName
+
+class Apply a where
+  apply :: ToCon i a => i -> [a] -> a
+
+instance Apply TypeQ where
+  apply = foldl appT . toCon
+
+instance Apply Type where
+  apply = foldl AppT . toCon
+
+instance Apply Exp where
+  apply = foldl AppE . toCon
+
+instance Apply ExpQ where
+  apply = foldl appE . toCon
+
+applyVars ::
+  ( ToName con,
+    ToName var,
+    Apply res,
+    ToCon con res,
+    ToVar var res
+  ) =>
+  con ->
+  [var] ->
+  res
+applyVars name li = apply name (vars li)
+
+applyCons :: (ToName con, ToName cons) => con -> [cons] -> Q Type
+applyCons name li = apply name (cons li)
+
+funDProxy :: [(Name, ExpQ)] -> [DecQ]
+funDProxy = map fun
+  where
+    fun (name, body) = funDSimple name [_'] body
+
+funDSimple :: Name -> [PatQ] -> ExpQ -> DecQ
+funDSimple name args body = funD name [clause args (normalB body) []]
+
+-- |
+-- input:
+-- >>>
+-- destructRecord "User" ["name","id"]
+-- >>>
 --
-typeInstanceDec typeFamily arg res = TySynInstD typeFamily (TySynEqn [arg] res)
-#endif
+-- expression:
+-- >>>
+-- (User name id)
+-- >>>
+destructRecord :: TypeName -> [FieldDefinition cat s] -> PatQ
+destructRecord conName fields = conP (toName conName) (vars names)
+  where
+    names = map fieldName fields
 
 infoTyVars :: Info -> [TyVarBndr]
 infoTyVars (TyConI x) = decArgs x
@@ -148,26 +257,92 @@
 decArgs (TySynD _ args _) = args
 decArgs _ = []
 
-mkTypeName :: TypeName -> Name
-mkTypeName = mkName . unpack . readTypeName
+toConT :: ToName a => a -> Q Type
+toConT = conT . toName
 
-mkFieldName :: FieldName -> Name
-mkFieldName = mkName . unpack . readName . convertToHaskellName
+toVarT :: ToVar a TypeQ => a -> TypeQ
+toVarT = toVar
 
-nameConT :: TypeName -> Q Type
-nameConT = conT . mkTypeName
+toVarE :: ToVar a Exp => a -> ExpQ
+toVarE = toVar
 
-nameConType :: TypeName -> Type
-nameConType = ConT . mkTypeName
+toConE :: ToCon a Exp => a -> ExpQ
+toConE = toCon
 
-nameVarT :: TypeName -> Q Type
-nameVarT = varT . mkTypeName
+-- | 'mkFieldsE'
+--
+--  input :
+--  >>>
+--       mkFieldsE 'mkValue [FieldDefinition { fieldName = \"field1" ,..} ,..]
+--  >>>
+--
+--  expression :
+--  >>>
+--    [ mkValue \"field1\" field1,
+--    ..
+--    ]
+-- >>>
+mkFieldsE :: Name -> [FieldDefinition cat s] -> Exp
+mkFieldsE name = ListE . map (mkEntryWith name)
 
-nameVarE :: FieldName -> ExpQ
-nameVarE = varE . mkFieldName
+--  input : mkFieldWith 'mkValue (FieldDefinition { fieldName = "field1", ..})
+--  expression: mkValue "field1"  field1
+mkEntryWith ::
+  Name ->
+  FieldDefinition cat s ->
+  Exp
+mkEntryWith f FieldDefinition {fieldName} =
+  AppE
+    (AppE (VarE f) (toString fieldName))
+    (toVar fieldName)
 
-nameConE :: TypeName -> ExpQ
-nameConE = conE . mkTypeName
+decodeObjectE :: (Bool -> Name) -> TypeName -> [FieldDefinition cat s] -> ExpQ
+decodeObjectE _ conName [] = appE (varE 'pure) (toCon conName)
+decodeObjectE funName conName fields =
+  uInfixE
+    (toCon conName)
+    (varE '(<$>))
+    (foldr1 withApplicative $ map (defField funName) fields)
 
-nameVarP :: FieldName -> PatQ
-nameVarP = varP . mkFieldName
+withApplicative :: ExpQ -> ExpQ -> ExpQ
+withApplicative x = uInfixE x (varE '(<*>))
+
+matchWith ::
+  Bool ->
+  (t -> (PatQ, ExpQ)) ->
+  [t] ->
+  ExpQ
+matchWith isClosed f xs = lamCaseE (map buildMatch xs <> fallback)
+  where
+    fallback
+      | isClosed = []
+      | otherwise = [elseCaseEXP]
+    buildMatch x = match pat (normalB body) []
+      where
+        (pat, body) = f x
+
+elseCaseEXP :: MatchQ
+elseCaseEXP = match v' body []
+  where
+    body =
+      normalB $
+        appE
+          (toVarE 'fail)
+          ( uInfixE
+              (appE (varE 'show) v')
+              (varE '(<>))
+              (stringE " is Not Valid Union Constructor")
+          )
+
+defField :: (Bool -> Name) -> FieldDefinition cat s -> ExpQ
+defField f field@FieldDefinition {fieldName} = uInfixE v' (varE $ f (isNullable field)) (toString fieldName)
+
+#if MIN_VERSION_template_haskell(2,15,0)
+-- fix breaking changes
+typeInstanceDec :: Name -> Type -> Type -> Dec
+typeInstanceDec typeFamily arg res = TySynInstD (TySynEqn Nothing (AppT (ConT typeFamily) arg) res)
+#else
+--
+typeInstanceDec :: Name -> Type -> Type -> Dec
+typeInstanceDec typeFamily arg res = TySynInstD typeFamily (TySynEqn [arg] res)
+#endif
diff --git a/src/Data/Morpheus/Internal/Utils.hs b/src/Data/Morpheus/Internal/Utils.hs
--- a/src/Data/Morpheus/Internal/Utils.hs
+++ b/src/Data/Morpheus/Internal/Utils.hs
@@ -2,9 +2,7 @@
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE FunctionalDependencies #-}
 {-# LANGUAGE PolyKinds #-}
-{-# LANGUAGE RankNTypes #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Internal.Utils
   ( capital,
@@ -27,17 +25,36 @@
     mapFst,
     mapSnd,
     mapTuple,
+    UpdateT (..),
+    resolveUpdates,
+    concatUpdates,
+    failUpdates,
+    ordTraverse,
+    ordTraverse_,
+    traverseCollection,
+    (<.>),
+    SemigroupM (..),
   )
 where
 
+import Control.Applicative (Applicative (..))
+import Control.Monad ((=<<), foldM)
+import Control.Monad.Trans.Class (lift)
+import Control.Monad.Trans.Reader
+  ( ReaderT (..),
+  )
 import Data.Char
   ( toLower,
     toUpper,
   )
+import Data.Foldable (null, traverse_)
+import Data.Function ((&))
 import Data.HashMap.Lazy (HashMap)
 import qualified Data.HashMap.Lazy as HM
 import Data.Hashable (Hashable)
 import Data.List (find)
+import Data.Maybe (isJust, maybe)
+import Data.Morpheus.Error.NameCollision (NameCollision (..))
 import Data.Morpheus.Types.Internal.AST.Base
   ( FieldName,
     FieldName (..),
@@ -46,22 +63,42 @@
     Token,
     TypeName (..),
     TypeNameRef (..),
+    ValidationErrors,
+    toGQLError,
   )
-import Data.Semigroup ((<>))
+import Data.Semigroup (Semigroup (..))
 import qualified Data.Text as T
   ( concat,
     pack,
     unpack,
   )
+import Data.Traversable (traverse)
 import Instances.TH.Lift ()
 import Text.Megaparsec.Internal (ParsecT (..))
 import Text.Megaparsec.Stream (Stream)
+import Prelude
+  ( ($),
+    (.),
+    Bool (..),
+    Either (..),
+    Eq (..),
+    Functor (..),
+    Int,
+    Monad,
+    Ord,
+    String,
+    const,
+    fst,
+    length,
+    otherwise,
+    snd,
+  )
 
 mapText :: (String -> String) -> Token -> Token
 mapText f = T.pack . f . T.unpack
 
 nameSpaceType :: [FieldName] -> TypeName -> TypeName
-nameSpaceType list (TypeName name) = TypeName . T.concat $ map capital (map readName list <> [name])
+nameSpaceType list (TypeName name) = TypeName . T.concat $ fmap capital (fmap readName list <> [name])
 
 nameSpaceField :: TypeName -> FieldName -> FieldName
 nameSpaceField nSpace (FieldName name) = FieldName (nonCapital nSpace <> capital name)
@@ -90,61 +127,111 @@
   empty = []
   singleton x = [x]
 
-instance (Hashable k, KeyOf v, k ~ KEY v) => Collection v (HashMap k v) where
+instance KeyOf k v => Collection v (HashMap k v) where
   empty = HM.empty
   singleton x = HM.singleton (keyOf x) x
 
-class Selectable c a | c -> a where
-  selectOr :: d -> (a -> d) -> KEY a -> c -> d
+class Selectable k a c | c -> a where
+  selectOr :: d -> (a -> d) -> k -> c -> d
 
-instance KeyOf a => Selectable [a] a where
+instance KeyOf k a => Selectable k a [a] where
   selectOr fb f key lib = maybe fb f (find ((key ==) . keyOf) lib)
 
-instance (KEY a ~ k, Eq k, Hashable k) => Selectable (HashMap k a) a where
+instance KeyOf k a => Selectable k a (HashMap k a) where
   selectOr fb f key lib = maybe fb f (HM.lookup key lib)
 
-selectBy :: (Failure e m, Selectable c a, Monad m) => e -> KEY a -> c -> m a
+selectBy :: (Failure e m, Selectable k a c, Monad m) => e -> k -> c -> m a
 selectBy err = selectOr (failure err) pure
 
-member :: forall a c. Selectable c a => KEY a -> c -> Bool
+member :: Selectable k a c => k -> c -> Bool
 member = selectOr False toTrue
   where
     toTrue :: a -> Bool
     toTrue _ = True
 
-class Eq (KEY a) => KeyOf a where
-  type KEY a :: *
-  type KEY a = FieldName
-  keyOf :: a -> KEY a
+ordTraverse ::
+  ( Monad f,
+    KeyOf k b,
+    Listable a (t a),
+    Listable b (t b),
+    Failure ValidationErrors f
+  ) =>
+  (a -> f b) ->
+  t a ->
+  f (t b)
+ordTraverse = traverseCollection
 
-instance KeyOf Ref where
+traverseCollection ::
+  ( Monad f,
+    KeyOf k b,
+    Listable a (t a),
+    Listable b (t' b),
+    Failure ValidationErrors f
+  ) =>
+  (a -> f b) ->
+  t a ->
+  f (t' b)
+traverseCollection f a = fromElems =<< traverse f (elems a)
+
+ordTraverse_ ::
+  ( Monad f,
+    Listable a (t a)
+  ) =>
+  (a -> f b) ->
+  t a ->
+  f ()
+ordTraverse_ f a = traverse_ f (elems a)
+
+class (Eq k, Hashable k) => KeyOf k a | a -> k where
+  keyOf :: a -> k
+
+instance (Eq k, Hashable k) => KeyOf k (k, a) where
+  keyOf = fst
+
+instance KeyOf FieldName Ref where
   keyOf = refName
 
-instance KeyOf TypeNameRef where
-  type KEY TypeNameRef = TypeName
+instance KeyOf TypeName TypeNameRef where
   keyOf = typeNameRef
 
-toPair :: KeyOf a => a -> (KEY a, a)
+toPair :: KeyOf k a => a -> (k, a)
 toPair x = (keyOf x, x)
 
 -- list Like Collections
 class Listable a coll | coll -> a where
   elems :: coll -> [a]
-  fromElems :: (KeyOf a, Monad m, Failure GQLErrors m) => [a] -> m coll
+  fromElems :: (Monad m, Failure ValidationErrors m) => [a] -> m coll
 
-keys :: (KeyOf a, Listable a coll) => coll -> [KEY a]
-keys = map keyOf . elems
+instance (NameCollision a, KeyOf k a) => Listable a (HashMap k a) where
+  fromElems = safeFromList
+  elems = HM.elems
 
+keys :: (KeyOf k a, Listable a coll) => coll -> [k]
+keys = fmap keyOf . elems
+
 size :: Listable a coll => coll -> Int
 size = length . elems
 
 -- Merge Object with of Failure as an Option
 class Merge a where
-  merge :: (Monad m, Failure GQLErrors m) => [Ref] -> a -> a -> m a
+  merge :: (Monad m, Failure ValidationErrors m) => [Ref] -> a -> a -> m a
 
-(<:>) :: (Monad m, Merge a, Failure GQLErrors m) => a -> a -> m a
+instance (NameCollision a, KeyOf k a) => Merge (HashMap k a) where
+  merge _ = safeJoin
+
+(<:>) :: (Monad m, Merge a, Failure ValidationErrors m) => a -> a -> m a
 (<:>) = merge []
 
+class SemigroupM m a where
+  mergeM :: [Ref] -> a -> a -> m a
+
+(<.>) ::
+  (SemigroupM m a) =>
+  a ->
+  a ->
+  m a
+(<.>) = mergeM []
+
 -- Failure: for custome Morpheus GrapHQL errors
 class Applicative f => Failure error (f :: * -> *) where
   failure :: error -> f v
@@ -152,9 +239,12 @@
 instance Failure error (Either error) where
   failure = Left
 
-instance (Stream s, Ord e, Failure [a] m) => Failure [a] (ParsecT e s m) where
-  failure x = ParsecT $ \_ _ _ _ _ -> failure x
+instance (Monad m, Failure errors m) => Failure errors (ReaderT ctx m) where
+  failure = lift . failure
 
+instance (Stream s, Ord e, Failure GQLErrors m) => Failure ValidationErrors (ParsecT e s m) where
+  failure x = ParsecT $ \_ _ _ _ _ -> failure (fmap toGQLError x)
+
 mapFst :: (a -> a') -> (a, b) -> (a', b)
 mapFst f (a, b) = (f a, b)
 
@@ -163,3 +253,53 @@
 
 mapTuple :: (a -> a') -> (b -> b') -> (a, b) -> (a', b')
 mapTuple f1 f2 (a, b) = (f1 a, f2 b)
+
+-- Helper Functions
+newtype UpdateT m a = UpdateT {updateTState :: a -> m a}
+
+failUpdates :: (Failure e m) => e -> UpdateT m a
+failUpdates = UpdateT . const . failure
+
+concatUpdates :: Monad m => [UpdateT m a] -> UpdateT m a
+concatUpdates x = UpdateT (`resolveUpdates` x)
+
+resolveUpdates :: Monad m => a -> [UpdateT m a] -> m a
+resolveUpdates a = foldM (&) a . fmap updateTState
+
+safeFromList ::
+  ( Failure ValidationErrors m,
+    Applicative m,
+    NameCollision a,
+    Eq k,
+    Hashable k,
+    KeyOf k a
+  ) =>
+  [a] ->
+  m (HashMap k a)
+safeFromList values = safeUnionWith HM.empty (fmap toPair values)
+
+safeJoin :: (Failure ValidationErrors m, Eq k, Hashable k, Applicative m, NameCollision a) => HashMap k a -> HashMap k a -> m (HashMap k a)
+safeJoin hm newls = safeUnionWith hm (HM.toList newls)
+
+safeUnionWith ::
+  ( Failure ValidationErrors m,
+    Applicative m,
+    Eq k,
+    Hashable k,
+    NameCollision a
+  ) =>
+  HashMap k a ->
+  [(k, a)] ->
+  m (HashMap k a)
+safeUnionWith hm names = case insertNoDups (hm, []) names of
+  (res, dupps)
+    | null dupps -> pure res
+    | otherwise -> failure $ fmap (nameCollision . snd) dupps
+
+type NoDupHashMap k a = (HashMap k a, [(k, a)])
+
+insertNoDups :: (Eq k, Hashable k) => NoDupHashMap k a -> [(k, a)] -> NoDupHashMap k a
+insertNoDups collected [] = collected
+insertNoDups (coll, errors) (pair@(name, value) : xs)
+  | isJust (name `HM.lookup` coll) = insertNoDups (coll, errors <> [pair]) xs
+  | otherwise = insertNoDups (HM.insert name value coll, errors) xs
diff --git a/src/Data/Morpheus/Parser.hs b/src/Data/Morpheus/Parser.hs
--- a/src/Data/Morpheus/Parser.hs
+++ b/src/Data/Morpheus/Parser.hs
@@ -7,28 +7,32 @@
 where
 
 import Control.Monad ((>=>))
-import Data.Morpheus.Internal.Utils
-  ( fromElems,
+import qualified Data.Morpheus.Parsing.Document.TypeSystem as P
+  ( parseSchema,
+    parseTypeDefinitions,
   )
-import Data.Morpheus.Parsing.Document.TypeSystem (parseSchema)
 import Data.Morpheus.Parsing.Request.Parser (parseGQL)
 import Data.Morpheus.Types.IO
   ( GQLRequest (..),
   )
 import Data.Morpheus.Types.Internal.AST
   ( ANY,
+    CONST,
     GQLQuery (..),
     Operation,
     Schema (..),
     TypeDefinition (..),
     VALID,
+  )
+import Data.Morpheus.Types.Internal.Config
+  ( Config (..),
     VALIDATION_MODE (..),
   )
 import Data.Morpheus.Types.Internal.Resolving
   ( Eventless,
   )
 import Data.Morpheus.Validation.Document.Validation
-  ( validatePartialDocument,
+  ( validateSchema,
   )
 import Data.Morpheus.Validation.Query.Validation
   ( validateRequest,
@@ -36,17 +40,22 @@
 import Data.Text (Text)
 
 parseTypeSystemDefinition ::
-  Text -> Eventless Schema
+  Text -> Eventless (Schema VALID)
 parseTypeSystemDefinition =
-  parseSchema >=> fromElems
+  P.parseSchema
+    >=> validateSchema
+      True
+      Config
+        { debug = False,
+          validationMode = FULL_VALIDATION
+        }
 
 parseTypeDefinitions ::
-  Text -> Eventless [TypeDefinition ANY]
-parseTypeDefinitions =
-  parseSchema >=> validatePartialDocument
+  Text -> Eventless [TypeDefinition ANY CONST]
+parseTypeDefinitions = P.parseTypeDefinitions
 
 parseRequest :: GQLRequest -> Eventless GQLQuery
 parseRequest = parseGQL
 
-parseRequestWith :: Schema -> GQLRequest -> Eventless (Operation VALID)
-parseRequestWith schema = parseRequest >=> validateRequest schema FULL_VALIDATION
+parseRequestWith :: Config -> Schema VALID -> GQLRequest -> Eventless (Operation VALID)
+parseRequestWith config schema = parseRequest >=> validateRequest config schema
diff --git a/src/Data/Morpheus/Parsing/Document/TypeSystem.hs b/src/Data/Morpheus/Parsing/Document/TypeSystem.hs
--- a/src/Data/Morpheus/Parsing/Document/TypeSystem.hs
+++ b/src/Data/Morpheus/Parsing/Document/TypeSystem.hs
@@ -1,50 +1,77 @@
+{-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Parsing.Document.TypeSystem
   ( parseSchema,
+    parseTypeDefinitions,
   )
 where
 
 -- MORPHEUS
+
+import Control.Applicative ((*>), pure)
+import Control.Monad ((>=>))
+import Data.Foldable (foldr)
+import Data.Functor ((<$>), fmap)
+import Data.Maybe (Maybe (..))
+import Data.Morpheus.Error.NameCollision (NameCollision (..))
 import Data.Morpheus.Parsing.Internal.Internal
   ( Parser,
     processParser,
   )
 import Data.Morpheus.Parsing.Internal.Pattern
-  ( enumValueDefinition,
+  ( argumentsDefinition,
+    enumValueDefinition,
     fieldsDefinition,
     inputFieldsDefinition,
     optionalDirectives,
+    parseDirectiveLocation,
+    parseOperationType,
     typeDeclaration,
   )
 import Data.Morpheus.Parsing.Internal.Terms
   ( collection,
+    ignoredTokens,
     keyword,
-    operator,
     optDescription,
+    optionalCollection,
+    parseName,
     parseTypeName,
-    pipeLiteral,
+    pipe,
     sepByAnd,
-    spaceAndComments,
+    setOf,
+    symbol,
   )
+import Data.Morpheus.Parsing.Internal.Value
+  ( Parse (..),
+  )
 import Data.Morpheus.Types.Internal.AST
   ( ANY,
+    CONST,
     DataFingerprint (..),
     Description,
+    DirectiveDefinition (..),
     IN,
     OUT,
+    RawTypeDefinition (..),
+    RootOperationTypeDefinition (..),
     ScalarDefinition (..),
+    Schema,
+    SchemaDefinition (..),
     TypeContent (..),
     TypeDefinition (..),
     TypeName,
-    UnionMember (..),
+    Value,
+    buildSchema,
     mkUnionMember,
     toAny,
   )
 import Data.Morpheus.Types.Internal.Resolving
   ( Eventless,
+    failure,
   )
 import Data.Text (Text)
 import Text.Megaparsec
@@ -52,15 +79,22 @@
     eof,
     label,
     manyTill,
-    sepBy1,
+    optional,
   )
+import Prelude
+  ( ($),
+    (.),
+  )
 
 -- Scalars : https://graphql.github.io/graphql-spec/June2018/#sec-Scalars
 --
 --  ScalarTypeDefinition:
 --    Description(opt) scalar Name Directives(Const)(opt)
 --
-scalarTypeDefinition :: Maybe Description -> Parser (TypeDefinition ANY)
+scalarTypeDefinition ::
+  Parse (Value s) =>
+  Maybe Description ->
+  Parser (TypeDefinition ANY s)
 scalarTypeDefinition typeDescription = label "ScalarTypeDefinition" $ do
   typeName <- typeDeclaration "scalar"
   typeDirectives <- optionalDirectives
@@ -86,7 +120,10 @@
 --  FieldDefinition
 --    Description(opt) Name ArgumentsDefinition(opt) : Type Directives(Const)(opt)
 --
-objectTypeDefinition :: Maybe Description -> Parser (TypeDefinition OUT)
+objectTypeDefinition ::
+  Parse (Value s) =>
+  Maybe Description ->
+  Parser (TypeDefinition OUT s)
 objectTypeDefinition typeDescription = label "ObjectTypeDefinition" $ do
   typeName <- typeDeclaration "type"
   objectImplements <- optionalImplementsInterfaces
@@ -111,7 +148,10 @@
 --  InterfaceTypeDefinition
 --    Description(opt) interface Name Directives(Const)(opt) FieldsDefinition(opt)
 --
-interfaceTypeDefinition :: Maybe Description -> Parser (TypeDefinition OUT)
+interfaceTypeDefinition ::
+  Parse (Value s) =>
+  Maybe Description ->
+  Parser (TypeDefinition OUT s)
 interfaceTypeDefinition typeDescription = label "InterfaceTypeDefinition" $ do
   typeName <- typeDeclaration "interface"
   typeDirectives <- optionalDirectives
@@ -131,7 +171,10 @@
 --    = |(opt) NamedType
 --      UnionMemberTypes | NamedType
 --
-unionTypeDefinition :: Maybe Description -> Parser (TypeDefinition OUT)
+unionTypeDefinition ::
+  Parse (Value s) =>
+  Maybe Description ->
+  Parser (TypeDefinition OUT s)
 unionTypeDefinition typeDescription = label "UnionTypeDefinition" $ do
   typeName <- typeDeclaration "union"
   typeDirectives <- optionalDirectives
@@ -142,7 +185,9 @@
         ..
       }
   where
-    unionMemberTypes = operator '=' *> (mkUnionMember <$> parseTypeName) `sepBy1` pipeLiteral
+    unionMemberTypes =
+      symbol '='
+        *> pipe (mkUnionMember <$> parseTypeName)
 
 -- Enums : https://graphql.github.io/graphql-spec/June2018/#sec-Enums
 --
@@ -155,7 +200,10 @@
 --  EnumValueDefinition
 --    Description(opt) EnumValue Directives(Const)(opt)
 --
-enumTypeDefinition :: Maybe Description -> Parser (TypeDefinition ANY)
+enumTypeDefinition ::
+  Parse (Value s) =>
+  Maybe Description ->
+  Parser (TypeDefinition ANY s)
 enumTypeDefinition typeDescription = label "EnumTypeDefinition" $ do
   typeName <- typeDeclaration "enum"
   typeDirectives <- optionalDirectives
@@ -174,7 +222,10 @@
 --   InputFieldsDefinition:
 --     { InputValueDefinition(list) }
 --
-inputObjectTypeDefinition :: Maybe Description -> Parser (TypeDefinition IN)
+inputObjectTypeDefinition ::
+  Parse (Value s) =>
+  Maybe Description ->
+  Parser (TypeDefinition IN s)
 inputObjectTypeDefinition typeDescription =
   label "InputObjectTypeDefinition" $ do
     typeName <- typeDeclaration "input"
@@ -187,20 +238,145 @@
           ..
         }
 
-parseDataType :: Parser (TypeDefinition ANY)
-parseDataType = label "TypeDefinition" $ do
-  description <- optDescription
-  -- scalar | enum |  input | object | union | interface
-  (toAny <$> inputObjectTypeDefinition description)
-    <|> (toAny <$> unionTypeDefinition description)
-    <|> enumTypeDefinition description
-    <|> scalarTypeDefinition description
-    <|> (toAny <$> objectTypeDefinition description)
-    <|> (toAny <$> interfaceTypeDefinition description)
+-- 3.13 DirectiveDefinition
+--
+--  DirectiveDefinition:
+--     Description[opt] directive @ Name ArgumentsDefinition[opt] repeatable[opt] on DirectiveLocations
+--
+--  DirectiveLocations:
+--    DirectiveLocations | DirectiveLocation
+--    |[opt] DirectiveLocation
 
-parseSchema :: Text -> Eventless [TypeDefinition ANY]
-parseSchema = processParser request
+parseDirectiveDefinition ::
+  Maybe Description ->
+  Parser RawTypeDefinition
+parseDirectiveDefinition directiveDefinitionDescription = label "DirectiveDefinition" $ do
+  keyword "directive"
+  symbol '@'
+  directiveDefinitionName <- parseName
+  directiveDefinitionArgs <- optionalCollection argumentsDefinition
+  _ <- optional (keyword "repeatable")
+  keyword "on"
+  directiveDefinitionLocations <- pipe parseDirectiveLocation
+  pure
+    $ RawDirectiveDefinition
+    $ DirectiveDefinition
+      { directiveDefinitionName,
+        directiveDefinitionDescription,
+        directiveDefinitionLocations,
+        directiveDefinitionArgs
+      }
+
+-- 3.2 Schema
+-- SchemaDefinition:
+--    schema Directives[Const,opt]
+--      { RootOperationTypeDefinitionlist }
+--
+--  RootOperationTypeDefinition:
+--    OperationType: NamedType
+
+-- data SchemaDefinition = SchemaDefinition
+--   { query :: TypeName,
+--     mutation :: Maybe TypeName,
+--     subscription :: Maybe TypeName
+--   }
+
+parseSchemaDefinition :: Maybe Description -> Parser RawTypeDefinition
+parseSchemaDefinition _schemaDescription = label "SchemaDefinition" $ do
+  keyword "schema"
+  schemaDirectives <- optionalDirectives
+  unSchemaDefinition <- setOf parseRootOperationTypeDefinition
+  pure
+    $ RawSchemaDefinition
+    $ SchemaDefinition {schemaDirectives, unSchemaDefinition}
+
+parseRootOperationTypeDefinition :: Parser RootOperationTypeDefinition
+parseRootOperationTypeDefinition = do
+  operationType <- parseOperationType
+  symbol ':'
+  RootOperationTypeDefinition operationType <$> parseTypeName
+
+parseTypeSystemUnit ::
+  Parser RawTypeDefinition
+parseTypeSystemUnit =
+  label "TypeDefinition" $
+    do
+      description <- optDescription
+      -- scalar | enum |  input | object | union | interface
+      types description
+        <|> parseSchemaDefinition description
+        <|> parseDirectiveDefinition description
   where
-    request = label "DocumentTypes" $ do
-      spaceAndComments
-      manyTill parseDataType eof
+    types description =
+      RawTypeDefinition
+        <$> ( (toAny <$> inputObjectTypeDefinition description)
+                <|> (toAny <$> unionTypeDefinition description)
+                <|> enumTypeDefinition description
+                <|> scalarTypeDefinition description
+                <|> (toAny <$> objectTypeDefinition description)
+                <|> (toAny <$> interfaceTypeDefinition description)
+            )
+
+typePartition ::
+  [RawTypeDefinition] ->
+  ( [SchemaDefinition],
+    [TypeDefinition ANY CONST],
+    [DirectiveDefinition CONST]
+  )
+typePartition = foldr split ([], [], [])
+
+split ::
+  RawTypeDefinition ->
+  ( [SchemaDefinition],
+    [TypeDefinition ANY CONST],
+    [DirectiveDefinition CONST]
+  ) ->
+  ( [SchemaDefinition],
+    [TypeDefinition ANY CONST],
+    [DirectiveDefinition CONST]
+  )
+split (RawSchemaDefinition schema) (schemas, types, dirs) = (schema : schemas, types, dirs)
+split (RawTypeDefinition ty) (schemas, types, dirs) = (schemas, ty : types, dirs)
+split (RawDirectiveDefinition dir) (schemas, types, dirs) = (schemas, types, dir : dirs)
+
+--  split (RawDirectiveDefinition d)
+
+withSchemaDefinition ::
+  ( [SchemaDefinition],
+    [TypeDefinition ANY s],
+    [DirectiveDefinition CONST]
+  ) ->
+  Eventless
+    (Maybe SchemaDefinition, [TypeDefinition ANY s], [DirectiveDefinition CONST])
+withSchemaDefinition ([], t, dirs) = pure (Nothing, t, dirs)
+withSchemaDefinition ([x], t, dirs) = pure (Just x, t, dirs)
+withSchemaDefinition (_ : xs, _, _) = failure (fmap nameCollision xs)
+
+parseTypeSystemDefinition :: Parser [RawTypeDefinition]
+parseTypeSystemDefinition = label "TypeSystemDefinitions" $ do
+  ignoredTokens
+  manyTill parseTypeSystemUnit eof
+
+typeSystemDefinition ::
+  Text ->
+  Eventless
+    ( Maybe SchemaDefinition,
+      [TypeDefinition ANY CONST],
+      [DirectiveDefinition CONST]
+    )
+typeSystemDefinition =
+  processParser parseTypeSystemDefinition
+    >=> withSchemaDefinition . typePartition
+
+parseTypeDefinitions :: Text -> Eventless [TypeDefinition ANY CONST]
+parseTypeDefinitions = fmap snd3 . typeSystemDefinition
+
+snd3 :: (a, b, c) -> b
+snd3 (_, x, _) = x
+
+parseSchema ::
+  Text ->
+  Eventless (Schema CONST)
+parseSchema =
+  typeSystemDefinition
+    >=> buildSchema
diff --git a/src/Data/Morpheus/Parsing/Internal/Pattern.hs b/src/Data/Morpheus/Parsing/Internal/Pattern.hs
--- a/src/Data/Morpheus/Parsing/Internal/Pattern.hs
+++ b/src/Data/Morpheus/Parsing/Internal/Pattern.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE RecordWildCards #-}
 
 module Data.Morpheus.Parsing.Internal.Pattern
@@ -8,9 +9,13 @@
     optionalDirectives,
     enumValueDefinition,
     inputFieldsDefinition,
+    parseOperationType,
+    argumentsDefinition,
+    parseDirectiveLocation,
   )
 where
 
+import Data.Functor (($>))
 -- MORPHEUS
 import Data.Morpheus.Parsing.Internal.Arguments
   ( maybeArguments,
@@ -20,14 +25,14 @@
     getLocation,
   )
 import Data.Morpheus.Parsing.Internal.Terms
-  ( keyword,
-    litAssignment,
-    operator,
+  ( ignoredTokens,
+    keyword,
     optDescription,
     parseName,
     parseType,
     parseTypeName,
     setOf,
+    symbol,
     uniqTuple,
   )
 import Data.Morpheus.Parsing.Internal.Value
@@ -38,6 +43,7 @@
   ( ArgumentsDefinition (..),
     DataEnumValue (..),
     Directive (..),
+    DirectiveLocation (..),
     FieldContent (..),
     FieldDefinition (..),
     FieldName,
@@ -45,21 +51,28 @@
     IN,
     InputFieldsDefinition,
     OUT,
+    OperationType (..),
     TypeName,
     Value,
   )
+import Data.Text (pack)
 import Text.Megaparsec
-  ( label,
+  ( (<|>),
+    choice,
+    label,
     many,
     optional,
   )
+import Text.Megaparsec.Char (string)
 
 --  EnumValueDefinition: https://graphql.github.io/graphql-spec/June2018/#EnumValueDefinition
 --
 --  EnumValueDefinition
 --    Description(opt) EnumValue Directives(Const)(opt)
 --
-enumValueDefinition :: Parser DataEnumValue
+enumValueDefinition ::
+  Parse (Value s) =>
+  Parser (DataEnumValue s)
 enumValueDefinition = label "EnumValueDefinition" $ do
   enumDescription <- optDescription
   enumName <- parseTypeName
@@ -71,11 +84,13 @@
 -- InputValueDefinition
 --   Description(opt) Name : Type DefaultValue(opt) Directives (Const)(opt)
 --
-inputValueDefinition :: Parser (FieldDefinition IN)
+inputValueDefinition ::
+  Parse (Value s) =>
+  Parser (FieldDefinition IN s)
 inputValueDefinition = label "InputValueDefinition" $ do
   fieldDescription <- optDescription
   fieldName <- parseName
-  litAssignment -- ':'
+  symbol ':'
   fieldType <- parseType
   fieldContent <- optional (DefaultInputValue <$> parseDefaultValue)
   fieldDirectives <- optionalDirectives
@@ -86,7 +101,9 @@
 -- ArgumentsDefinition:
 --   ( InputValueDefinition(list) )
 --
-argumentsDefinition :: Parser ArgumentsDefinition
+argumentsDefinition ::
+  Parse (Value s) =>
+  Parser (ArgumentsDefinition s)
 argumentsDefinition =
   label "ArgumentsDefinition" $
     uniqTuple inputValueDefinition
@@ -96,18 +113,20 @@
 --  FieldsDefinition :
 --    { FieldDefinition(list) }
 --
-fieldsDefinition :: Parser (FieldsDefinition OUT)
+fieldsDefinition ::
+  Parse (Value s) =>
+  Parser (FieldsDefinition OUT s)
 fieldsDefinition = label "FieldsDefinition" $ setOf fieldDefinition
 
 --  FieldDefinition
 --    Description(opt) Name ArgumentsDefinition(opt) : Type Directives(Const)(opt)
 --
-fieldDefinition :: Parser (FieldDefinition OUT)
+fieldDefinition :: Parse (Value s) => Parser (FieldDefinition OUT s)
 fieldDefinition = label "FieldDefinition" $ do
   fieldDescription <- optDescription
   fieldName <- parseName
   fieldContent <- optional (FieldArgs <$> argumentsDefinition)
-  litAssignment -- ':'
+  symbol ':'
   fieldType <- parseType
   fieldDirectives <- optionalDirectives
   pure FieldDefinition {..}
@@ -116,7 +135,9 @@
 --   InputFieldsDefinition:
 --     { InputValueDefinition(list) }
 --
-inputFieldsDefinition :: Parser InputFieldsDefinition
+inputFieldsDefinition ::
+  Parse (Value s) =>
+  Parser (InputFieldsDefinition s)
 inputFieldsDefinition = label "InputFieldsDefinition" $ setOf inputValueDefinition
 
 -- Directives : https://graphql.github.io/graphql-spec/June2018/#sec-Language.Directives
@@ -135,7 +156,7 @@
 directive :: Parse (Value s) => Parser (Directive s)
 directive = label "Directive" $ do
   directivePosition <- getLocation
-  operator '@'
+  symbol '@'
   directiveName <- parseName
   directiveArgs <- maybeArguments
   pure Directive {..}
@@ -149,3 +170,43 @@
 typeDeclaration kind = do
   keyword kind
   parseTypeName
+
+parseOperationType :: Parser OperationType
+parseOperationType = label "OperationType" $ do
+  kind <-
+    (string "query" $> Query)
+      <|> (string "mutation" $> Mutation)
+      <|> (string "subscription" $> Subscription)
+  ignoredTokens
+  return kind
+
+parseDirectiveLocation :: Parser DirectiveLocation
+parseDirectiveLocation =
+  label
+    "DirectiveLocation"
+    ( choice $
+        toKeyword
+          <$> [ FIELD_DEFINITION,
+                FRAGMENT_DEFINITION,
+                FRAGMENT_SPREAD,
+                INLINE_FRAGMENT,
+                ARGUMENT_DEFINITION,
+                INTERFACE,
+                ENUM_VALUE,
+                INPUT_OBJECT,
+                INPUT_FIELD_DEFINITION,
+                SCHEMA,
+                SCALAR,
+                OBJECT,
+                QUERY,
+                MUTATION,
+                SUBSCRIPTION,
+                UNION,
+                ENUM,
+                FIELD
+              ]
+    )
+    <* ignoredTokens
+
+toKeyword :: Show a => a -> Parser a
+toKeyword x = string (pack $ show x) $> x
diff --git a/src/Data/Morpheus/Parsing/Internal/Terms.hs b/src/Data/Morpheus/Parsing/Internal/Terms.hs
--- a/src/Data/Morpheus/Parsing/Internal/Terms.hs
+++ b/src/Data/Morpheus/Parsing/Internal/Terms.hs
@@ -3,12 +3,10 @@
 {-# LANGUAGE TupleSections #-}
 
 module Data.Morpheus.Parsing.Internal.Terms
-  ( token,
-    qualifier,
+  ( name,
     variable,
-    spaceAndComments,
-    spaceAndComments1,
-    pipeLiteral,
+    ignoredTokens,
+    parseString,
     -------------
     collection,
     setOf,
@@ -19,19 +17,17 @@
     parseNonNull,
     parseAssignment,
     parseWrappedType,
-    litEquals,
-    litAssignment,
-    parseTuple,
     parseAlias,
     sepByAnd,
     parseName,
     parseType,
     keyword,
-    operator,
+    symbol,
     optDescription,
-    optionalList,
+    optionalCollection,
     parseNegativeSign,
     parseTypeName,
+    pipe,
   )
 where
 
@@ -40,8 +36,10 @@
 -- MORPHEUS
 
 import Data.Morpheus.Internal.Utils
-  ( KeyOf,
+  ( Collection,
+    KeyOf,
     Listable (..),
+    empty,
     fromElems,
   )
 import Data.Morpheus.Parsing.Internal.Internal
@@ -67,16 +65,16 @@
   ( (<?>),
     (<|>),
     between,
+    choice,
     label,
     many,
     manyTill,
     optional,
     sepBy,
+    sepBy1,
     sepEndBy,
-    skipMany,
     skipManyTill,
     try,
-    try,
   )
 import Text.Megaparsec.Char
   ( char,
@@ -89,57 +87,55 @@
     string,
   )
 
--- Name : https://graphql.github.io/graphql-spec/June2018/#sec-Names
---
--- Name :: /[_A-Za-z][_0-9A-Za-z]*/
---
-
 parseNegativeSign :: Parser Bool
-parseNegativeSign = (char '-' $> True <* spaceAndComments) <|> pure False
+parseNegativeSign = (char '-' $> True <* ignoredTokens) <|> pure False
 
 parseName :: Parser FieldName
-parseName = FieldName <$> token
+parseName = FieldName <$> name
 
 parseTypeName :: Parser TypeName
-parseTypeName = TypeName <$> token
+parseTypeName = label "TypeName" $ TypeName <$> name
 
 keyword :: FieldName -> Parser ()
-keyword (FieldName word) = string word *> space1 *> spaceAndComments
+keyword (FieldName word) = string word *> space1 *> ignoredTokens
 
-operator :: Char -> Parser ()
-operator x = char x *> spaceAndComments
+symbol :: Char -> Parser ()
+symbol x = char x *> ignoredTokens
 
 -- LITERALS
 braces :: Parser [a] -> Parser [a]
 braces =
   between
-    (char '{' *> spaceAndComments)
-    (char '}' *> spaceAndComments)
-
-pipeLiteral :: Parser ()
-pipeLiteral = char '|' *> spaceAndComments
-
-litEquals :: Parser ()
-litEquals = char '=' *> spaceAndComments
-
-litAssignment :: Parser ()
-litAssignment = char ':' *> spaceAndComments
+    (char '{' *> ignoredTokens)
+    (char '}' *> ignoredTokens)
 
 -- PRIMITIVE
 ------------------------------------
-token :: Parser Token
-token = label "token" $ do
-  firstChar <- letterChar <|> char '_'
-  restToken <- many $ letterChar <|> char '_' <|> digitChar
-  spaceAndComments
-  return $ pack $ firstChar : restToken
 
-qualifier :: Parser (FieldName, Position)
-qualifier = label "qualifier" $ do
-  position <- getLocation
-  value <- parseName
-  return (value, position)
+-- 2.1.9 Names
+-- https://spec.graphql.org/draft/#Name
+-- Name ::
+--  NameStart NameContinue[list,opt]
+--
+name :: Parser Token
+name = label "Name" $ do
+  start <- nameStart
+  continue <- nameContinue
+  ignoredTokens
+  pure $ pack (start : continue)
 
+-- NameStart::
+--   Letter
+--   _
+nameStart :: Parser Char
+nameStart = letterChar <|> char '_'
+
+--  NameContinue::
+--   Letter
+--   Digit
+nameContinue :: Parser String
+nameContinue = many (letterChar <|> char '_' <|> digitChar)
+
 -- Variable : https://graphql.github.io/graphql-spec/June2018/#Variable
 --
 -- Variable :  $Name
@@ -149,37 +145,61 @@
   refPosition <- getLocation
   _ <- char '$'
   refName <- parseName
-  spaceAndComments
+  ignoredTokens
   pure $ Ref {refName, refPosition}
 
-spaceAndComments1 :: Parser ()
-spaceAndComments1 = space1 *> spaceAndComments
-
 -- Descriptions: https://graphql.github.io/graphql-spec/June2018/#Description
 --
 -- Description:
 --   StringValue
--- TODO: should support """ and "
---
+parseDescription :: Parser Description
+parseDescription = strip <$> parseString
+
 optDescription :: Parser (Maybe Description)
 optDescription = optional parseDescription
 
-parseDescription :: Parser Description
-parseDescription =
-  strip . pack <$> (blockDescription <|> singleLine) <* spaceAndComments
+parseString :: Parser Token
+parseString = blockString <|> singleLineString
+
+blockString :: Parser Token
+blockString = stringWith (string "\"\"\"") (printChar <|> newline)
+
+singleLineString :: Parser Token
+singleLineString = stringWith (char '"') escapedChar
+
+stringWith :: Parser quote -> Parser Char -> Parser Token
+stringWith quote parser =
+  pack
+    <$> ( quote
+            *> manyTill parser quote
+            <* ignoredTokens
+        )
+
+escapedChar :: Parser Char
+escapedChar = label "EscapedChar" $ printChar >>= handleEscape
+
+handleEscape :: Char -> Parser Char
+handleEscape '\\' = choice escape
+handleEscape x = pure x
+
+escape :: [Parser Char]
+escape = map escapeCh escapeOptions
   where
-    blockDescription =
-      blockQuotes
-        *> manyTill (printChar <|> newline) blockQuotes
-        <* spaceAndComments
-      where
-        blockQuotes = string "\"\"\""
-    ----------------------------
-    singleLine =
-      stringQuote *> manyTill printChar stringQuote <* spaceAndComments
-      where
-        stringQuote = char '"'
+    escapeCh :: (Char, Char) -> Parser Char
+    escapeCh (code, replacement) = char code $> replacement
 
+escapeOptions :: [(Char, Char)]
+escapeOptions =
+  [ ('b', '\b'),
+    ('n', '\n'),
+    ('f', '\f'),
+    ('r', '\r'),
+    ('t', '\t'),
+    ('\\', '\\'),
+    ('\"', '\"'),
+    ('/', '/')
+  ]
+
 -- Ignored Tokens : https://graphql.github.io/graphql-spec/June2018/#sec-Source-Text.Ignored-Tokens
 --  Ignored:
 --    UnicodeBOM
@@ -187,57 +207,67 @@
 --    LineTerminator
 --    Comment
 --    Comma
--- TODO: implement as in specification
-spaceAndComments :: Parser ()
-spaceAndComments = ignoredTokens
-
 ignoredTokens :: Parser ()
 ignoredTokens =
-  label "IgnoredTokens" $ space *> skipMany inlineComment *> space
-  where
-    inlineComment = char '#' *> skipManyTill printChar newline *> space
+  label "IgnoredTokens" $
+    space
+      *> many ignored
+      *> space
 
+ignored :: Parser ()
+ignored =
+  label "Ignored" $
+    comment
+      <|> comma
+
+comment :: Parser ()
+comment =
+  label "Comment" $
+    char '#' *> skipManyTill printChar newline *> space
+
+comma :: Parser ()
+comma = label "Comma" $ char ',' *> space
+
 ------------------------------------------------------------------------
 
--- COMPLEX
 sepByAnd :: Parser a -> Parser [a]
-sepByAnd entry = entry `sepBy` (optional (char '&') *> spaceAndComments)
+sepByAnd entry = entry `sepBy` (optional (symbol '&') *> ignoredTokens)
 
+pipe :: Parser a -> Parser [a]
+pipe x = optional (symbol '|') *> (x `sepBy1` symbol '|')
+
 -----------------------------
 collection :: Parser a -> Parser [a]
-collection entry = braces (entry `sepEndBy` many (char ',' *> spaceAndComments))
+collection entry = braces (entry `sepEndBy` ignoredTokens)
 
-setOf :: (Listable a coll, KeyOf a) => Parser a -> Parser coll
+setOf :: (Listable a coll, KeyOf k a) => Parser a -> Parser coll
 setOf = collection >=> fromElems
 
+optionalCollection :: Collection a c => Parser c -> Parser c
+optionalCollection x = x <|> pure empty
+
 parseNonNull :: Parser [DataTypeWrapper]
 parseNonNull = do
   wrapper <- (char '!' $> [NonNullType]) <|> pure []
-  spaceAndComments
+  ignoredTokens
   return wrapper
 
-optionalList :: Parser [a] -> Parser [a]
-optionalList x = x <|> pure []
-
-parseTuple :: Parser a -> Parser [a]
-parseTuple parser =
+uniqTuple :: (Listable a coll, KeyOf k a) => Parser a -> Parser coll
+uniqTuple parser =
   label "Tuple" $
     between
-      (char '(' *> spaceAndComments)
-      (char ')' *> spaceAndComments)
-      ( parser `sepBy` (many (char ',') *> spaceAndComments) <?> "empty Tuple value!"
-      )
-
-uniqTuple :: (Listable a coll, KeyOf a) => Parser a -> Parser coll
-uniqTuple = parseTuple >=> fromElems
+      (char '(' *> ignoredTokens)
+      (char ')' *> ignoredTokens)
+      (parser `sepBy` ignoredTokens <?> "empty Tuple value!")
+      >>= fromElems
 
-uniqTupleOpt :: (Listable a coll, KeyOf a) => Parser a -> Parser coll
-uniqTupleOpt = optionalList . parseTuple >=> fromElems
+uniqTupleOpt :: (Listable a coll, Collection a coll, KeyOf k a) => Parser a -> Parser coll
+uniqTupleOpt x = uniqTuple x <|> pure empty
 
 parseAssignment :: (Show a, Show b) => Parser a -> Parser b -> Parser (a, b)
 parseAssignment nameParser valueParser = label "assignment" $ do
   name' <- nameParser
-  litAssignment
+  symbol ':'
   value' <- valueParser
   pure (name', value')
 
@@ -248,8 +278,7 @@
 --
 parseTypeCondition :: Parser TypeName
 parseTypeCondition = do
-  _ <- string "on"
-  space1
+  keyword "on"
   parseTypeName
 
 spreadLiteral :: Parser Position
@@ -259,30 +288,13 @@
   space
   return index
 
-parseWrappedType :: Parser ([DataTypeWrapper], TypeName)
-parseWrappedType = (unwrapped <|> wrapped) <* spaceAndComments
-  where
-    unwrapped :: Parser ([DataTypeWrapper], TypeName)
-    unwrapped = ([],) <$> parseTypeName <* spaceAndComments
-    ----------------------------------------------
-    wrapped :: Parser ([DataTypeWrapper], TypeName)
-    wrapped =
-      between
-        (char '[' *> spaceAndComments)
-        (char ']' *> spaceAndComments)
-        ( do
-            (wrappers, name) <- unwrapped <|> wrapped
-            nonNull' <- parseNonNull
-            return ((ListType : nonNull') ++ wrappers, name)
-        )
-
 -- Field Alias : https://graphql.github.io/graphql-spec/June2018/#sec-Field-Alias
 -- Alias
 --  Name:
 parseAlias :: Parser (Maybe FieldName)
 parseAlias = try (optional alias) <|> pure Nothing
   where
-    alias = label "alias" $ parseName <* char ':' <* spaceAndComments
+    alias = label "alias" $ parseName <* char ':' <* ignoredTokens
 
 parseType :: Parser TypeRef
 parseType = do
@@ -294,3 +306,20 @@
         typeArgs = Nothing,
         typeWrappers = toHSWrappers $ nonNull ++ wrappers
       }
+
+parseWrappedType :: Parser ([DataTypeWrapper], TypeName)
+parseWrappedType = (unwrapped <|> wrapped) <* ignoredTokens
+  where
+    unwrapped :: Parser ([DataTypeWrapper], TypeName)
+    unwrapped = ([],) <$> parseTypeName <* ignoredTokens
+    ----------------------------------------------
+    wrapped :: Parser ([DataTypeWrapper], TypeName)
+    wrapped =
+      between
+        (char '[' *> ignoredTokens)
+        (char ']' *> ignoredTokens)
+        ( do
+            (wrappers, tname) <- unwrapped <|> wrapped
+            nonNull' <- parseNonNull
+            return ((ListType : nonNull') ++ wrappers, tname)
+        )
diff --git a/src/Data/Morpheus/Parsing/Internal/Value.hs b/src/Data/Morpheus/Parsing/Internal/Value.hs
--- a/src/Data/Morpheus/Parsing/Internal/Value.hs
+++ b/src/Data/Morpheus/Parsing/Internal/Value.hs
@@ -17,32 +17,29 @@
   ( Parser,
   )
 import Data.Morpheus.Parsing.Internal.Terms
-  ( litEquals,
+  ( ignoredTokens,
     parseAssignment,
     parseName,
     parseNegativeSign,
+    parseString,
     parseTypeName,
     setOf,
-    spaceAndComments,
+    symbol,
     variable,
   )
 import Data.Morpheus.Types.Internal.AST
-  ( FieldName,
+  ( CONST,
+    FieldName,
     ObjectEntry (..),
-    OrderedMap,
+    OrdMap,
     RAW,
-    ResolvedValue,
     ScalarValue (..),
-    VALID,
     Value (..),
     decodeScientific,
   )
-import Data.Text (pack)
 import Text.Megaparsec
   ( (<|>),
-    anySingleBut,
     between,
-    choice,
     label,
     many,
     sepBy,
@@ -74,53 +71,38 @@
 enumValue :: Parser (Value a)
 enumValue = do
   enum <- Enum <$> parseTypeName
-  spaceAndComments
+  ignoredTokens
   return enum
 
-escaped :: Parser Char
-escaped = label "escaped" $ do
-  x <- anySingleBut '\"'
-  if x == '\\' then choice (zipWith escapeChar codes replacements) else pure x
-  where
-    replacements = ['\b', '\n', '\f', '\r', '\t', '\\', '\"', '/']
-    codes = ['b', 'n', 'f', 'r', 't', '\\', '\"', '/']
-    escapeChar code replacement = char code >> return replacement
-
 stringValue :: Parser (Value a)
-stringValue =
-  label "stringValue" $
-    Scalar . String . pack
-      <$> between
-        (char '"')
-        (char '"')
-        (many escaped)
+stringValue = label "stringValue" $ Scalar . String <$> parseString
 
 listValue :: Parser a -> Parser [a]
 listValue parser =
   label "ListValue" $
     between
-      (char '[' *> spaceAndComments)
-      (char ']' *> spaceAndComments)
-      (parser `sepBy` (many (char ',') *> spaceAndComments))
+      (char '[' *> ignoredTokens)
+      (char ']' *> ignoredTokens)
+      (parser `sepBy` (many (char ',') *> ignoredTokens))
 
 objectEntry :: Parser (Value a) -> Parser (ObjectEntry a)
 objectEntry parser = label "ObjectEntry" $ do
   (entryName, entryValue) <- parseAssignment parseName parser
   pure ObjectEntry {entryName, entryValue}
 
-objectValue :: Parser (Value a) -> Parser (OrderedMap FieldName (ObjectEntry a))
+objectValue :: Parser (Value a) -> Parser (OrdMap FieldName (ObjectEntry a))
 objectValue = label "ObjectValue" . setOf . objectEntry
 
 parsePrimitives :: Parser (Value a)
 parsePrimitives =
   valueNull <|> booleanValue <|> valueNumber <|> enumValue <|> stringValue
 
-parseDefaultValue :: Parser ResolvedValue
+parseDefaultValue :: Parser (Value s)
 parseDefaultValue = do
-  litEquals
+  symbol '='
   parseV
   where
-    parseV :: Parser ResolvedValue
+    parseV :: Parser (Value s)
     parseV = structValue parseV
 
 class Parse a where
@@ -129,7 +111,7 @@
 instance Parse (Value RAW) where
   parse = (VariableValue <$> variable) <|> structValue parse
 
-instance Parse (Value VALID) where
+instance Parse (Value CONST) where
   parse = structValue parse
 
 structValue :: Parser (Value a) -> Parser (Value a)
@@ -139,4 +121,4 @@
         <|> (Object <$> objectValue parser)
         <|> (List <$> listValue parser)
     )
-      <* spaceAndComments
+      <* ignoredTokens
diff --git a/src/Data/Morpheus/Parsing/JSONSchema/Parse.hs b/src/Data/Morpheus/Parsing/JSONSchema/Parse.hs
deleted file mode 100644
--- a/src/Data/Morpheus/Parsing/JSONSchema/Parse.hs
+++ /dev/null
@@ -1,116 +0,0 @@
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE TypeOperators #-}
-
-module Data.Morpheus.Parsing.JSONSchema.Parse
-  ( decodeIntrospection,
-  )
-where
-
-import Data.Aeson
-import Data.ByteString.Lazy (ByteString)
-import Data.Morpheus.Error.Internal (internalError)
-import Data.Morpheus.Internal.Utils
-  ( fromElems,
-  )
-import Data.Morpheus.Parsing.JSONSchema.Types
-  ( EnumValue (..),
-    Field (..),
-    InputValue (..),
-    Introspection (..),
-    Schema (..),
-    Type (..),
-  )
-import Data.Morpheus.Schema.TypeKind (TypeKind (..))
-import Data.Morpheus.Types.IO (JSONResponse (..))
-import qualified Data.Morpheus.Types.Internal.AST as AST
-  ( Schema,
-  )
-import Data.Morpheus.Types.Internal.AST
-  ( ANY,
-    ArgumentsDefinition (..),
-    DataTypeWrapper (..),
-    FieldDefinition,
-    IN,
-    OUT,
-    TypeContent (..),
-    TypeDefinition (..),
-    TypeName,
-    TypeWrapper,
-    createArgument,
-    createEnumType,
-    createScalarType,
-    createType,
-    createUnionType,
-    mkField,
-    mkObjectField,
-    msg,
-    toAny,
-    toHSWrappers,
-  )
-import Data.Morpheus.Types.Internal.Resolving
-  ( Eventless,
-  )
-import Data.Semigroup ((<>))
-
-decodeIntrospection :: ByteString -> Eventless AST.Schema
-decodeIntrospection jsonDoc = case jsonSchema of
-  Left errors -> internalError $ msg errors
-  Right JSONResponse {responseData = Just Introspection {__schema = Schema {types}}} ->
-    traverse parse types >>= fromElems . concat
-  Right res -> internalError (msg $ show res)
-  where
-    jsonSchema :: Either String (JSONResponse Introspection)
-    jsonSchema = eitherDecode jsonDoc
-
-class ParseJSONSchema a b where
-  parse :: a -> Eventless b
-
-instance ParseJSONSchema Type [TypeDefinition ANY] where
-  parse Type {name = Just typeName, kind = SCALAR} =
-    pure [createScalarType typeName]
-  parse Type {name = Just typeName, kind = ENUM, enumValues = Just enums} =
-    pure [createEnumType typeName (map enumName enums)]
-  parse Type {name = Just typeName, kind = UNION, possibleTypes = Just unions} =
-    case traverse name unions of
-      Nothing -> internalError "ERROR: GQL ERROR"
-      Just uni -> pure [toAny $ createUnionType typeName uni]
-  parse Type {name = Just typeName, kind = INPUT_OBJECT, inputFields = Just iFields} =
-    do
-      (fields :: [FieldDefinition IN]) <- traverse parse iFields
-      fs <- fromElems fields
-      pure [createType typeName $ DataInputObject fs]
-  parse Type {name = Just typeName, kind = OBJECT, fields = Just oFields} =
-    do
-      (fields :: [FieldDefinition OUT]) <- traverse parse oFields
-      fs <- fromElems fields
-      pure [createType typeName $ DataObject [] fs]
-  parse _ = pure []
-
-instance ParseJSONSchema Field (FieldDefinition OUT) where
-  parse Field {fieldName, fieldArgs, fieldType} = do
-    fType <- fieldTypeFromJSON fieldType
-    args <- traverse genArg fieldArgs >>= fromElems
-    pure $ mkObjectField (ArgumentsDefinition Nothing args) fieldName fType
-    where
-      genArg InputValue {inputName = argName, inputType = argType} =
-        createArgument argName <$> fieldTypeFromJSON argType
-
-instance ParseJSONSchema InputValue (FieldDefinition IN) where
-  parse InputValue {inputName, inputType} = mkField inputName <$> fieldTypeFromJSON inputType
-
-fieldTypeFromJSON :: Type -> Eventless ([TypeWrapper], TypeName)
-fieldTypeFromJSON = fmap toHs . fieldTypeRec []
-  where
-    toHs (w, t) = (toHSWrappers w, t)
-    fieldTypeRec ::
-      [DataTypeWrapper] -> Type -> Eventless ([DataTypeWrapper], TypeName)
-    fieldTypeRec acc Type {kind = LIST, ofType = Just ofType} =
-      fieldTypeRec (ListType : acc) ofType
-    fieldTypeRec acc Type {kind = NON_NULL, ofType = Just ofType} =
-      fieldTypeRec (NonNullType : acc) ofType
-    fieldTypeRec acc Type {name = Just name} = pure (acc, name)
-    fieldTypeRec _ x = internalError $ "Unsuported Field" <> msg (show x)
diff --git a/src/Data/Morpheus/Parsing/JSONSchema/Types.hs b/src/Data/Morpheus/Parsing/JSONSchema/Types.hs
deleted file mode 100644
--- a/src/Data/Morpheus/Parsing/JSONSchema/Types.hs
+++ /dev/null
@@ -1,86 +0,0 @@
-{-# LANGUAGE DeriveAnyClass #-}
-{-# LANGUAGE DeriveGeneric #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE TypeOperators #-}
-
-module Data.Morpheus.Parsing.JSONSchema.Types
-  ( Introspection (..),
-    Schema (..),
-    Type (..),
-    Field (..),
-    InputValue (..),
-    EnumValue (..),
-  )
-where
-
-import Data.Aeson
---
--- MORPHEUS
-import Data.Morpheus.Schema.TypeKind (TypeKind)
-import Data.Morpheus.Types.Internal.AST
-  ( FieldName,
-    TypeName,
-  )
-import GHC.Generics (Generic)
-
--- TYPES FOR DECODING JSON INTROSPECTION
---
-newtype Introspection = Introspection
-  { __schema :: Schema
-  }
-  deriving (Generic, Show, FromJSON)
-
-newtype Schema = Schema
-  { types :: [Type]
-  }
-  deriving (Generic, Show, FromJSON)
-
--- TYPE
-data Type = Type
-  { kind :: TypeKind,
-    name :: Maybe TypeName,
-    fields :: Maybe [Field],
-    interfaces :: Maybe [Type],
-    possibleTypes :: Maybe [Type],
-    enumValues :: Maybe [EnumValue],
-    inputFields :: Maybe [InputValue],
-    ofType :: Maybe Type
-  }
-  deriving (Generic, Show, FromJSON)
-
--- FIELD
-data Field = Field
-  { fieldName :: FieldName,
-    fieldArgs :: [InputValue],
-    fieldType :: Type
-  }
-  deriving (Show, Generic)
-
-instance FromJSON Field where
-  parseJSON = withObject "Field" objectParser
-    where
-      objectParser o = Field <$> o .: "name" <*> o .: "args" <*> o .: "type"
-
--- INPUT
-data InputValue = InputValue
-  { inputName :: FieldName,
-    inputType :: Type
-  }
-  deriving (Show, Generic)
-
-instance FromJSON InputValue where
-  parseJSON = withObject "InputValue" objectParser
-    where
-      objectParser o = InputValue <$> o .: "name" <*> o .: "type"
-
--- ENUM
-newtype EnumValue = EnumValue
-  { enumName :: TypeName
-  }
-  deriving (Generic, Show)
-
-instance FromJSON EnumValue where
-  parseJSON = withObject "EnumValue" objectParser
-    where
-      objectParser o = EnumValue <$> o .: "name"
diff --git a/src/Data/Morpheus/Parsing/Request/Operation.hs b/src/Data/Morpheus/Parsing/Request/Operation.hs
--- a/src/Data/Morpheus/Parsing/Request/Operation.hs
+++ b/src/Data/Morpheus/Parsing/Request/Operation.hs
@@ -6,10 +6,6 @@
   )
 where
 
-import Data.Functor (($>))
---
--- MORPHEUS
-
 import Data.Morpheus.Internal.Utils
   ( empty,
   )
@@ -19,12 +15,12 @@
   )
 import Data.Morpheus.Parsing.Internal.Pattern
   ( optionalDirectives,
+    parseOperationType,
   )
 import Data.Morpheus.Parsing.Internal.Terms
-  ( operator,
-    parseName,
+  ( parseName,
     parseType,
-    spaceAndComments1,
+    symbol,
     uniqTupleOpt,
     variable,
   )
@@ -48,7 +44,6 @@
     label,
     optional,
   )
-import Text.Megaparsec.Char (string)
 
 -- Variables :  https://graphql.github.io/graphql-spec/June2018/#VariableDefinition
 --
@@ -58,7 +53,7 @@
 variableDefinition :: Parser (Variable RAW)
 variableDefinition = label "VariableDefinition" $ do
   (Ref variableName variablePosition) <- variable
-  operator ':'
+  symbol ':'
   variableType <- parseType
   variableValue <- DefaultValue <$> optional parseDefaultValue
   pure Variable {..}
@@ -79,15 +74,6 @@
   operationDirectives <- optionalDirectives
   operationSelection <- parseSelectionSet
   pure Operation {..}
-
-parseOperationType :: Parser OperationType
-parseOperationType = label "OperationType" $ do
-  kind <-
-    (string "query" $> Query)
-      <|> (string "mutation" $> Mutation)
-      <|> (string "subscription" $> Subscription)
-  spaceAndComments1
-  return kind
 
 parseAnonymousQuery :: Parser (Operation RAW)
 parseAnonymousQuery = label "AnonymousQuery" $ do
diff --git a/src/Data/Morpheus/Parsing/Request/Parser.hs b/src/Data/Morpheus/Parsing/Request/Parser.hs
--- a/src/Data/Morpheus/Parsing/Request/Parser.hs
+++ b/src/Data/Morpheus/Parsing/Request/Parser.hs
@@ -18,7 +18,7 @@
     processParser,
   )
 import Data.Morpheus.Parsing.Internal.Terms
-  ( spaceAndComments,
+  ( ignoredTokens,
   )
 import Data.Morpheus.Parsing.Request.Operation
   ( parseOperation,
@@ -44,7 +44,7 @@
 
 request :: Parser GQLQuery
 request = label "GQLQuery" $ do
-  spaceAndComments
+  ignoredTokens
   operation <- parseOperation
   fragments <- manyTill parseFragmentDefinition eof >>= fromElems
   pure GQLQuery {operation, fragments, inputVariables = []}
diff --git a/src/Data/Morpheus/Parsing/Request/Selection.hs b/src/Data/Morpheus/Parsing/Request/Selection.hs
--- a/src/Data/Morpheus/Parsing/Request/Selection.hs
+++ b/src/Data/Morpheus/Parsing/Request/Selection.hs
@@ -108,7 +108,7 @@
 --  FragmentDefinition:
 --   fragment FragmentName TypeCondition Directives(opt) SelectionSet
 --
-parseFragmentDefinition :: Parser Fragment
+parseFragmentDefinition :: Parser (Fragment RAW)
 parseFragmentDefinition = label "FragmentDefinition" $ do
   keyword "fragment"
   fragmentPosition <- getLocation
@@ -125,7 +125,7 @@
   fragmentPosition <- spreadLiteral
   InlineFragment <$> fragmentBody "INLINE_FRAGMENT" fragmentPosition
 
-fragmentBody :: FieldName -> Position -> Parser Fragment
+fragmentBody :: FieldName -> Position -> Parser (Fragment RAW)
 fragmentBody fragmentName fragmentPosition = label "FragmentBody" $ do
   fragmentType <- parseTypeCondition
   fragmentDirectives <- optionalDirectives
diff --git a/src/Data/Morpheus/QuasiQuoter.hs b/src/Data/Morpheus/QuasiQuoter.hs
--- a/src/Data/Morpheus/QuasiQuoter.hs
+++ b/src/Data/Morpheus/QuasiQuoter.hs
@@ -19,7 +19,7 @@
   )
 import Data.Morpheus.Parser
   ( parseRequest,
-    parseTypeDefinitions,
+    parseTypeSystemDefinition,
   )
 import Data.Morpheus.Types.IO (GQLRequest (..))
 import Data.Morpheus.Types.Internal.Resolving
@@ -72,7 +72,7 @@
       error $ things ++ " are not supported by the GraphQL QuasiQuoter"
 
 dslExpression :: Text -> Q Exp
-dslExpression doc = case parseTypeDefinitions doc of
+dslExpression doc = case parseTypeSystemDefinition doc of
   Failure errors -> fail (renderGQLErrors errors)
   Success {result, warnings} ->
     gqlWarnings warnings >> [|result|]
diff --git a/src/Data/Morpheus/Rendering/RenderGQL.hs b/src/Data/Morpheus/Rendering/RenderGQL.hs
--- a/src/Data/Morpheus/Rendering/RenderGQL.hs
+++ b/src/Data/Morpheus/Rendering/RenderGQL.hs
@@ -1,26 +1,51 @@
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Rendering.RenderGQL
   ( RenderGQL (..),
     renderObject,
-    renderIndent,
+    renderMembers,
+    newline,
+    renderArguments,
+    renderEntry,
+    space,
+    Rendering,
   )
 where
 
 -- MORPHEUS
+
+import Data.Foldable (null)
+import Data.Functor ((<$>))
+import Data.Maybe (Maybe, maybe)
 import Data.Semigroup ((<>))
 import Data.Text
   ( Text,
     intercalate,
     pack,
   )
+import Prelude
+  ( (.),
+    Bool (..),
+    Float,
+    Int,
+    fmap,
+    otherwise,
+    show,
+  )
 
 type Rendering = Text
 
 class RenderGQL a where
   render :: a -> Rendering
 
+instance
+  RenderGQL a =>
+  RenderGQL (Maybe a)
+  where
+  render = maybe "" render
+
 instance RenderGQL Int where
   render = pack . show
 
@@ -34,9 +59,35 @@
   render True = "true"
   render False = "false"
 
-renderIndent :: Rendering
-renderIndent = "  "
+indent :: Rendering
+indent = "  "
 
-renderObject :: (a -> Rendering) -> [a] -> Rendering
-renderObject f list =
-  " { \n  " <> intercalate ("\n" <> renderIndent) (map f list) <> "\n}"
+space :: Rendering
+space = " "
+
+newline :: Rendering
+newline = "\n"
+
+indentNewline :: Rendering
+indentNewline = newline <> indent
+
+renderAtNewLine :: (RenderGQL a) => [a] -> Rendering
+renderAtNewLine elems = indentNewline <> intercalate indentNewline (fmap render elems)
+
+renderObject :: (RenderGQL a) => [a] -> Rendering
+renderObject fields = " {" <> renderAtNewLine fields <> "\n}"
+
+renderMembers :: (RenderGQL a) => [a] -> Rendering
+renderMembers members = intercalate (space <> "|" <> space) (fmap render members)
+
+renderArguments :: (RenderGQL a) => [a] -> Rendering
+renderArguments arguments
+  | null arguments = ""
+  | otherwise = "(" <> intercalate ", " (render <$> arguments) <> ")"
+
+renderEntry ::
+  (RenderGQL name, RenderGQL value) =>
+  name ->
+  value ->
+  Rendering
+renderEntry name value = render name <> ": " <> render value
diff --git a/src/Data/Morpheus/Rendering/RenderIntrospection.hs b/src/Data/Morpheus/Rendering/RenderIntrospection.hs
--- a/src/Data/Morpheus/Rendering/RenderIntrospection.hs
+++ b/src/Data/Morpheus/Rendering/RenderIntrospection.hs
@@ -2,13 +2,11 @@
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE GADTs #-}
-{-# LANGUAGE LambdaCase #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE RecordWildCards #-}
 {-# LANGUAGE TupleSections #-}
-{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Rendering.RenderIntrospection
   ( render,
@@ -16,20 +14,21 @@
   )
 where
 
-import Data.Maybe (isJust)
 -- Morpheus
 
+import Control.Applicative (pure)
+import Control.Monad (Monad (..))
+import Data.Foldable (foldr)
+import Data.Functor ((<$>))
+import Data.List (filter)
+import Data.Maybe (Maybe (..), isJust, maybe)
 import Data.Morpheus.Internal.Utils
   ( Failure,
     elems,
     failure,
-    fromElems,
     selectBy,
-    selectOr,
   )
 import qualified Data.Morpheus.Rendering.RenderGQL as GQL (RenderGQL (..))
-import Data.Morpheus.Schema.TypeKind (TypeKind (..))
-import qualified Data.Morpheus.Types.Internal.AST as AST (TypeKind (..))
 import Data.Morpheus.Types.Internal.AST
   ( ANY,
     ArgumentsDefinition (..),
@@ -47,31 +46,30 @@
     IN,
     Message,
     OUT,
-    Object,
-    ObjectEntry (..),
     QUERY,
-    RESOLVED,
     Schema,
     TRUE,
     TypeContent (..),
     TypeDefinition (..),
+    TypeKind (..),
     TypeName (..),
     TypeRef (..),
     UnionMember (..),
     VALID,
     Value (..),
-    createInputUnionFields,
     fieldVisibility,
     kindOf,
     lookupDeprecated,
     lookupDeprecatedReason,
+    mkInputUnionFields,
     msg,
+    possibleInterfaceTypes,
     toGQLWrapper,
   )
 import Data.Morpheus.Types.Internal.Resolving
-  ( Context (..),
-    ResModel,
+  ( ResModel,
     Resolver,
+    ResolverContext (..),
     mkBoolean,
     mkList,
     mkNull,
@@ -81,8 +79,13 @@
   )
 import Data.Semigroup ((<>))
 import Data.Text (pack)
-
-type Result e m a = Resolver QUERY e m a
+import Data.Traversable (traverse)
+import Prelude
+  ( ($),
+    (.),
+    Bool,
+    show,
+  )
 
 class
   ( Monad m,
@@ -91,7 +94,7 @@
   ) =>
   WithSchema m
   where
-  getSchema :: m Schema
+  getSchema :: m (Schema VALID)
 
 instance Monad m => WithSchema (Resolver QUERY e m) where
   getSchema = schema <$> unsafeInternalContext
@@ -99,7 +102,7 @@
 selectType ::
   WithSchema m =>
   TypeName ->
-  m (TypeDefinition ANY)
+  m (TypeDefinition ANY VALID)
 selectType name =
   getSchema
     >>= selectBy (" INTERNAL: INTROSPECTION Type not Found: \"" <> msg name <> "\"") name
@@ -119,13 +122,20 @@
 instance RenderIntrospection Description where
   render = pure . mkString
 
-instance RenderIntrospection TypeKind where
-  render = pure . mkString . pack . show
-
 instance RenderIntrospection a => RenderIntrospection [a] where
   render ls = mkList <$> traverse render ls
 
-instance RenderIntrospection DirectiveDefinition where
+instance RenderIntrospection a => RenderIntrospection (Maybe a) where
+  render (Just value) = render value
+  render Nothing = pure mkNull
+
+instance RenderIntrospection Bool where
+  render = pure . mkBoolean
+
+instance RenderIntrospection TypeKind where
+  render = pure . mkString . GQL.render
+
+instance RenderIntrospection (DirectiveDefinition VALID) where
   render
     DirectiveDefinition
       { directiveDefinitionName,
@@ -145,7 +155,7 @@
 instance RenderIntrospection DirectiveLocation where
   render locations = pure $ mkString (pack $ show locations)
 
-instance RenderIntrospection (TypeDefinition a) where
+instance RenderIntrospection (TypeDefinition cat VALID) where
   render
     TypeDefinition
       { typeName,
@@ -153,44 +163,66 @@
         typeContent
       } = pure $ renderContent typeContent
       where
-        __type :: Monad m => TypeKind -> [(FieldName, Resolver QUERY e m (ResModel QUERY e m))] -> ResModel QUERY e m
+        __type ::
+          Monad m =>
+          TypeKind ->
+          [(FieldName, Resolver QUERY e m (ResModel QUERY e m))] ->
+          ResModel QUERY e m
         __type kind = mkType kind typeName typeDescription
-        renderContent :: Monad m => TypeContent bool a -> ResModel QUERY e m
-        renderContent DataScalar {} = __type SCALAR []
-        renderContent (DataEnum enums) = __type ENUM [("enumValues", render enums)]
+        renderContent ::
+          Monad m =>
+          TypeContent bool a VALID ->
+          ResModel QUERY e m
+        renderContent DataScalar {} = __type KindScalar []
+        renderContent (DataEnum enums) = __type KindEnum [("enumValues", render enums)]
         renderContent (DataInputObject inputFiels) =
           __type
-            INPUT_OBJECT
+            KindInputObject
             [("inputFields", render inputFiels)]
         renderContent DataObject {objectImplements, objectFields} =
           createObjectType typeName typeDescription objectImplements objectFields
         renderContent (DataUnion union) =
           __type
-            UNION
+            KindUnion
             [("possibleTypes", render union)]
         renderContent (DataInputUnion members) =
           __type
-            INPUT_OBJECT
+            KindInputObject
             [ ( "inputFields",
                 render
-                  $ createInputUnionFields typeName
-                  $ filter visibility members
+                  ( mkInputUnionFields typeName $
+                      filter visibility members ::
+                      FieldsDefinition IN VALID
+                  )
               )
             ]
         renderContent (DataInterface fields) =
           __type
-            INTERFACE
+            KindInterface
             [ ("fields", render fields),
-              ("possibleTypes", interfacePossibleTypes typeName)
+              ("possibleTypes", renderPossibleTypes typeName)
             ]
 
-instance RenderIntrospection (UnionMember OUT) where
+instance RenderIntrospection (UnionMember OUT s) where
   render UnionMember {memberName} = selectType memberName >>= render
 
-instance RenderIntrospection (FieldDefinition cat) => RenderIntrospection (FieldsDefinition cat) where
+instance
+  RenderIntrospection (FieldDefinition cat s) =>
+  RenderIntrospection (FieldsDefinition cat s)
+  where
   render = render . filter fieldVisibility . elems
 
-instance RenderIntrospection (FieldDefinition OUT) where
+instance RenderIntrospection (FieldContent TRUE IN VALID) where
+  render = render . defaultInputValue
+
+instance RenderIntrospection (Value VALID) where
+  render Null = pure mkNull
+  render x = pure $ mkString $ GQL.render x
+
+instance
+  RenderIntrospection
+    (FieldDefinition OUT VALID)
+  where
   render FieldDefinition {..} =
     pure
       $ mkObject "__Field"
@@ -201,13 +233,13 @@
         ]
         <> renderDeprecated fieldDirectives
 
-instance RenderIntrospection (FieldContent TRUE OUT) where
+instance RenderIntrospection (FieldContent TRUE OUT VALID) where
   render (FieldArgs args) = render args
 
-instance RenderIntrospection ArgumentsDefinition where
+instance RenderIntrospection (ArgumentsDefinition VALID) where
   render ArgumentsDefinition {arguments} = mkList <$> traverse render (elems arguments)
 
-instance RenderIntrospection (FieldDefinition IN) where
+instance RenderIntrospection (FieldDefinition IN VALID) where
   render FieldDefinition {..} =
     pure $
       mkObject
@@ -215,10 +247,10 @@
         [ renderName fieldName,
           description fieldDescription,
           type' fieldType,
-          defaultValue fieldType (fmap defaultInputValue fieldContent)
+          defaultValue fieldContent
         ]
 
-instance RenderIntrospection DataEnumValue where
+instance RenderIntrospection (DataEnumValue VALID) where
   render DataEnumValue {enumName, enumDescription, enumDirectives} =
     pure $ mkObject "__Field" $
       [ renderName enumName,
@@ -228,7 +260,7 @@
 
 instance RenderIntrospection TypeRef where
   render TypeRef {typeConName, typeWrappers} = do
-    kind <- lookupKind typeConName
+    kind <- kindOf <$> selectType typeConName
     let currentType = mkType kind typeConName Nothing []
     pure $ foldr wrap currentType (toGQLWrapper typeWrappers)
     where
@@ -239,50 +271,30 @@
           [ renderKind (wrapperKind wrapper),
             ("ofType", pure contentType)
           ]
-      wrapperKind ListType = LIST
-      wrapperKind NonNullType = NON_NULL
+      wrapperKind ListType = KindList
+      wrapperKind NonNullType = KindNonNull
 
-interfacePossibleTypes ::
+renderPossibleTypes ::
   (Monad m) =>
   TypeName ->
   Resolver QUERY e m (ResModel QUERY e m)
-interfacePossibleTypes interfaceName =
+renderPossibleTypes name =
   mkList
     <$> ( getSchema
-            >>= sequence
-              . concatMap implements
-              . elems
+            >>= traverse render . possibleInterfaceTypes name
         )
-  where
-    implements typeDef@TypeDefinition {typeContent = DataObject {objectImplements}, ..}
-      | interfaceName `elem` objectImplements = [render typeDef]
-    implements _ = []
 
 renderDeprecated ::
   (Monad m) =>
-  Directives VALID ->
+  Directives s ->
   [(FieldName, Resolver QUERY e m (ResModel QUERY e m))]
 renderDeprecated dirs =
-  [ ("isDeprecated", pure $ mkBoolean (isJust $ lookupDeprecated dirs)),
-    ("deprecationReason", opt (pure . mkString) (lookupDeprecated dirs >>= lookupDeprecatedReason))
+  [ ("isDeprecated", render (isJust $ lookupDeprecated dirs)),
+    ("deprecationReason", render (lookupDeprecated dirs >>= lookupDeprecatedReason))
   ]
 
 description :: Monad m => Maybe Description -> (FieldName, Resolver QUERY e m (ResModel QUERY e m))
-description desc = ("description", opt render desc)
-
-lookupKind :: (Monad m) => TypeName -> Result e m TypeKind
-lookupKind = fmap (renderTypeKind . kindOf) . selectType
-
-renderTypeKind :: AST.TypeKind -> TypeKind
-renderTypeKind AST.KindScalar = SCALAR
-renderTypeKind (AST.KindObject _) = OBJECT
-renderTypeKind AST.KindUnion = UNION
-renderTypeKind AST.KindInputUnion = INPUT_OBJECT
-renderTypeKind AST.KindEnum = ENUM
-renderTypeKind AST.KindInputObject = INPUT_OBJECT
-renderTypeKind AST.KindList = LIST
-renderTypeKind AST.KindNonNull = NON_NULL
-renderTypeKind AST.KindInterface = INTERFACE
+description = ("description",) . render
 
 mkType ::
   (Monad m, RenderIntrospection name) =>
@@ -302,9 +314,14 @@
     )
 
 createObjectType ::
-  Monad m => TypeName -> Maybe Description -> [TypeName] -> FieldsDefinition OUT -> ResModel QUERY e m
+  Monad m =>
+  TypeName ->
+  Maybe Description ->
+  [TypeName] ->
+  FieldsDefinition OUT VALID ->
+  ResModel QUERY e m
 createObjectType name desc interfaces fields =
-  mkType OBJECT name desc [("fields", render fields), ("interfaces", mkList <$> traverse implementedInterface interfaces)]
+  mkType (KindObject Nothing) name desc [("fields", render fields), ("interfaces", mkList <$> traverse implementedInterface interfaces)]
 
 implementedInterface ::
   (Monad m) =>
@@ -317,10 +334,6 @@
     renderContent typeDef@TypeDefinition {typeContent = DataInterface {}} = render typeDef
     renderContent _ = failure ("Type " <> msg name <> " must be an Interface" :: Message)
 
-opt :: Monad m => (a -> Resolver QUERY e m (ResModel QUERY e m)) -> Maybe a -> Resolver QUERY e m (ResModel QUERY e m)
-opt f (Just x) = f x
-opt _ Nothing = pure mkNull
-
 renderName ::
   ( RenderIntrospection name,
     Monad m
@@ -333,70 +346,12 @@
 renderKind = ("kind",) . render
 
 type' :: Monad m => TypeRef -> (FieldName, Resolver QUERY e m (ResModel QUERY e m))
-type' ref = ("type", render ref)
+type' = ("type",) . render
 
 defaultValue ::
   Monad m =>
-  TypeRef ->
-  Maybe (Value RESOLVED) ->
+  Maybe (FieldContent TRUE IN VALID) ->
   ( FieldName,
     Resolver QUERY e m (ResModel QUERY e m)
   )
-defaultValue
-  typeRef
-  value =
-    ( "defaultValue",
-      opt
-        ( fmap
-            (mkString . GQL.render)
-            . fulfill typeRef
-            . Just
-        )
-        value
-    )
-
-fulfill ::
-  WithSchema m =>
-  TypeRef ->
-  Maybe (Value RESOLVED) ->
-  m (Value RESOLVED)
-fulfill TypeRef {typeConName} (Just (Object fields)) =
-  selectType typeConName
-    >>= \case
-      TypeDefinition
-        { typeContent =
-            DataInputObject {inputObjectFields}
-        } ->
-          Object
-            <$> ( traverse
-                    (handleField fields)
-                    (elems inputObjectFields)
-                    >>= fromElems
-                )
-      _ -> failure (msg typeConName <> "is not must be Object")
-fulfill typeRef (Just (List values)) =
-  List <$> traverse (fulfill typeRef . Just) values
-fulfill _ (Just v) = pure v
-fulfill _ Nothing = pure Null
-
-handleField ::
-  WithSchema m =>
-  Object RESOLVED ->
-  FieldDefinition IN ->
-  m (ObjectEntry RESOLVED)
-handleField
-  fields
-  FieldDefinition
-    { fieldName,
-      fieldType,
-      fieldContent = x
-    } =
-    ObjectEntry fieldName
-      <$> fulfill
-        fieldType
-        ( selectOr
-            (fmap defaultInputValue x)
-            (Just . entryValue)
-            fieldName
-            fields
-        )
+defaultValue = ("defaultValue",) . render
diff --git a/src/Data/Morpheus/Schema/DSL.hs b/src/Data/Morpheus/Schema/DSL.hs
--- a/src/Data/Morpheus/Schema/DSL.hs
+++ b/src/Data/Morpheus/Schema/DSL.hs
@@ -3,6 +3,7 @@
 {-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE RecordWildCards #-}
 {-# LANGUAGE TemplateHaskell #-}
 
 module Data.Morpheus.Schema.DSL (dsl) where
@@ -11,11 +12,11 @@
   ( gqlWarnings,
     renderGQLErrors,
   )
-import Data.Morpheus.Parsing.Document.TypeSystem (parseSchema)
-import Data.Morpheus.Types.Internal.AST (ANY, TypeDefinition)
+import Data.Morpheus.Parsing.Document.TypeSystem
+  ( parseSchema,
+  )
 import Data.Morpheus.Types.Internal.Resolving
-  ( Eventless,
-    Result (..),
+  ( Result (..),
   )
 import Data.Text
   ( Text,
@@ -37,7 +38,6 @@
       error $ things ++ " are not supported by the GraphQL QuasiQuoter"
 
 dslExpression :: Text -> Q Exp
-dslExpression doc = case (parseSchema doc :: Eventless [TypeDefinition ANY]) of
+dslExpression doc = case parseSchema doc of
   Failure errors -> fail (renderGQLErrors errors)
-  Success {result, warnings} ->
-    gqlWarnings warnings >> [|result|]
+  Success {result, warnings} -> gqlWarnings warnings >> [|result|]
diff --git a/src/Data/Morpheus/Schema/Directives.hs b/src/Data/Morpheus/Schema/Directives.hs
deleted file mode 100644
--- a/src/Data/Morpheus/Schema/Directives.hs
+++ /dev/null
@@ -1,43 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-
-module Data.Morpheus.Schema.Directives (defaultDirectives) where
-
-import Data.Morpheus.Internal.Utils
-  ( singleton,
-  )
-import Data.Morpheus.Types.Internal.AST
-  ( ArgumentsDefinition (..),
-    DirectiveDefinition (..),
-    DirectiveLocation (..),
-    TypeWrapper (..),
-    mkField,
-  )
-
-defaultDirectives :: [DirectiveDefinition]
-defaultDirectives =
-  [ DirectiveDefinition
-      { directiveDefinitionName = "skip",
-        directiveDefinitionDescription = Just "Directs the executor to skip this field or fragment when the `if` argument is true.",
-        directiveDefinitionLocations = [FIELD, FRAGMENT_SPREAD, INLINE_FRAGMENT],
-        directiveDefinitionArgs = argumentsIf
-      },
-    DirectiveDefinition
-      { directiveDefinitionName = "include",
-        directiveDefinitionDescription = Just "Directs the executor to include this field or fragment only when the `if` argument is true.",
-        directiveDefinitionLocations = [FIELD, FRAGMENT_SPREAD, INLINE_FRAGMENT],
-        directiveDefinitionArgs = argumentsIf
-      },
-    DirectiveDefinition
-      { directiveDefinitionName = "deprecated",
-        directiveDefinitionDescription = Just "Marks an element of a GraphQL schema as no longer supported.",
-        directiveDefinitionLocations = [FIELD_DEFINITION, ENUM_VALUE],
-        directiveDefinitionArgs =
-          singleton $
-            mkField
-              "reason"
-              ([TypeMaybe], "String")
-      }
-  ]
-
-argumentsIf :: ArgumentsDefinition
-argumentsIf = singleton $ mkField "if" ([], "Boolean")
diff --git a/src/Data/Morpheus/Schema/Schema.hs b/src/Data/Morpheus/Schema/Schema.hs
--- a/src/Data/Morpheus/Schema/Schema.hs
+++ b/src/Data/Morpheus/Schema/Schema.hs
@@ -3,80 +3,61 @@
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE RecordWildCards #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TemplateHaskell #-}
 {-# LANGUAGE TypeFamilies #-}
 {-# LANGUAGE TypeOperators #-}
 
 module Data.Morpheus.Schema.Schema
-  ( withSystemTypes,
-    systemTypes,
+  ( internalSchema,
   )
 where
 
 -- MORPHEUS
 
-import Data.Morpheus.Internal.Utils
-  ( (<:>),
-    singleton,
-  )
 import Data.Morpheus.Schema.DSL (dsl)
 import Data.Morpheus.Types.Internal.AST
-  ( ANY,
-    DataFingerprint (..),
-    FieldsDefinition,
-    Message,
-    OUT,
+  ( DataFingerprint (..),
     Schema (..),
-    TypeContent (..),
     TypeDefinition (..),
-    TypeUpdater,
-    TypeWrapper (..),
-    createArgument,
-    insertType,
     internalFingerprint,
-    mkField,
-    mkObjectField,
-    unsafeFromFields,
   )
-import Data.Morpheus.Types.Internal.Resolving
-  ( failure,
-    resolveUpdates,
-  )
 
-withSystemTypes :: TypeUpdater
-withSystemTypes s@Schema {query = q@TypeDefinition {typeContent = DataObject inter fields}} =
-  ( do
-      fs <- fields <:> hiddenFields
-      pure $ s {query = q {typeContent = DataObject inter fs}}
-  )
-    >>= (`resolveUpdates` map (insertType . internalType) systemTypes)
-withSystemTypes _ = failure ("Query must be an Object Type" :: Message)
-
-hiddenFields :: FieldsDefinition OUT
-hiddenFields =
-  unsafeFromFields
-    [ mkObjectField
-        (singleton (createArgument "name" ([], "String")))
-        "__type"
-        ([TypeMaybe], "__Type"),
-      mkField
-        "__schema"
-        ([], "__Schema")
-    ]
+toInternalSchema :: Schema s -> Schema s
+toInternalSchema Schema {..} = Schema {types = fmap toInternalType types, ..}
 
-internalType :: TypeDefinition a -> TypeDefinition a
-internalType
+toInternalType :: TypeDefinition a s -> TypeDefinition a s
+toInternalType
   tyDef@TypeDefinition
     { typeFingerprint = DataFingerprint name xs
     } =
     tyDef {typeFingerprint = internalFingerprint name xs}
 
-systemTypes :: [TypeDefinition ANY]
-systemTypes =
-  [dsl|
+internalSchema :: Schema s
+internalSchema =
+  toInternalSchema
+    [dsl|
 
-# default scalars
+"""
+Directs the executor to skip this field or fragment when the `if` argument is true.
+"""
+directive @skip(if: Boolean!) 
+  on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
+
+"""
+Directs the executor to include this field or fragment only when the `if` argument is true.
+"""
+directive @include(if: Boolean!) 
+  on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
+
+"""
+Marks an element of a GraphQL schema as no longer supported.
+"""
+directive @deprecated(reason: String) 
+  on FIELD_DEFINITION | ENUM_VALUE
+
+
 scalar Boolean
 scalar Int
 scalar Float
@@ -175,6 +156,11 @@
   INPUT_OBJECT
   LIST
   NON_NULL
+}
+
+type Query {
+  __type(name: String!): __Type
+  __schema: __Schema!
 }
 
 |]
diff --git a/src/Data/Morpheus/Schema/SchemaAPI.hs b/src/Data/Morpheus/Schema/SchemaAPI.hs
--- a/src/Data/Morpheus/Schema/SchemaAPI.hs
+++ b/src/Data/Morpheus/Schema/SchemaAPI.hs
@@ -3,7 +3,6 @@
 {-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE TypeOperators #-}
 
 module Data.Morpheus.Schema.SchemaAPI
   ( withSystemFields,
@@ -12,7 +11,7 @@
 
 -- MORPHEUS
 import Data.Morpheus.Internal.Utils
-  ( (<:>),
+  ( (<.>),
     elems,
     empty,
     selectOr,
@@ -21,20 +20,19 @@
   ( createObjectType,
     render,
   )
-import Data.Morpheus.Schema.Directives
-  ( defaultDirectives,
-  )
 import Data.Morpheus.Schema.Schema
   (
   )
 import Data.Morpheus.Types.Internal.AST
   ( Argument (..),
-    OUT,
+    FieldName,
+    OBJECT,
     QUERY,
     ScalarValue (..),
     Schema (..),
     TypeDefinition (..),
     TypeName (..),
+    VALID,
     Value (..),
   )
 import Data.Morpheus.Types.Internal.Resolving
@@ -49,35 +47,28 @@
   )
 
 resolveTypes ::
-  Monad m => Schema -> Resolver QUERY e m (ResModel QUERY e m)
+  Monad m => Schema VALID -> Resolver QUERY e m (ResModel QUERY e m)
 resolveTypes schema = mkList <$> traverse render (elems schema)
 
 renderOperation ::
-  Monad m => Maybe (TypeDefinition OUT) -> Resolver QUERY e m (ResModel QUERY e m)
+  Monad m =>
+  Maybe (TypeDefinition OBJECT VALID) ->
+  Resolver QUERY e m (ResModel QUERY e m)
 renderOperation (Just TypeDefinition {typeName}) = pure $ createObjectType typeName Nothing [] empty
 renderOperation Nothing = pure mkNull
 
 findType ::
   Monad m =>
   TypeName ->
-  Schema ->
+  Schema VALID ->
   Resolver QUERY e m (ResModel QUERY e m)
 findType = selectOr (pure mkNull) render
 
-renderDirectives ::
-  Monad m =>
-  Resolver QUERY e m (ResModel QUERY e m)
-renderDirectives =
-  mkList
-    <$> traverse
-      render
-      defaultDirectives
-
 schemaResolver ::
   Monad m =>
-  Schema ->
+  Schema VALID ->
   Resolver QUERY e m (ResModel QUERY e m)
-schemaResolver schema@Schema {query, mutation, subscription} =
+schemaResolver schema@Schema {query, mutation, subscription, directiveDefinitions} =
   pure $
     mkObject
       "__Schema"
@@ -85,10 +76,10 @@
         ("queryType", renderOperation (Just query)),
         ("mutationType", renderOperation mutation),
         ("subscriptionType", renderOperation subscription),
-        ("directives", renderDirectives)
+        ("directives", render directiveDefinitions)
       ]
 
-schemaAPI :: Monad m => Schema -> ResModel QUERY e m
+schemaAPI :: Monad m => Schema VALID -> ResModel QUERY e m
 schemaAPI schema =
   mkObject
     "Root"
@@ -96,7 +87,7 @@
       ("__schema", schemaResolver schema)
     ]
   where
-    typeResolver = selectOr (pure mkNull) handleArg "name"
+    typeResolver = selectOr (pure mkNull) handleArg ("name" :: FieldName)
       where
         handleArg
           Argument
@@ -104,10 +95,14 @@
             } = findType (TypeName typename) schema
         handleArg _ = pure mkNull
 
-withSystemFields :: Monad m => Schema -> RootResModel e m -> ResultT e' m (RootResModel e m)
+withSystemFields ::
+  Monad m =>
+  Schema VALID ->
+  RootResModel e m ->
+  ResultT e' m (RootResModel e m)
 withSystemFields schema RootResModel {query, ..} =
   pure $
     RootResModel
-      { query = query >>= (<:> schemaAPI schema),
+      { query = query >>= (<.> schemaAPI schema),
         ..
       }
diff --git a/src/Data/Morpheus/Schema/TypeKind.hs b/src/Data/Morpheus/Schema/TypeKind.hs
deleted file mode 100644
--- a/src/Data/Morpheus/Schema/TypeKind.hs
+++ /dev/null
@@ -1,22 +0,0 @@
-{-# LANGUAGE DeriveAnyClass #-}
-{-# LANGUAGE DeriveGeneric #-}
-{-# LANGUAGE TypeFamilies #-}
-
-module Data.Morpheus.Schema.TypeKind
-  ( TypeKind (..),
-  )
-where
-
-import Data.Aeson (FromJSON (..))
-import GHC.Generics
-
-data TypeKind
-  = SCALAR
-  | OBJECT
-  | INTERFACE
-  | UNION
-  | ENUM
-  | INPUT_OBJECT
-  | LIST
-  | NON_NULL
-  deriving (Eq, Generic, FromJSON, Show)
diff --git a/src/Data/Morpheus/Types/GQLScalar.hs b/src/Data/Morpheus/Types/GQLScalar.hs
--- a/src/Data/Morpheus/Types/GQLScalar.hs
+++ b/src/Data/Morpheus/Types/GQLScalar.hs
@@ -2,6 +2,7 @@
 {-# LANGUAGE GADTs #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Types.GQLScalar
   ( GQLScalar (..),
@@ -11,8 +12,9 @@
   )
 where
 
-import Control.Monad.Fail (MonadFail)
+import Control.Monad.Fail (MonadFail (..))
 import qualified Data.Aeson as A
+import Data.Either (Either (..), either)
 import Data.Morpheus.Types.Internal.AST
   ( ScalarDefinition (..),
     ScalarValue (..),
@@ -22,6 +24,17 @@
   )
 import Data.Proxy (Proxy (..))
 import Data.Text (Text, unpack)
+import Prelude
+  ( ($),
+    (.),
+    Bool,
+    Float,
+    Int,
+    Monad,
+    fromInteger,
+    pure,
+    toInteger,
+  )
 
 toScalar :: ValidValue -> Either Text ScalarValue
 toScalar (Scalar x) = pure x
@@ -53,7 +66,7 @@
       validator value = do
         scalarValue' <- toScalar value
         (_ :: a) <- parseValue scalarValue'
-        return value
+        pure value
 
 instance GQLScalar Text where
   parseValue (String x) = pure x
diff --git a/src/Data/Morpheus/Types/ID.hs b/src/Data/Morpheus/Types/ID.hs
--- a/src/Data/Morpheus/Types/ID.hs
+++ b/src/Data/Morpheus/Types/ID.hs
@@ -1,6 +1,7 @@
 {-# LANGUAGE DeriveGeneric #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Types.ID
   ( ID (..),
@@ -21,6 +22,13 @@
     pack,
   )
 import GHC.Generics (Generic)
+import Prelude
+  ( ($),
+    Either (..),
+    Eq,
+    Show (..),
+    pure,
+  )
 
 -- | default GraphQL type,
 -- parses only 'String' and 'Int' values,
@@ -28,12 +36,12 @@
 newtype ID = ID
   { unpackID :: Text
   }
-  deriving (Show, Generic)
+  deriving (Show, Generic, Eq)
 
 instance GQLScalar ID where
-  parseValue (Int x) = return (ID $ pack $ show x)
-  parseValue (String x) = return (ID x)
-  parseValue _ = Left ""
+  parseValue (Int x) = pure (ID $ pack $ show x)
+  parseValue (String x) = pure (ID x)
+  parseValue _ = Left "ID can only be String or number"
   serialize (ID x) = String x
 
 instance ToJSON ID where
diff --git a/src/Data/Morpheus/Types/IO.hs b/src/Data/Morpheus/Types/IO.hs
--- a/src/Data/Morpheus/Types/IO.hs
+++ b/src/Data/Morpheus/Types/IO.hs
@@ -1,8 +1,10 @@
 {-# LANGUAGE DeriveAnyClass #-}
 {-# LANGUAGE DeriveGeneric #-}
 {-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Types.IO
   ( GQLRequest (..),
@@ -13,6 +15,10 @@
   )
 where
 
+-- MORPHEUS
+
+import Control.Applicative (Applicative (..))
+import Control.Monad.Fail (fail)
 import Data.Aeson
   ( (.:?),
     (.=),
@@ -40,10 +46,12 @@
     fromStrict,
     toStrict,
   )
+import Data.Either (Either (..))
+import Data.Functor ((<$>), fmap)
 import qualified Data.HashMap.Lazy as LH
   ( toList,
   )
--- MORPHEUS
+import Data.Maybe (Maybe (..))
 import Data.Morpheus.Error.Utils (badRequestError)
 import Data.Morpheus.Types.Internal.AST
   ( FieldName,
@@ -66,27 +74,31 @@
     encodeUtf8,
   )
 import GHC.Generics (Generic)
+import Prelude (($), (.), Show, String)
 
 decodeNoDup :: Failure String m => LB.ByteString -> m GQLRequest
 decodeNoDup str = case eitherDecodeWith jsonNoDup ifromJSON str of
   Left (path, x) -> failure $ formatError path x
   Right value -> pure value
 
-class MapAPI a where
-  mapAPI :: Applicative m => (GQLRequest -> m GQLResponse) -> a -> m a
+class MapAPI a b where
+  mapAPI :: Applicative m => (GQLRequest -> m GQLResponse) -> a -> m b
 
-instance MapAPI LB.ByteString where
+instance MapAPI GQLRequest GQLResponse where
+  mapAPI f = f
+
+instance MapAPI LB.ByteString LB.ByteString where
   mapAPI api request = case decodeNoDup request of
     Left aesonError -> pure $ badRequestError aesonError
     Right req -> encode <$> api req
 
-instance MapAPI LT.Text where
+instance MapAPI LT.Text LT.Text where
   mapAPI api = fmap decodeUtf8 . mapAPI api . encodeUtf8
 
-instance MapAPI ByteString where
+instance MapAPI ByteString ByteString where
   mapAPI api = fmap LB.toStrict . mapAPI api . LB.fromStrict
 
-instance MapAPI Text where
+instance MapAPI Text Text where
   mapAPI api = fmap LT.toStrict . mapAPI api . LT.fromStrict
 
 renderResponse :: Result e ValidValue -> GQLResponse
diff --git a/src/Data/Morpheus/Types/Internal/AST.hs b/src/Data/Morpheus/Types/Internal/AST.hs
--- a/src/Data/Morpheus/Types/Internal/AST.hs
+++ b/src/Data/Morpheus/Types/Internal/AST.hs
@@ -2,6 +2,7 @@
 {-# LANGUAGE DuplicateRecordFields #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Types.Internal.AST
   ( -- BASE
@@ -12,10 +13,9 @@
     FieldName (..),
     Description,
     Stage,
-    RESOLVED,
+    CONST,
     VALID,
     RAW,
-    VALIDATION_MODE (..),
     -- VALUE
     Value (..),
     ScalarValue (..),
@@ -47,7 +47,6 @@
     VariableDefinitions,
     DefaultValue,
     getOperationName,
-    getOperationDataType,
     -- DSL
     ScalarDefinition (..),
     DataEnum,
@@ -71,17 +70,14 @@
     MUTATION,
     SUBSCRIPTION,
     Directive (..),
-    TypeUpdater,
     ConsD (..),
     TypeCategory,
     DataInputUnion,
     VariableContent (..),
     TypeLib,
     initTypeLib,
-    defineType,
-    isFieldNullable,
     kindOf,
-    toNullableField,
+    toNullable,
     toListField,
     isObject,
     isInput,
@@ -91,19 +87,14 @@
     isWeaker,
     isSubscription,
     isOutputObject,
-    sysTypes,
-    isSystemTypeName,
+    isNotSystemTypeName,
     isEntNode,
-    createField,
-    createArgument,
-    createEnumType,
+    mkEnumContent,
     createScalarType,
-    createType,
-    createUnionType,
-    createAlias,
-    createInputUnionFields,
+    mkUnionContent,
+    mkTypeRef,
+    mkInputUnionFields,
     fieldVisibility,
-    createEnumValue,
     insertType,
     lookupDeprecated,
     lookupDeprecatedReason,
@@ -113,9 +104,8 @@
     -- LOCAL
     GQLQuery (..),
     Variables,
-    isNullableWrapper,
     unsafeFromFields,
-    OrderedMap,
+    OrdMap,
     GQLError (..),
     GQLErrors,
     ObjectEntry (..),
@@ -126,8 +116,10 @@
     ANY,
     IN,
     OUT,
-    FromAny (..),
-    ToAny (..),
+    OBJECT,
+    IMPLEMENTABLE,
+    fromAny,
+    toAny,
     TRUE,
     FALSE,
     TypeName (..),
@@ -147,30 +139,59 @@
     DirectiveLocation (..),
     FieldContent (..),
     fieldContentArgs,
-    mkField,
+    mkInputValue,
+    mkType,
     TypeNameTH (..),
     isOutput,
     mkObjectField,
     UnionMember (..),
     mkUnionMember,
+    RawTypeDefinition (..),
+    RootOperationTypeDefinition (..),
+    UnionSelection,
+    SchemaDefinition (..),
+    buildSchema,
+    InternalError (..),
+    ValidationError (..),
+    msgInternal,
+    getOperationDataType,
+    Typed (Typed),
+    typed,
+    untyped,
+    msgValidation,
+    withPosition,
+    ValidationErrors,
+    toGQLError,
+    ELEM,
+    LEAF,
+    REQURE_IMPLEMENTABLE,
+    ToCategory (..),
+    FromCategory (..),
+    possibleTypes,
+    possibleInterfaceTypes,
   )
 where
 
 import Data.HashMap.Lazy (HashMap)
 -- Morpheus
+
 import Data.Morpheus.Types.Internal.AST.Base
 import Data.Morpheus.Types.Internal.AST.DirectiveLocation (DirectiveLocation (..))
-import Data.Morpheus.Types.Internal.AST.OrderedMap
+import Data.Morpheus.Types.Internal.AST.Fields
+import Data.Morpheus.Types.Internal.AST.OrdMap
 import Data.Morpheus.Types.Internal.AST.Selection
+import Data.Morpheus.Types.Internal.AST.Stage
 import Data.Morpheus.Types.Internal.AST.TH
+import Data.Morpheus.Types.Internal.AST.TypeCategory
 import Data.Morpheus.Types.Internal.AST.TypeSystem
 import Data.Morpheus.Types.Internal.AST.Value
 import Language.Haskell.TH.Syntax (Lift)
+import Prelude (Show)
 
 type Variables = HashMap FieldName ResolvedValue
 
 data GQLQuery = GQLQuery
-  { fragments :: Fragments,
+  { fragments :: Fragments RAW,
     operation :: Operation RAW,
     inputVariables :: [(FieldName, ResolvedValue)]
   }
diff --git a/src/Data/Morpheus/Types/Internal/AST/Base.hs b/src/Data/Morpheus/Types/Internal/AST/Base.hs
--- a/src/Data/Morpheus/Types/Internal/AST/Base.hs
+++ b/src/Data/Morpheus/Types/Internal/AST/Base.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE DataKinds #-}
 {-# LANGUAGE DeriveAnyClass #-}
 {-# LANGUAGE DeriveGeneric #-}
@@ -8,6 +9,8 @@
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Types.Internal.AST.Base
   ( Ref (..),
@@ -15,13 +18,8 @@
     Message (..),
     FieldName (..),
     Description,
-    VALID,
-    RAW,
     TypeWrapper (..),
-    Stage (..),
-    RESOLVED,
     TypeRef (..),
-    VALIDATION_MODE (..),
     OperationType (..),
     QUERY,
     MUTATION,
@@ -33,15 +31,13 @@
     anonymousRef,
     toHSWrappers,
     toGQLWrapper,
-    sysTypes,
-    isNullable,
+    Nullable (..),
     isWeaker,
     isSubscription,
     isOutputObject,
-    isSystemTypeName,
+    isNotSystemTypeName,
     isObject,
     isInput,
-    isNullableWrapper,
     sysFields,
     hsTypeName,
     toOperationType,
@@ -60,6 +56,14 @@
     convertToJSONName,
     convertToHaskellName,
     isOutput,
+    mkTypeRef,
+    InternalError (..),
+    msgInternal,
+    ValidationError (..),
+    msgValidation,
+    ValidationErrors,
+    withPosition,
+    toGQLError,
   )
 where
 
@@ -70,16 +74,43 @@
     encode,
   )
 import Data.ByteString.Lazy.Char8 (ByteString, unpack)
+import Data.Char (toLower)
 import Data.Hashable (Hashable)
+import Data.Maybe (Maybe (..), maybeToList)
 import Data.Morpheus.Rendering.RenderGQL (RenderGQL (..))
 import Data.Semigroup (Semigroup (..))
-import Data.String (IsString)
+import Data.String (IsString (..))
 import Data.Text (Text, intercalate, pack)
 import qualified Data.Text as T
 import GHC.Generics (Generic)
--- import Instances.TH.Lift ()
-import Language.Haskell.TH (stringE)
-import Language.Haskell.TH.Syntax (Lift (..))
+import Language.Haskell.TH
+  ( ExpQ,
+    stringE,
+  )
+import Language.Haskell.TH.Syntax
+  ( Lift (..),
+    Q,
+    TExp,
+    unsafeTExpCoerce,
+  )
+import Prelude
+  ( ($),
+    (&&),
+    (.),
+    Bool (..),
+    Eq (..),
+    Functor (..),
+    Int,
+    Ord (..),
+    Show (..),
+    String,
+    elem,
+    fst,
+    id,
+    not,
+    notElem,
+    otherwise,
+  )
 
 type TRUE = 'True
 
@@ -96,13 +127,65 @@
     (Show, Eq, Ord, IsString, Semigroup, Hashable, FromJSON, ToJSON)
 
 instance Lift Message where
-  lift = stringE . T.unpack . readMessage
+  lift = liftString . readMessage
 
+#if MIN_VERSION_template_haskell(2,16,0)
+  liftTyped = liftTypedString . readMessage
+#endif
+
+newtype InternalError = InternalError
+  { readInternalError :: Text
+  }
+  deriving
+    (Generic)
+  deriving newtype
+    (Show, Eq, Ord, IsString, Semigroup, Hashable, FromJSON, ToJSON)
+
+data ValidationError = ValidationError
+  { validationMessage :: Message,
+    validationLocations :: [Position]
+  }
+  deriving (Show)
+
+instance IsString ValidationError where
+  fromString = (`ValidationError` []) . msg
+
+instance Semigroup ValidationError where
+  ValidationError m1 p1 <> ValidationError m2 p2 =
+    ValidationError (m1 <> m2) (p1 <> p2)
+
+withPosition :: Maybe Position -> ValidationError -> ValidationError
+withPosition pos (ValidationError m ps) = ValidationError m (ps <> maybeToList pos)
+
+type ValidationErrors = [ValidationError]
+
+toGQLError :: ValidationError -> GQLError
+toGQLError (ValidationError m p) = GQLError m p
+
+-- instance Lift InternalError where
+--   lift = liftString . readInternalError
+
+-- #if MIN_VERSION_template_haskell(2,16,0)
+--   liftTyped = liftTypedString . readInternalError
+-- #endif
+
+msgInternal :: (Msg a) => a -> InternalError
+msgInternal = InternalError . readMessage . msg
+
+msgValidation :: (Msg a) => a -> ValidationError
+msgValidation = (`ValidationError` []) . msg
+
 class Msg a where
   msg :: a -> Message
   msgSepBy :: Text -> [a] -> Message
-  msgSepBy t = Message . intercalate t . map (readMessage . msg)
+  msgSepBy t = Message . intercalate t . fmap (readMessage . msg)
 
+instance Msg Message where
+  msg = id
+
+instance Msg InternalError where
+  msg = Message . ("Internal Error! " <>) . readInternalError
+
 instance Msg String where
   msg = Message . pack
 
@@ -115,6 +198,10 @@
 instance Msg Value where
   msg = msg . encode
 
+class Nullable a where
+  isNullable :: a -> Bool
+  toNullable :: a -> a
+
 -- FieldName : lower case names
 newtype FieldName = FieldName {readName :: Text}
   deriving
@@ -123,8 +210,12 @@
     (Show, Ord, Eq, IsString, Hashable, Semigroup, FromJSON, ToJSON)
 
 instance Lift FieldName where
-  lift = stringE . T.unpack . readName
+  lift = liftString . readName
 
+#if MIN_VERSION_template_haskell(2,16,0)
+  liftTyped = liftTypedString . readName
+#endif
+
 instance Msg FieldName where
   msg FieldName {readName} = Message $ "\"" <> readName <> "\""
 
@@ -132,7 +223,7 @@
   render = readName
 
 intercalateName :: FieldName -> [FieldName] -> FieldName
-intercalateName (FieldName x) = FieldName . intercalate x . map readName
+intercalateName (FieldName x) = FieldName . intercalate x . fmap readName
 
 toFieldName :: TypeName -> FieldName
 toFieldName = FieldName . readTypeName
@@ -145,8 +236,18 @@
     (Show, Ord, Eq, IsString, Hashable, Semigroup, FromJSON, ToJSON)
 
 instance Lift TypeName where
-  lift = stringE . T.unpack . readTypeName
+  lift = liftString . readTypeName
 
+#if MIN_VERSION_template_haskell(2,16,0)
+  liftTyped = liftTypedString . readTypeName
+#endif
+
+liftTypedString :: IsString a => Token -> Q (TExp a)
+liftTypedString = unsafeTExpCoerce . stringE . T.unpack
+
+liftString :: Token -> ExpQ
+liftString = stringE . T.unpack
+
 instance Msg TypeName where
   msg TypeName {readTypeName} = Message $ "\"" <> readTypeName <> "\""
 
@@ -156,8 +257,6 @@
 -- Description
 type Description = Text
 
-data Stage = RAW | RESOLVED | VALID
-
 data Position = Position
   { line :: Int,
     column :: Int
@@ -177,17 +276,6 @@
 
 type GQLErrors = [GQLError]
 
-type RAW = 'RAW
-
-type RESOLVED = 'RESOLVED
-
-type VALID = 'VALID
-
-data VALIDATION_MODE
-  = WITHOUT_VARIABLES
-  | FULL_VALIDATION
-  deriving (Eq, Show)
-
 data DataFingerprint = DataFingerprint TypeName [String] deriving (Show, Eq, Ord, Lift)
 
 internalFingerprint :: TypeName -> [String] -> DataFingerprint
@@ -197,8 +285,16 @@
   = Query
   | Subscription
   | Mutation
-  deriving (Show, Eq, Lift)
+  deriving (Show, Eq, Lift, Generic, Hashable)
 
+instance RenderGQL OperationType where
+  render = pack . fmap toLower . show
+
+instance Msg OperationType where
+  msg Query = msg ("query" :: TypeName)
+  msg Mutation = msg ("mutation" :: TypeName)
+  msg Subscription = msg ("subscription" :: TypeName)
+
 type QUERY = 'Query
 
 type MUTATION = 'Mutation
@@ -236,9 +332,14 @@
   }
   deriving (Show, Eq, Lift)
 
-isNullable :: TypeRef -> Bool
-isNullable TypeRef {typeWrappers = typeWrappers} = isNullableWrapper typeWrappers
+mkTypeRef :: TypeName -> TypeRef
+mkTypeRef typeConName =
+  TypeRef {typeConName, typeWrappers = [], typeArgs = Nothing}
 
+instance Nullable TypeRef where
+  isNullable = isNullable . typeWrappers
+  toNullable TypeRef {..} = TypeRef {typeWrappers = toNullable typeWrappers, ..}
+
 instance RenderGQL TypeRef where
   render TypeRef {typeConName, typeWrappers} = renderWrapped typeConName typeWrappers
 
@@ -259,6 +360,17 @@
   | KindInterface
   deriving (Eq, Show, Lift)
 
+instance RenderGQL TypeKind where
+  render KindScalar = "SCALAR"
+  render KindObject {} = "OBJECT"
+  render KindUnion = "UNION"
+  render KindInputUnion = "INPUT_OBJECT"
+  render KindEnum = "ENUM"
+  render KindInputObject = "INPUT_OBJECT"
+  render KindList = "LIST"
+  render KindNonNull = "NON_NULL"
+  render KindInterface = "INTERFACE"
+
 isSubscription :: TypeKind -> Bool
 isSubscription (KindObject (Just Subscription)) = True
 isSubscription _ = False
@@ -296,9 +408,11 @@
   | NonNullType
   deriving (Show, Lift)
 
-isNullableWrapper :: [TypeWrapper] -> Bool
-isNullableWrapper (TypeMaybe : _) = True
-isNullableWrapper _ = False
+instance Nullable [TypeWrapper] where
+  isNullable (TypeMaybe : _) = True
+  isNullable _ = False
+  toNullable (TypeMaybe : xs) = TypeMaybe : xs
+  toNullable xs = TypeMaybe : xs
 
 isWeaker :: [TypeWrapper] -> [TypeWrapper] -> Bool
 isWeaker (TypeMaybe : xs1) (TypeMaybe : xs2) = isWeaker xs1 xs2
@@ -328,25 +442,24 @@
     showGQLWrapper (ListType : xs) = "[" <> showGQLWrapper xs <> "]"
     showGQLWrapper (NonNullType : xs) = showGQLWrapper xs <> "!"
 
-isSystemTypeName :: TypeName -> Bool
-isSystemTypeName = (`elem` sysTypes)
-
-sysTypes :: [TypeName]
-sysTypes =
-  [ "__Schema",
-    "__Type",
-    "__Directive",
-    "__TypeKind",
-    "__Field",
-    "__DirectiveLocation",
-    "__InputValue",
-    "__EnumValue",
-    "String",
-    "Float",
-    "Int",
-    "Boolean",
-    "ID"
-  ]
+isNotSystemTypeName :: TypeName -> Bool
+isNotSystemTypeName =
+  ( `notElem`
+      [ "__Schema",
+        "__Type",
+        "__Directive",
+        "__TypeKind",
+        "__Field",
+        "__DirectiveLocation",
+        "__InputValue",
+        "__EnumValue",
+        "String",
+        "Float",
+        "Int",
+        "Boolean",
+        "ID"
+      ]
+  )
 
 sysFields :: [FieldName]
 sysFields = ["__typename", "__schema", "__type"]
diff --git a/src/Data/Morpheus/Types/Internal/AST/DirectiveLocation.hs b/src/Data/Morpheus/Types/Internal/AST/DirectiveLocation.hs
--- a/src/Data/Morpheus/Types/Internal/AST/DirectiveLocation.hs
+++ b/src/Data/Morpheus/Types/Internal/AST/DirectiveLocation.hs
@@ -1,9 +1,14 @@
 {-# LANGUAGE DeriveLift #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
-module Data.Morpheus.Types.Internal.AST.DirectiveLocation (DirectiveLocation (..)) where
+module Data.Morpheus.Types.Internal.AST.DirectiveLocation
+  ( DirectiveLocation (..),
+  )
+where
 
 import Data.Morpheus.Types.Internal.AST.Base (Msg (..))
 import Language.Haskell.TH.Syntax (Lift)
+import Prelude ((.), Eq, Show (..))
 
 data DirectiveLocation
   = QUERY
diff --git a/src/Data/Morpheus/Types/Internal/AST/Fields.hs b/src/Data/Morpheus/Types/Internal/AST/Fields.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Morpheus/Types/Internal/AST/Fields.hs
@@ -0,0 +1,368 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE DeriveLift #-}
+{-# LANGUAGE DeriveTraversable #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE NamedFieldPuns #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE PolyKinds #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE StandaloneDeriving #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+module Data.Morpheus.Types.Internal.AST.Fields
+  ( Arguments,
+    Argument (..),
+    ArgumentDefinition,
+    ArgumentsDefinition (..),
+    FieldDefinition (..),
+    FieldsDefinition,
+    Fields (..),
+    FieldContent (..),
+    InputFieldsDefinition,
+    DirectiveDefinitions,
+    DirectiveDefinition (..),
+    Directives,
+    Directive (..),
+    fieldVisibility,
+    toListField,
+    lookupDeprecated,
+    lookupDeprecatedReason,
+    unsafeFromFields,
+    fieldsToArguments,
+    fieldContentArgs,
+    mkInputValue,
+    mkObjectField,
+  )
+where
+
+-- MORPHEUS
+
+import Data.Foldable (Foldable)
+import Data.Functor ((<$>), Functor (..))
+import Data.List (find)
+import Data.Maybe (Maybe (..))
+import Data.Morpheus.Error.NameCollision
+  ( NameCollision (..),
+  )
+import Data.Morpheus.Internal.Utils
+  ( Collection (..),
+    KeyOf (..),
+    Listable (..),
+    Merge (..),
+    Selectable (..),
+    elems,
+  )
+import Data.Morpheus.Rendering.RenderGQL
+  ( RenderGQL (..),
+    renderArguments,
+    renderEntry,
+    renderObject,
+  )
+import Data.Morpheus.Types.Internal.AST.Base
+  ( Description,
+    FieldName,
+    FieldName (..),
+    Msg (..),
+    Nullable (..),
+    Position,
+    TRUE,
+    TypeName,
+    TypeRef (..),
+    TypeWrapper (..),
+    ValidationError (..),
+    msgValidation,
+    sysFields,
+  )
+import Data.Morpheus.Types.Internal.AST.DirectiveLocation (DirectiveLocation)
+import Data.Morpheus.Types.Internal.AST.OrdMap
+  ( OrdMap,
+    unsafeFromValues,
+  )
+import Data.Morpheus.Types.Internal.AST.Stage
+  ( Stage,
+  )
+import Data.Morpheus.Types.Internal.AST.TypeCategory
+  ( ANY,
+    ELEM,
+    IN,
+    OUT,
+    ToCategory (..),
+    TypeCategory,
+    toAny,
+  )
+import Data.Morpheus.Types.Internal.AST.Value
+  ( ScalarValue (..),
+    Value (..),
+  )
+import Data.Semigroup (Semigroup ((<>)))
+import Data.Traversable (Traversable)
+import Instances.TH.Lift ()
+import Language.Haskell.TH.Syntax (Lift (..))
+import Prelude
+  ( ($),
+    (.),
+    Bool (..),
+    Eq,
+    Show,
+    filter,
+    notElem,
+  )
+
+-- scalar
+------------------------------------------------------------------
+data Argument (valid :: Stage) = Argument
+  { argumentName :: FieldName,
+    argumentPosition :: Position,
+    argumentValue :: Value valid
+  }
+  deriving (Show, Eq, Lift)
+
+instance KeyOf FieldName (Argument stage) where
+  keyOf = argumentName
+
+instance RenderGQL (Argument s) where
+  render Argument {argumentName, argumentValue} =
+    renderEntry argumentName argumentValue
+
+instance NameCollision (Argument s) where
+  nameCollision Argument {argumentName, argumentPosition} =
+    ValidationError
+      { validationMessage = "There can Be only One Argument Named " <> msg argumentName,
+        validationLocations = [argumentPosition]
+      }
+
+type Arguments (s :: Stage) = OrdMap FieldName (Argument s)
+
+-- directive
+------------------------------------------------------------------
+data Directive (s :: Stage) = Directive
+  { directiveName :: FieldName,
+    directivePosition :: Position,
+    directiveArgs :: Arguments s
+  }
+  deriving (Show, Lift, Eq)
+
+instance KeyOf FieldName (Directive s) where
+  keyOf = directiveName
+
+type Directives s = [Directive s]
+
+data DirectiveDefinition s = DirectiveDefinition
+  { directiveDefinitionName :: FieldName,
+    directiveDefinitionDescription :: Maybe Description,
+    directiveDefinitionLocations :: [DirectiveLocation],
+    directiveDefinitionArgs :: ArgumentsDefinition s
+  }
+  deriving (Show, Lift)
+
+type DirectiveDefinitions s = [DirectiveDefinition s]
+
+instance KeyOf FieldName (DirectiveDefinition s) where
+  keyOf = directiveDefinitionName
+
+instance Selectable FieldName (ArgumentDefinition s) (DirectiveDefinition s) where
+  selectOr fb f key DirectiveDefinition {directiveDefinitionArgs} =
+    selectOr fb f key directiveDefinitionArgs
+
+lookupDeprecated :: [Directive s] -> Maybe (Directive s)
+lookupDeprecated = find isDeprecation
+  where
+    isDeprecation Directive {directiveName = "deprecated"} = True
+    isDeprecation _ = False
+
+lookupDeprecatedReason :: Directive s -> Maybe Description
+lookupDeprecatedReason Directive {directiveArgs} =
+  selectOr
+    Nothing
+    argumentStringValue
+    ("reason" :: FieldName)
+    directiveArgs
+
+argumentStringValue :: Argument s -> Maybe Description
+argumentStringValue Argument {argumentValue = Null} = Nothing
+argumentStringValue Argument {argumentValue = (Scalar (String x))} = Just x
+argumentStringValue _ = Just "can't read deprecated Reason Value"
+
+instance ToCategory FieldDefinition a ANY where
+  toCategory FieldDefinition {fieldContent, ..} = FieldDefinition {fieldContent = toAny <$> fieldContent, ..}
+
+instance ToCategory (FieldContent TRUE) a ANY where
+  toCategory (FieldArgs x) = FieldArgs x
+  toCategory (DefaultInputValue x) = DefaultInputValue x
+
+newtype Fields def = Fields
+  {unFields :: OrdMap FieldName def}
+  deriving
+    ( Show,
+      Lift,
+      Functor,
+      Foldable,
+      Traversable
+    )
+
+deriving instance (KeyOf FieldName def) => Collection def (Fields def)
+
+instance Merge (FieldsDefinition cat s) where
+  merge path (Fields x) (Fields y) = Fields <$> merge path x y
+
+instance Selectable FieldName (FieldDefinition cat s) (Fields (FieldDefinition cat s)) where
+  selectOr fb f name (Fields lib) = selectOr fb f name lib
+
+unsafeFromFields :: [FieldDefinition cat s] -> FieldsDefinition cat s
+unsafeFromFields = Fields . unsafeFromValues
+
+fieldsToArguments :: FieldsDefinition IN s -> ArgumentsDefinition s
+fieldsToArguments = ArgumentsDefinition Nothing . unFields
+
+instance (KeyOf FieldName def, NameCollision def) => Listable def (Fields def) where
+  fromElems = fmap Fields . fromElems
+  elems = elems . unFields
+
+-- 3.6 Objects : https://graphql.github.io/graphql-spec/June2018/#sec-Objects
+------------------------------------------------------------------------------
+--  ObjectTypeDefinition:
+--    Description(opt) type Name ImplementsInterfaces(opt) Directives(Const)(opt) FieldsDefinition(opt)
+--
+--  ImplementsInterfaces
+--    implements &(opt) NamedType
+--    ImplementsInterfaces & NamedType
+--
+--  FieldsDefinition
+--    { FieldDefinition(list) }
+--
+type FieldsDefinition cat s = Fields (FieldDefinition cat s)
+
+--  FieldDefinition
+--    Description(opt) Name ArgumentsDefinition(opt) : Type Directives(Const)(opt)
+--
+-- InputValueDefinition
+--   Description(opt) Name: Type DefaultValue(opt) Directives[Const](opt)
+
+data FieldDefinition (cat :: TypeCategory) (s :: Stage) = FieldDefinition
+  { fieldName :: FieldName,
+    fieldDescription :: Maybe Description,
+    fieldType :: TypeRef,
+    fieldDirectives :: [Directive s],
+    fieldContent :: Maybe (FieldContent TRUE cat s)
+  }
+  deriving (Show, Lift)
+
+data FieldContent (bool :: Bool) (cat :: TypeCategory) (s :: Stage) where
+  DefaultInputValue ::
+    { defaultInputValue :: Value s
+    } ->
+    FieldContent (ELEM IN cat) cat s
+  FieldArgs ::
+    { fieldArgsDef :: ArgumentsDefinition s
+    } ->
+    FieldContent (ELEM OUT cat) cat s
+
+fieldContentArgs :: FieldContent b cat s -> ArgumentsDefinition s
+fieldContentArgs (FieldArgs args) = args
+fieldContentArgs _ = empty
+
+deriving instance Show (FieldContent bool cat s)
+
+deriving instance Lift (FieldContent bool cat s)
+
+instance KeyOf FieldName (FieldDefinition cat s) where
+  keyOf = fieldName
+
+instance Selectable FieldName (ArgumentDefinition s) (FieldDefinition OUT s) where
+  selectOr fb f key FieldDefinition {fieldContent = Just (FieldArgs args)} = selectOr fb f key args
+  selectOr fb _ _ _ = fb
+
+instance NameCollision (FieldDefinition cat s) where
+  nameCollision FieldDefinition {fieldName} =
+    "There can Be only One field Named " <> msgValidation fieldName
+
+instance RenderGQL (FieldDefinition cat s) where
+  render FieldDefinition {fieldName = FieldName name, fieldType, fieldContent = Just (FieldArgs args)} =
+    name <> render args <> ": " <> render fieldType
+  render FieldDefinition {fieldName, fieldType} =
+    renderEntry fieldName fieldType
+
+instance RenderGQL (FieldsDefinition cat s) where
+  render = renderObject . filter fieldVisibility . elems
+
+instance Nullable (FieldDefinition cat s) where
+  isNullable = isNullable . fieldType
+  toNullable field = field {fieldType = toNullable (fieldType field)}
+
+fieldVisibility :: FieldDefinition cat s -> Bool
+fieldVisibility FieldDefinition {fieldName} = fieldName `notElem` sysFields
+
+createField ::
+  Maybe (FieldContent TRUE cat s) ->
+  FieldName ->
+  [TypeWrapper] ->
+  TypeName ->
+  FieldDefinition cat s
+createField fieldContent fieldName typeWrappers typeConName =
+  FieldDefinition
+    { fieldName,
+      fieldContent,
+      fieldDescription = Nothing,
+      fieldType = TypeRef {typeConName, typeWrappers, typeArgs = Nothing},
+      fieldDirectives = []
+    }
+
+mkInputValue :: FieldName -> [TypeWrapper] -> TypeName -> FieldDefinition cat s
+mkInputValue = createField Nothing
+
+mkObjectField ::
+  ArgumentsDefinition s ->
+  FieldName ->
+  [TypeWrapper] ->
+  TypeName ->
+  FieldDefinition OUT s
+mkObjectField args = createField (Just $ FieldArgs args)
+
+toListField :: FieldDefinition cat s -> FieldDefinition cat s
+toListField dataField = dataField {fieldType = listW (fieldType dataField)}
+  where
+    listW alias@TypeRef {typeWrappers} =
+      alias {typeWrappers = TypeList : typeWrappers}
+
+-- 3.10 Input Objects: https://spec.graphql.org/June2018/#sec-Input-Objects
+---------------------------------------------------------------------------
+--- InputFieldsDefinition
+-- { InputValueDefinition(list) }
+
+type InputFieldsDefinition s = Fields (InputValueDefinition s)
+
+type InputValueDefinition = FieldDefinition IN
+
+-- 3.6.1 Field Arguments : https://graphql.github.io/graphql-spec/June2018/#sec-Field-Arguments
+-----------------------------------------------------------------------------------------------
+-- ArgumentsDefinition:
+--   (InputValueDefinition(list))
+
+data ArgumentsDefinition s = ArgumentsDefinition
+  { argumentsTypename :: Maybe TypeName,
+    arguments :: OrdMap FieldName (ArgumentDefinition s)
+  }
+  deriving (Show, Lift)
+
+instance RenderGQL (ArgumentsDefinition s) where
+  render ArgumentsDefinition {arguments} = renderArguments (elems arguments)
+
+type ArgumentDefinition = FieldDefinition IN
+
+instance Selectable FieldName (ArgumentDefinition s) (ArgumentsDefinition s) where
+  selectOr fb f key (ArgumentsDefinition _ args) = selectOr fb f key args
+
+instance Collection (ArgumentDefinition s) (ArgumentsDefinition s) where
+  empty = ArgumentsDefinition Nothing empty
+  singleton = ArgumentsDefinition Nothing . singleton
+
+instance Listable (ArgumentDefinition s) (ArgumentsDefinition s) where
+  elems (ArgumentsDefinition _ args) = elems args
+  fromElems args = ArgumentsDefinition Nothing <$> fromElems args
diff --git a/src/Data/Morpheus/Types/Internal/AST/MergeSet.hs b/src/Data/Morpheus/Types/Internal/AST/MergeSet.hs
--- a/src/Data/Morpheus/Types/Internal/AST/MergeSet.hs
+++ b/src/Data/Morpheus/Types/Internal/AST/MergeSet.hs
@@ -1,5 +1,4 @@
 {-# LANGUAGE DataKinds #-}
-{-# LANGUAGE DeriveFunctor #-}
 {-# LANGUAGE DeriveLift #-}
 {-# LANGUAGE DeriveTraversable #-}
 {-# LANGUAGE FlexibleContexts #-}
@@ -9,19 +8,24 @@
 {-# LANGUAGE KindSignatures #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Types.Internal.AST.MergeSet
   ( MergeSet,
-    toOrderedMap,
+    toOrdMap,
     concatTraverse,
     join,
   )
 where
 
-import Data.List ((\\), find)
-import Data.Maybe (maybe)
 -- MORPHEUS
 
+import Control.Applicative (Applicative (..))
+import Control.Monad (Monad (..))
+import Data.Foldable (Foldable (..))
+import Data.Functor ((<$>), Functor (..))
+import Data.List ((\\), find)
+import Data.Maybe (maybe)
 import Data.Morpheus.Internal.Utils
   ( (<:>),
     Collection (..),
@@ -33,19 +37,29 @@
     elems,
   )
 import Data.Morpheus.Types.Internal.AST.Base
-  ( FieldName,
-    GQLErrors,
-    RAW,
-    Ref,
+  ( Ref,
+    ValidationErrors,
+  )
+import Data.Morpheus.Types.Internal.AST.OrdMap
+  ( OrdMap (..),
+  )
+import qualified Data.Morpheus.Types.Internal.AST.OrdMap as OM
+import Data.Morpheus.Types.Internal.AST.Stage
+  ( RAW,
     Stage,
     VALID,
   )
-import Data.Morpheus.Types.Internal.AST.OrderedMap
-  ( OrderedMap (..),
-  )
-import qualified Data.Morpheus.Types.Internal.AST.OrderedMap as OM
-import Data.Semigroup ((<>))
+import Data.Semigroup (Semigroup (..))
+import Data.Traversable (Traversable (..))
 import Language.Haskell.TH.Syntax (Lift (..))
+import Prelude
+  ( ($),
+    (.),
+    Eq (..),
+    Show,
+    flip,
+    otherwise,
+  )
 
 -- set with mergeable components
 newtype MergeSet (dups :: Stage) a = MergeSet
@@ -66,9 +80,9 @@
     Eq b,
     Merge a,
     Merge b,
-    KeyOf b,
+    KeyOf k b,
     Monad m,
-    Failure GQLErrors m
+    Failure ValidationErrors m
   ) =>
   (a -> m (MergeSet VALID b)) ->
   MergeSet RAW a ->
@@ -79,10 +93,10 @@
 
 join ::
   ( Eq a,
-    KeyOf a,
+    KeyOf k a,
     Merge a,
     Monad m,
-    Failure GQLErrors m,
+    Failure ValidationErrors m,
     Listable a (MergeSet opt a),
     Merge (MergeSet opt a)
   ) =>
@@ -93,16 +107,16 @@
     __join acc [] = pure acc
     __join acc (x : xs) = acc <:> x >>= (`__join` xs)
 
-toOrderedMap :: (KEY a ~ FieldName, KeyOf a) => MergeSet opt a -> OrderedMap FieldName a
-toOrderedMap = OM.unsafeFromValues . unpack
+toOrdMap :: (KeyOf k a) => MergeSet opt a -> OrdMap k a
+toOrdMap = OM.unsafeFromValues . unpack
 
-instance (KeyOf a, k ~ KEY a) => Selectable (MergeSet opt a) a where
+instance (KeyOf k a) => Selectable k a (MergeSet opt a) where
   selectOr fb f key (MergeSet ls) = maybe fb f (find ((key ==) . keyOf) ls)
 
 -- must merge files on collision
 
 instance
-  ( KeyOf a,
+  ( KeyOf k a,
     Listable a (MergeSet VALID a),
     Merge a,
     Eq a
@@ -113,7 +127,7 @@
 
 instance
   ( Listable a (MergeSet VALID a),
-    KeyOf a,
+    KeyOf k a,
     Merge a,
     Eq a
   ) =>
@@ -129,17 +143,17 @@
   fromElems = pure . MergeSet
   elems = unpack
 
-safeFromList :: (Monad m, KeyOf a, Eq a, Merge a, Failure GQLErrors m) => [a] -> m (MergeSet opt a)
+safeFromList :: (Monad m, Eq a, KeyOf k a, Merge a, Failure ValidationErrors m) => [a] -> m (MergeSet opt a)
 safeFromList = insertList [] empty
 
-safeJoin :: (Monad m, KeyOf a, Eq a, Listable a (MergeSet opt a), Merge a, Failure GQLErrors m) => [Ref] -> MergeSet opt a -> MergeSet opt a -> m (MergeSet opt a)
+safeJoin :: (Monad m, KeyOf k a, Eq a, Listable a (MergeSet opt a), Merge a, Failure ValidationErrors m) => [Ref] -> MergeSet opt a -> MergeSet opt a -> m (MergeSet opt a)
 safeJoin path hm1 hm2 = insertList path hm1 (elems hm2)
 
-insertList :: (Monad m, Eq a, KeyOf a, Merge a, Failure GQLErrors m) => [Ref] -> MergeSet opt a -> [a] -> m (MergeSet opt a)
+insertList :: (Monad m, Eq a, KeyOf k a, Merge a, Failure ValidationErrors m) => [Ref] -> MergeSet opt a -> [a] -> m (MergeSet opt a)
 insertList _ smap [] = pure smap
 insertList path smap (x : xs) = insert path smap x >>= flip (insertList path) xs
 
-insert :: (Monad m, Eq a, KeyOf a, Merge a, Failure GQLErrors m) => [Ref] -> MergeSet opt a -> a -> m (MergeSet opt a)
+insert :: (Monad m, Eq a, KeyOf k a, Merge a, Failure ValidationErrors m) => [Ref] -> MergeSet opt a -> a -> m (MergeSet opt a)
 insert path mSet@(MergeSet ls) currentValue = MergeSet <$> __insert
   where
     __insert =
diff --git a/src/Data/Morpheus/Types/Internal/AST/OrdMap.hs b/src/Data/Morpheus/Types/Internal/AST/OrdMap.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Morpheus/Types/Internal/AST/OrdMap.hs
@@ -0,0 +1,100 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE NamedFieldPuns #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+module Data.Morpheus.Types.Internal.AST.OrdMap
+  ( OrdMap (..),
+    unsafeFromValues,
+  )
+where
+
+-- MORPHEUS
+import Data.Foldable (Foldable (..))
+import Data.Functor ((<$>), Functor (..))
+import Data.HashMap.Lazy (HashMap)
+import qualified Data.HashMap.Lazy as HM
+import Data.Hashable (Hashable)
+import Data.Maybe (fromMaybe, maybe)
+import Data.Morpheus.Error.NameCollision (NameCollision (..))
+import Data.Morpheus.Internal.Utils
+  ( Collection (..),
+    KeyOf (..),
+    Listable (..),
+    Merge (..),
+    Selectable (..),
+    toPair,
+  )
+import Data.Semigroup ((<>))
+import Data.Traversable (Traversable (..))
+import Language.Haskell.TH.Syntax (Lift (..))
+import Prelude
+  ( ($),
+    (.),
+    Eq,
+    Show,
+    error,
+  )
+
+-- OrdMap
+data OrdMap k a = OrdMap
+  { mapKeys :: [k],
+    mapEntries :: HashMap k a
+  }
+  deriving
+    ( Show,
+      Eq,
+      Functor
+    )
+
+instance (Lift a, Lift k, Eq k, Hashable k) => Lift (OrdMap k a) where
+  lift (OrdMap names x) = [|OrdMap names (HM.fromList ls)|]
+    where
+      ls = HM.toList x
+
+#if MIN_VERSION_template_haskell(2,16,0)
+  liftTyped (OrdMap names x) = [||OrdMap names (HM.fromList ls)||]
+    where
+      ls = HM.toList x
+#endif
+
+instance (Eq k, Hashable k) => Foldable (OrdMap k) where
+  foldMap f = foldMap f . getElements
+
+getElements :: (Eq k, Hashable k) => OrdMap k b -> [b]
+getElements OrdMap {mapKeys, mapEntries} = fmap takeValue mapKeys
+  where
+    takeValue key = fromMaybe (error "TODO: invalid Ordered Map") (key `HM.lookup` mapEntries)
+
+instance (Eq k, Hashable k) => Traversable (OrdMap k) where
+  traverse f (OrdMap names values) = OrdMap names <$> traverse f values
+
+instance (KeyOf k a, Hashable k) => Collection a (OrdMap k a) where
+  empty = OrdMap [] HM.empty
+  singleton x = OrdMap [keyOf x] $ HM.singleton (keyOf x) x
+
+instance (Eq k, Hashable k) => Selectable k a (OrdMap k a) where
+  selectOr fb f key OrdMap {mapEntries} = maybe fb f (HM.lookup key mapEntries)
+
+instance (NameCollision a, KeyOf k a) => Merge (OrdMap k a) where
+  merge ref (OrdMap k1 x) (OrdMap k2 y) = OrdMap (k1 <> k2) <$> merge ref x y
+
+instance (NameCollision a, KeyOf k a, Hashable k) => Listable a (OrdMap k a) where
+  fromElems values = OrdMap (fmap keyOf values) <$> fromElems values
+  elems = getElements
+
+unsafeFromValues ::
+  ( KeyOf k a,
+    Hashable k
+  ) =>
+  [a] ->
+  OrdMap k a
+unsafeFromValues x = OrdMap (fmap keyOf x) $ HM.fromList $ fmap toPair x
diff --git a/src/Data/Morpheus/Types/Internal/AST/OrderedMap.hs b/src/Data/Morpheus/Types/Internal/AST/OrderedMap.hs
deleted file mode 100644
--- a/src/Data/Morpheus/Types/Internal/AST/OrderedMap.hs
+++ /dev/null
@@ -1,122 +0,0 @@
-{-# LANGUAGE DeriveFunctor #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE GADTs #-}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE TemplateHaskell #-}
-
-module Data.Morpheus.Types.Internal.AST.OrderedMap
-  ( OrderedMap (..),
-    unsafeFromValues,
-  )
-where
-
-import Data.HashMap.Lazy (HashMap)
-import qualified Data.HashMap.Lazy as HM
-import Data.Hashable (Hashable)
-import Data.Maybe (fromMaybe, isJust)
--- MORPHEUS
-import Data.Morpheus.Error.NameCollision (NameCollision (..))
-import Data.Morpheus.Internal.Utils
-  ( Collection (..),
-    Failure (..),
-    KeyOf (..),
-    Listable (..),
-    Merge (..),
-    Selectable (..),
-    toPair,
-  )
-import Data.Morpheus.Types.Internal.AST.Base
-  ( GQLErrors,
-  )
-import Data.Semigroup ((<>))
-import Language.Haskell.TH.Syntax (Lift (..))
-
--- OrderedMap
-data OrderedMap k a = OrderedMap
-  { mapKeys :: [k],
-    mapEntries :: HashMap k a
-  }
-  deriving (Show, Eq, Functor)
-
-instance (Lift a, Lift k) => Lift (OrderedMap k a) where
-  lift (OrderedMap names x) = [|OrderedMap names (HM.fromList ls)|]
-    where
-      ls = HM.toList x
-
-instance (Eq k, Hashable k) => Foldable (OrderedMap k) where
-  foldMap f = foldMap f . getElements
-
-getElements :: (Eq k, Hashable k) => OrderedMap k b -> [b]
-getElements OrderedMap {mapKeys, mapEntries} = map takeValue mapKeys
-  where
-    takeValue key = fromMaybe (error "TODO: invalid Ordered Map") (key `HM.lookup` mapEntries)
-
-instance (Eq k, Hashable k) => Traversable (OrderedMap k) where
-  traverse f (OrderedMap names values) = OrderedMap names <$> traverse f values
-
-instance (KeyOf a, Hashable k, KEY a ~ k) => Collection a (OrderedMap k a) where
-  empty = OrderedMap [] HM.empty
-  singleton x = OrderedMap [keyOf x] $ HM.singleton (keyOf x) x
-
-instance (Eq k, Hashable k, k ~ KEY a) => Selectable (OrderedMap k a) a where
-  selectOr fb f key OrderedMap {mapEntries} = maybe fb f (HM.lookup key mapEntries)
-
-instance (NameCollision a, Eq k, Hashable k, k ~ KEY a) => Merge (OrderedMap k a) where
-  merge _ (OrderedMap k1 x) (OrderedMap k2 y) = OrderedMap (k1 <> k2) <$> safeJoin x y
-
-instance (NameCollision a, Eq k, Hashable k, k ~ KEY a) => Listable a (OrderedMap k a) where
-  fromElems = safeFromList
-  elems = getElements
-
-safeFromList ::
-  ( Failure GQLErrors m,
-    Applicative m,
-    NameCollision a,
-    Eq (KEY a),
-    Hashable (KEY a),
-    KeyOf a
-  ) =>
-  [a] ->
-  m (OrderedMap (KEY a) a)
-safeFromList values = OrderedMap (map keyOf values) <$> safeUnionWith HM.empty (map toPair values)
-
-unsafeFromValues ::
-  ( KeyOf a,
-    Eq (KEY a),
-    Hashable (KEY a)
-  ) =>
-  [a] ->
-  OrderedMap (KEY a) a
-unsafeFromValues x = OrderedMap (map keyOf x) $ HM.fromList $ fmap toPair x
-
-safeJoin :: (Failure GQLErrors m, Eq k, Hashable k, KEY a ~ k, Applicative m, NameCollision a) => HashMap k a -> HashMap k a -> m (HashMap k a)
-safeJoin hm newls = safeUnionWith hm (HM.toList newls)
-
-safeUnionWith ::
-  ( Failure GQLErrors m,
-    Applicative m,
-    Eq k,
-    Hashable k,
-    NameCollision a,
-    KEY a ~ k
-  ) =>
-  HashMap k a ->
-  [(k, a)] ->
-  m (HashMap k a)
-safeUnionWith hm names = case insertNoDups (hm, []) names of
-  (res, dupps)
-    | null dupps -> pure res
-    | otherwise -> failure $ map (uncurry nameCollision) dupps
-
-type NoDupHashMap k a = (HashMap k a, [(k, a)])
-
-insertNoDups :: (Eq k, Hashable k) => NoDupHashMap k a -> [(k, a)] -> NoDupHashMap k a
-insertNoDups collected [] = collected
-insertNoDups (coll, errors) (pair@(name, value) : xs)
-  | isJust (name `HM.lookup` coll) = insertNoDups (coll, errors <> [pair]) xs
-  | otherwise = insertNoDups (HM.insert name value coll, errors) xs
diff --git a/src/Data/Morpheus/Types/Internal/AST/SafeHashMap.hs b/src/Data/Morpheus/Types/Internal/AST/SafeHashMap.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Morpheus/Types/Internal/AST/SafeHashMap.hs
@@ -0,0 +1,86 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE DeriveTraversable #-}
+{-# LANGUAGE DerivingStrategies #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE StandaloneDeriving #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+module Data.Morpheus.Types.Internal.AST.SafeHashMap
+  ( SafeHashMap,
+    insert,
+  )
+where
+
+-- MORPHEUS
+import Control.Monad (Monad)
+import Data.Foldable (Foldable (..))
+import Data.Functor ((<$>), Functor (..))
+import Data.HashMap.Lazy (HashMap)
+import qualified Data.HashMap.Lazy as HM
+import Data.Hashable (Hashable)
+import Data.Morpheus.Error.NameCollision (NameCollision (..))
+import Data.Morpheus.Internal.Utils
+  ( (<:>),
+    Collection (..),
+    Failure (..),
+    KeyOf (..),
+    Listable (..),
+    Merge (..),
+    Selectable (..),
+  )
+import Data.Morpheus.Types.Internal.AST.Base (ValidationErrors)
+import Data.Traversable (Traversable (..))
+import Language.Haskell.TH.Syntax (Lift (..))
+import Prelude
+  ( (.),
+    Eq,
+    Show,
+  )
+
+newtype SafeHashMap k a = SafeHashMap
+  { unpackSafeHashMap :: HashMap k a
+  }
+  deriving
+    ( Show,
+      Eq,
+      Functor,
+      Foldable,
+      Traversable
+    )
+  deriving newtype
+    ( Collection a,
+      Selectable k a
+    )
+
+instance (Lift a, Lift k, Eq k, Hashable k) => Lift (SafeHashMap k a) where
+  lift (SafeHashMap x) = let ls = HM.toList x in [|SafeHashMap (HM.fromList ls)|]
+
+#if MIN_VERSION_template_haskell(2,16,0)
+  liftTyped (SafeHashMap x) = let ls = HM.toList x in [||SafeHashMap (HM.fromList ls)||]
+#endif
+
+instance (NameCollision a, KeyOf k a) => Merge (SafeHashMap k a) where
+  merge ref (SafeHashMap x) (SafeHashMap y) = SafeHashMap <$> merge ref x y
+
+instance (NameCollision a, KeyOf k a, Hashable k) => Listable a (SafeHashMap k a) where
+  fromElems = fmap SafeHashMap . fromElems
+  elems = elems . unpackSafeHashMap
+
+insert ::
+  ( NameCollision a,
+    KeyOf k a,
+    Monad m,
+    Failure ValidationErrors m
+  ) =>
+  a ->
+  SafeHashMap k a ->
+  m (SafeHashMap k a)
+insert x = (<:> singleton x)
diff --git a/src/Data/Morpheus/Types/Internal/AST/Selection.hs b/src/Data/Morpheus/Types/Internal/AST/Selection.hs
--- a/src/Data/Morpheus/Types/Internal/AST/Selection.hs
+++ b/src/Data/Morpheus/Types/Internal/AST/Selection.hs
@@ -3,12 +3,14 @@
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE GADTs #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE RecordWildCards #-}
 {-# LANGUAGE StandaloneDeriving #-}
 {-# LANGUAGE TypeFamilies #-}
 {-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Types.Internal.AST.Selection
   ( Selection (..),
@@ -27,9 +29,10 @@
   )
 where
 
-import Data.Maybe (fromMaybe, isJust)
--- MORPHEUS
-
+import Control.Applicative (pure)
+import Data.Foldable (all, foldr)
+import Data.Functor ((<$>), fmap)
+import Data.Maybe (Maybe (..), fromMaybe, isJust, maybe)
 import Data.Morpheus.Error.NameCollision
   ( NameCollision (..),
   )
@@ -41,34 +44,50 @@
   ( Failure (..),
     KeyOf (..),
     Merge (..),
+    elems,
   )
+import Data.Morpheus.Rendering.RenderGQL
+  ( RenderGQL (..),
+    Rendering,
+    renderArguments,
+    renderObject,
+    space,
+  )
 import Data.Morpheus.Types.Internal.AST.Base
   ( FieldName,
-    GQLError (..),
-    GQLErrors,
     Message,
+    Msg (..),
     OperationType (..),
     Position,
-    RAW,
     Ref (..),
-    Stage,
     TypeName (..),
-    VALID,
+    ValidationError (..),
+    ValidationErrors,
     intercalateName,
     msg,
+    msgValidation,
     readName,
   )
+import Data.Morpheus.Types.Internal.AST.Fields
+  ( Arguments,
+    Directives,
+  )
 import Data.Morpheus.Types.Internal.AST.MergeSet
   ( MergeSet,
   )
-import Data.Morpheus.Types.Internal.AST.OrderedMap
-  ( OrderedMap,
+import Data.Morpheus.Types.Internal.AST.OrdMap
+  ( OrdMap,
   )
+import Data.Morpheus.Types.Internal.AST.Stage
+  ( RAW,
+    Stage,
+    VALID,
+  )
+import Data.Morpheus.Types.Internal.AST.TypeCategory
+  ( OBJECT,
+  )
 import Data.Morpheus.Types.Internal.AST.TypeSystem
-  ( Arguments,
-    Directives,
-    OUT,
-    Schema (..),
+  ( Schema (..),
     TypeDefinition (..),
   )
 import Data.Morpheus.Types.Internal.AST.Value
@@ -78,34 +97,48 @@
   )
 import Data.Semigroup ((<>))
 import Language.Haskell.TH.Syntax (Lift (..))
+import Prelude
+  ( ($),
+    (.),
+    Eq (..),
+    Show (..),
+    otherwise,
+  )
 
-data Fragment = Fragment
+data Fragment (stage :: Stage) = Fragment
   { fragmentName :: FieldName,
     fragmentType :: TypeName,
     fragmentPosition :: Position,
-    fragmentSelection :: SelectionSet RAW,
-    fragmentDirectives :: Directives RAW
+    fragmentSelection :: SelectionSet stage,
+    fragmentDirectives :: Directives stage
   }
   deriving (Show, Eq, Lift)
 
 -- ERRORs
-instance NameCollision Fragment where
-  nameCollision _ Fragment {fragmentName, fragmentPosition} =
-    GQLError
-      { message = "There can be only one fragment named " <> msg fragmentName <> ".",
-        locations = [fragmentPosition]
-      }
+instance NameCollision (Fragment s) where
+  nameCollision Fragment {fragmentName, fragmentPosition} =
+    ValidationError
+      ("There can be only one fragment named " <> msg fragmentName <> ".")
+      [fragmentPosition]
 
-instance KeyOf Fragment where
+instance KeyOf FieldName (Fragment s) where
   keyOf = fragmentName
 
-type Fragments = OrderedMap FieldName Fragment
+type Fragments (s :: Stage) = OrdMap FieldName (Fragment s)
 
 data SelectionContent (s :: Stage) where
   SelectionField :: SelectionContent s
   SelectionSet :: SelectionSet s -> SelectionContent s
   UnionSelection :: UnionSelection VALID -> SelectionContent VALID
 
+renderSelectionSet :: SelectionSet VALID -> Rendering
+renderSelectionSet = renderObject . elems
+
+instance RenderGQL (SelectionContent VALID) where
+  render SelectionField = ""
+  render (SelectionSet selSet) = renderSelectionSet selSet
+  render (UnionSelection unionSets) = renderObject (elems unionSets)
+
 instance
   Merge (SelectionSet s) =>
   Merge (SelectionContent s)
@@ -116,9 +149,9 @@
     | oldC == currC = pure oldC
     | otherwise =
       failure
-        [ GQLError
-            { message = msg (intercalateName "." $ map refName path),
-              locations = map refPosition path
+        [ ValidationError
+            { validationMessage = msg (intercalateName "." $ fmap refName path),
+              validationLocations = fmap refPosition path
             }
         ]
 
@@ -134,12 +167,22 @@
   }
   deriving (Show, Eq, Lift)
 
-mergeConflict :: [Ref] -> GQLError -> GQLErrors
+instance KeyOf TypeName UnionTag where
+  keyOf = unionTagName
+
+instance RenderGQL UnionTag where
+  render UnionTag {unionTagName, unionTagSelection} =
+    "... on "
+      <> render unionTagName
+      <> space
+      <> renderSelectionSet unionTagSelection
+
+mergeConflict :: [Ref] -> ValidationError -> ValidationErrors
 mergeConflict [] err = [err]
 mergeConflict refs@(rootField : xs) err =
-  [ GQLError
-      { message = renderSubfields <> message err,
-        locations = map refPosition refs <> locations err
+  [ ValidationError
+      { validationMessage = renderSubfields <> validationMessage err,
+        validationLocations = fmap refPosition refs <> validationLocations err
       }
   ]
   where
@@ -156,10 +199,6 @@
   merge path (UnionTag oldTag oldSel) (UnionTag _ currentSel) =
     UnionTag oldTag <$> merge path oldSel currentSel
 
-instance KeyOf UnionTag where
-  type KEY UnionTag = TypeName
-  keyOf = unionTagName
-
 type UnionSelection (s :: Stage) = MergeSet s UnionTag
 
 type SelectionSet (s :: Stage) = MergeSet s (Selection s)
@@ -174,10 +213,19 @@
       selectionDirectives :: Directives s
     } ->
     Selection s
-  InlineFragment :: Fragment -> Selection RAW
+  InlineFragment :: Fragment RAW -> Selection RAW
   Spread :: Directives RAW -> Ref -> Selection RAW
 
-instance KeyOf (Selection s) where
+instance RenderGQL (Selection VALID) where
+  render
+    Selection
+      { ..
+      } =
+      render (fromMaybe selectionName selectionAlias)
+        <> renderArguments (elems selectionArguments)
+        <> render selectionContent
+
+instance KeyOf FieldName (Selection s) where
   keyOf
     Selection
       { selectionName,
@@ -223,12 +271,12 @@
           | selectionName old == selectionName current = pure $ selectionName current
           | otherwise =
             failure $ mergeConflict path $
-              GQLError
-                { message =
+              ValidationError
+                { validationMessage =
                     "" <> msg (selectionName old) <> " and " <> msg (selectionName current)
                       <> " are different fields. "
                       <> useDufferentAliases,
-                  locations = [pos1, pos2]
+                  validationLocations = [pos1, pos2]
                 }
         ---------------------
         -- allias name is relevant only if they collide by allias like:
@@ -243,16 +291,15 @@
           | selectionArguments old == selectionArguments current = pure $ selectionArguments current
           | otherwise =
             failure $ mergeConflict currentPath $
-              GQLError
-                { message = "they have differing arguments. " <> useDufferentAliases,
-                  locations = [pos1, pos2]
+              ValidationError
+                { validationMessage = "they have differing arguments. " <> useDufferentAliases,
+                  validationLocations = [pos1, pos2]
                 }
   merge path _ _ =
-    failure $ mergeConflict path $
-      GQLError
-        { message = "INTERNAL: can't merge. " <> useDufferentAliases,
-          locations = []
-        }
+    failure $
+      mergeConflict
+        path
+        ("INTERNAL: can't merge. " <> msgValidation useDufferentAliases :: ValidationError)
 
 deriving instance Show (Selection a)
 
@@ -272,16 +319,25 @@
   }
   deriving (Show, Lift)
 
+instance RenderGQL (Operation VALID) where
+  render
+    Operation
+      { operationName,
+        operationType,
+        operationSelection
+      } =
+      render operationType
+        <> space
+        <> render operationName
+        <> space
+        <> renderSelectionSet operationSelection
+
 getOperationName :: Maybe FieldName -> TypeName
 getOperationName = maybe "AnonymousOperation" (TypeName . readName)
 
-getOperationDataType :: Failure GQLErrors m => Operation a -> Schema -> m (TypeDefinition OUT)
+getOperationDataType :: Failure ValidationError m => Operation s -> Schema VALID -> m (TypeDefinition OBJECT VALID)
 getOperationDataType Operation {operationType = Query} lib = pure (query lib)
 getOperationDataType Operation {operationType = Mutation, operationPosition} lib =
-  case mutation lib of
-    Just x -> pure x
-    Nothing -> failure $ mutationIsNotDefined operationPosition
+  maybe (failure $ mutationIsNotDefined operationPosition) pure (mutation lib)
 getOperationDataType Operation {operationType = Subscription, operationPosition} lib =
-  case subscription lib of
-    Just x -> pure x
-    Nothing -> failure $ subscriptionIsNotDefined operationPosition
+  maybe (failure $ subscriptionIsNotDefined operationPosition) pure (subscription lib)
diff --git a/src/Data/Morpheus/Types/Internal/AST/Stage.hs b/src/Data/Morpheus/Types/Internal/AST/Stage.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Morpheus/Types/Internal/AST/Stage.hs
@@ -0,0 +1,31 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+module Data.Morpheus.Types.Internal.AST.Stage
+  ( CONST,
+    VALID,
+    RAW,
+    Stage (..),
+    CONST_OR_VALID,
+  )
+where
+
+type CONST = 'CONST
+
+type VALID = 'VALID
+
+type RAW = 'RAW
+
+data Stage
+  = RAW
+  | CONST
+  | VALID
+
+type family CONST_OR_VALID (a :: Stage) :: Stage
+
+type instance CONST_OR_VALID RAW = CONST
+
+type instance CONST_OR_VALID CONST = CONST
+
+type instance CONST_OR_VALID VALID = VALID
diff --git a/src/Data/Morpheus/Types/Internal/AST/TH.hs b/src/Data/Morpheus/Types/Internal/AST/TH.hs
--- a/src/Data/Morpheus/Types/Internal/AST/TH.hs
+++ b/src/Data/Morpheus/Types/Internal/AST/TH.hs
@@ -1,5 +1,6 @@
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE NamedFieldPuns #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Types.Internal.AST.TH
   ( ConsD (..),
@@ -17,13 +18,23 @@
     TypeRef (..),
     hsTypeName,
   )
+import Data.Morpheus.Types.Internal.AST.Fields
+  ( FieldDefinition (..),
+    FieldsDefinition,
+  )
 import Data.Morpheus.Types.Internal.AST.TypeSystem
   ( DataEnumValue (..),
-    FieldDefinition (..),
-    FieldsDefinition,
   )
+import Prelude
+  ( (.),
+    Bool (..),
+    Show,
+    all,
+    fmap,
+    null,
+  )
 
-toHSFieldDefinition :: FieldDefinition cat -> FieldDefinition cat
+toHSFieldDefinition :: FieldDefinition cat s -> FieldDefinition cat s
 toHSFieldDefinition field@FieldDefinition {fieldType = tyRef@TypeRef {typeConName}} =
   field
     { fieldType = tyRef {typeConName = hsTypeName typeConName}
@@ -37,21 +48,21 @@
 
 -- Template Haskell Types
 
-data ConsD cat = ConsD
+data ConsD cat s = ConsD
   { cName :: TypeName,
-    cFields :: [FieldDefinition cat]
+    cFields :: [FieldDefinition cat s]
   }
   deriving (Show)
 
-mkCons :: TypeName -> FieldsDefinition cat -> ConsD cat
+mkCons :: TypeName -> FieldsDefinition cat s -> ConsD cat s
 mkCons typename fields =
   ConsD
     { cName = hsTypeName typename,
-      cFields = map toHSFieldDefinition (elems fields)
+      cFields = fmap toHSFieldDefinition (elems fields)
     }
 
-isEnum :: [ConsD cat] -> Bool
+isEnum :: [ConsD cat s] -> Bool
 isEnum = all (null . cFields)
 
-mkConsEnum :: DataEnumValue -> ConsD cat
+mkConsEnum :: DataEnumValue s -> ConsD cat s
 mkConsEnum DataEnumValue {enumName} = ConsD {cName = hsTypeName enumName, cFields = []}
diff --git a/src/Data/Morpheus/Types/Internal/AST/TypeCategory.hs b/src/Data/Morpheus/Types/Internal/AST/TypeCategory.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Morpheus/Types/Internal/AST/TypeCategory.hs
@@ -0,0 +1,133 @@
+{-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+module Data.Morpheus.Types.Internal.AST.TypeCategory
+  ( TypeCategory,
+    ELEM,
+    OUT,
+    IN,
+    ANY,
+    LEAF,
+    OBJECT,
+    IMPLEMENTABLE,
+    fromAny,
+    toAny,
+    REQURE_IMPLEMENTABLE,
+    ToCategory (..),
+    FromCategory (..),
+  )
+where
+
+import Data.Maybe (Maybe (..))
+import Data.Morpheus.Types.Internal.AST.Base
+  ( FALSE,
+    TRUE,
+  )
+import Data.Morpheus.Types.Internal.AST.Stage (Stage)
+import Prelude (Bool (..))
+
+data TypeCategory
+  = IN
+  | OUT
+  | ANY
+  | LEAF
+  | OBJECT
+  | IMPLEMENTABLE
+
+type IN = 'IN
+
+type OUT = 'OUT
+
+type ANY = 'ANY
+
+type OBJECT = 'OBJECT
+
+type IMPLEMENTABLE = 'IMPLEMENTABLE
+
+type LEAF = 'LEAF
+
+toAny ::
+  (ToCategory a k ANY) =>
+  a (k :: TypeCategory) (s :: Stage) ->
+  a ANY s
+toAny = toCategory
+
+fromAny ::
+  (FromCategory a ANY k) =>
+  a ANY (s :: Stage) ->
+  Maybe (a k s)
+fromAny = fromCategory
+
+class ToCategory a (k :: TypeCategory) (k' :: TypeCategory) where
+  toCategory :: a k (s :: Stage) -> a k' s
+
+class FromCategory a (k :: TypeCategory) (k' :: TypeCategory) where
+  fromCategory :: a k (s :: Stage) -> Maybe (a k' s)
+
+type family
+  ELEM
+    (elemKind :: TypeCategory)
+    (setOfKind :: TypeCategory) ::
+    Bool
+
+type REQURE_IMPLEMENTABLE cat = ELEM cat IMPLEMENTABLE ~ TRUE
+
+-- ANY
+type instance ELEM ANY a = TRUE
+
+type instance ELEM a ANY = TRUE
+
+-- LEAF
+type instance ELEM LEAF LEAF = TRUE
+
+type instance ELEM LEAF IN = TRUE
+
+type instance ELEM LEAF OUT = TRUE
+
+type instance ELEM LEAF OBJECT = FALSE
+
+type instance ELEM LEAF IMPLEMENTABLE = FALSE
+
+-- IN
+type instance ELEM IN IN = TRUE
+
+type instance ELEM IN OUT = FALSE
+
+type instance ELEM IN OBJECT = FALSE
+
+type instance ELEM IN IMPLEMENTABLE = FALSE
+
+-- OUT
+type instance ELEM OUT OUT = TRUE
+
+type instance ELEM OUT IN = FALSE
+
+type instance ELEM OUT OBJECT = FALSE
+
+type instance ELEM OUT IMPLEMENTABLE = FALSE
+
+-- IMPLEMENTABLE
+type instance ELEM IMPLEMENTABLE IMPLEMENTABLE = TRUE
+
+type instance ELEM IMPLEMENTABLE OUT = TRUE
+
+type instance ELEM IMPLEMENTABLE IN = FALSE
+
+type instance ELEM IMPLEMENTABLE LEAF = FALSE
+
+type instance ELEM IMPLEMENTABLE OBJECT = FALSE
+
+-- OUTPUT_OBJECT
+type instance ELEM OBJECT OBJECT = TRUE
+
+type instance ELEM OBJECT IMPLEMENTABLE = TRUE
+
+type instance ELEM OBJECT OUT = TRUE
+
+type instance ELEM OBJECT IN = FALSE
+
+type instance ELEM OBJECT LEAF = FALSE
diff --git a/src/Data/Morpheus/Types/Internal/AST/TypeSystem.hs b/src/Data/Morpheus/Types/Internal/AST/TypeSystem.hs
--- a/src/Data/Morpheus/Types/Internal/AST/TypeSystem.hs
+++ b/src/Data/Morpheus/Types/Internal/AST/TypeSystem.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE DataKinds #-}
 {-# LANGUAGE DeriveLift #-}
 {-# LANGUAGE DeriveTraversable #-}
@@ -16,164 +17,195 @@
 {-# LANGUAGE TemplateHaskell #-}
 {-# LANGUAGE TypeFamilies #-}
 {-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Types.Internal.AST.TypeSystem
-  ( Arguments,
-    ScalarDefinition (..),
+  ( ScalarDefinition (..),
     DataEnum,
-    FieldsDefinition,
-    ArgumentDefinition,
     DataUnion,
-    ArgumentsDefinition (..),
-    FieldDefinition (..),
-    InputFieldsDefinition,
     TypeContent (..),
     TypeDefinition (..),
     Schema (..),
     DataEnumValue (..),
     TypeLib,
-    Directive (..),
-    TypeUpdater,
     TypeCategory,
     DataInputUnion,
-    Argument (..),
-    Fields (..),
-    createField,
-    createArgument,
-    createEnumType,
+    mkEnumContent,
+    mkUnionContent,
+    mkType,
     createScalarType,
-    createType,
-    createUnionType,
-    createAlias,
-    createInputUnionFields,
-    createEnumValue,
-    defineType,
-    isTypeDefined,
+    mkInputUnionFields,
     initTypeLib,
-    isFieldNullable,
     insertType,
-    fieldVisibility,
     kindOf,
-    toNullableField,
-    toListField,
     isEntNode,
-    lookupDeprecated,
-    lookupDeprecatedReason,
     lookupWith,
-    unsafeFromFields,
     __inputname,
     updateSchema,
-    OUT,
-    IN,
-    ANY,
-    FromAny (..),
-    ToAny (..),
-    DirectiveDefinitions,
-    DirectiveDefinition (..),
-    Directives,
-    fieldsToArguments,
-    FieldContent (..),
-    fieldContentArgs,
-    mkField,
-    mkObjectField,
     UnionMember (..),
     mkUnionMember,
+    RawTypeDefinition (..),
+    RootOperationTypeDefinition (..),
+    SchemaDefinition (..),
+    buildSchema,
+    Typed (Typed),
+    untyped,
+    typed,
+    possibleTypes,
+    possibleInterfaceTypes,
   )
 where
 
-import Data.HashMap.Lazy
-  ( HashMap,
-    union,
-  )
-import qualified Data.HashMap.Lazy as HM
-import Data.List (find)
 -- MORPHEUS
 
-import Data.Morpheus.Error (globalErrorMessage)
+import Control.Applicative ((<|>), Applicative (..))
+import Control.Monad (Monad (..), foldM)
+import Data.Either (Either (..))
+import Data.Foldable (concatMap)
+import Data.Functor ((<$>), fmap)
+import Data.List (elem, filter, find, notElem)
+import Data.Maybe (Maybe (..), catMaybes, mapMaybe, maybe)
 import Data.Morpheus.Error.NameCollision
   ( NameCollision (..),
   )
 import Data.Morpheus.Error.Schema (nameCollisionError)
 import Data.Morpheus.Internal.Utils
-  ( Collection (..),
+  ( (<:>),
+    Collection (..),
+    Failure (..),
     KeyOf (..),
     Listable (..),
     Merge (..),
     Selectable (..),
+    UpdateT (..),
+    concatUpdates,
     elems,
+    resolveUpdates,
   )
 import Data.Morpheus.Rendering.RenderGQL
   ( RenderGQL (..),
-    renderIndent,
+    newline,
+    renderMembers,
     renderObject,
   )
 import Data.Morpheus.Types.Internal.AST.Base
   ( DataFingerprint (..),
     Description,
-    FALSE,
     FieldName,
     FieldName (..),
-    GQLError (..),
     Msg (..),
-    Position,
-    RESOLVED,
-    Stage,
+    OperationType (..),
     TRUE,
     Token,
     TypeKind (..),
     TypeName,
     TypeRef (..),
     TypeWrapper (..),
-    VALID,
-    isNullable,
-    isSystemTypeName,
+    ValidationError,
+    ValidationErrors,
+    isNotSystemTypeName,
+    mkTypeRef,
     msg,
-    sysFields,
+    msgValidation,
     toFieldName,
     toOperationType,
   )
-import Data.Morpheus.Types.Internal.AST.DirectiveLocation (DirectiveLocation)
-import Data.Morpheus.Types.Internal.AST.OrderedMap
-  ( OrderedMap,
-    unsafeFromValues,
+import Data.Morpheus.Types.Internal.AST.Fields
+  ( Directive,
+    DirectiveDefinition (..),
+    Directives,
+    FieldDefinition (..),
+    FieldsDefinition,
+    unsafeFromFields,
   )
-import Data.Morpheus.Types.Internal.AST.Value
-  ( ScalarValue (..),
-    ValidValue,
-    Value (..),
+import Data.Morpheus.Types.Internal.AST.OrdMap
+  ( OrdMap,
   )
-import Data.Morpheus.Types.Internal.Resolving.Core
-  ( Failure (..),
-    LibUpdater,
-    resolveUpdates,
+import Data.Morpheus.Types.Internal.AST.SafeHashMap
+  ( SafeHashMap,
+    insert,
   )
+import Data.Morpheus.Types.Internal.AST.Stage
+  ( CONST,
+    Stage,
+    VALID,
+  )
+import Data.Morpheus.Types.Internal.AST.TypeCategory
+  ( ANY,
+    ELEM,
+    FromCategory (..),
+    IMPLEMENTABLE,
+    IN,
+    LEAF,
+    OBJECT,
+    OUT,
+    ToCategory (..),
+    TypeCategory,
+    fromAny,
+    toAny,
+  )
+import Data.Morpheus.Types.Internal.AST.Value
+  ( Value (..),
+  )
 import Data.Semigroup (Semigroup (..))
 import Data.Text (intercalate)
 import Instances.TH.Lift ()
 import Language.Haskell.TH.Syntax (Lift (..))
+import Prelude
+  ( ($),
+    (.),
+    Bool (..),
+    Eq (..),
+    Show (..),
+    const,
+    flip,
+    otherwise,
+  )
 
-type DataEnum = [DataEnumValue]
+type DataEnum s = [DataEnumValue s]
 
-mkUnionMember :: TypeName -> UnionMember cat
+-- used for perserving type information from untyped values
+-- e.g
+-- unionType :: UnionMember IN VALID -> Typed IN VALID TypeName
+-- unionType = typed memberName
+typed :: (a c s -> b) -> a c s -> Typed c s b
+typed f = Typed . f
+
+untyped :: (a -> b) -> Typed c s a -> b
+untyped f = f . _untyped
+
+-- | used for perserving type information from untyped values
+-- see function typed
+newtype Typed (cat :: TypeCategory) (s :: Stage) a = Typed
+  { _untyped :: a
+  }
+
+mkUnionMember :: TypeName -> UnionMember cat s
 mkUnionMember name = UnionMember name True
 
-data UnionMember (cat :: TypeCategory) = UnionMember
+data UnionMember (cat :: TypeCategory) (s :: Stage) = UnionMember
   { memberName :: TypeName,
     visibility :: Bool
   }
   deriving (Show, Lift, Eq)
 
-type DataUnion = [UnionMember OUT]
+type DataUnion s = [UnionMember OUT s]
 
-type DataInputUnion = [UnionMember IN]
+type DataInputUnion s = [UnionMember IN s]
 
-instance RenderGQL (UnionMember cat) where
+instance RenderGQL (UnionMember cat s) where
   render = render . memberName
 
+instance Msg (UnionMember cat s) where
+  msg = msg . memberName
+
+instance KeyOf TypeName (UnionMember cat s) where
+  keyOf = memberName
+
 -- scalar
 ------------------------------------------------------------------
 newtype ScalarDefinition = ScalarDefinition
-  {validateValue :: ValidValue -> Either Token ValidValue}
+  {validateValue :: Value VALID -> Either Token (Value VALID)}
 
 instance Show ScalarDefinition where
   show _ = "ScalarDefinition"
@@ -181,79 +213,19 @@
 instance Lift ScalarDefinition where
   lift _ = [|ScalarDefinition pure|]
 
-data Argument (valid :: Stage) = Argument
-  { argumentName :: FieldName,
-    argumentValue :: Value valid,
-    argumentPosition :: Position
-  }
-  deriving (Show, Eq, Lift)
-
-instance KeyOf (Argument stage) where
-  keyOf = argumentName
-
-instance NameCollision (Argument s) where
-  nameCollision _ Argument {argumentName, argumentPosition} =
-    GQLError
-      { message = "There can Be only One Argument Named " <> msg argumentName,
-        locations = [argumentPosition]
-      }
-
-type Arguments s = OrderedMap FieldName (Argument s)
-
--- directive
-------------------------------------------------------------------
-data Directive (s :: Stage) = Directive
-  { directiveName :: FieldName,
-    directivePosition :: Position,
-    directiveArgs :: Arguments s
-  }
-  deriving (Show, Lift, Eq)
-
-instance KeyOf (Directive s) where
-  keyOf = directiveName
-
-type Directives s = [Directive s]
-
-data DirectiveDefinition = DirectiveDefinition
-  { directiveDefinitionName :: FieldName,
-    directiveDefinitionDescription :: Maybe Description,
-    directiveDefinitionLocations :: [DirectiveLocation],
-    directiveDefinitionArgs :: ArgumentsDefinition
-  }
-  deriving (Show, Lift)
-
-type DirectiveDefinitions = [DirectiveDefinition]
-
-instance KeyOf DirectiveDefinition where
-  keyOf = directiveDefinitionName
-
-instance Selectable DirectiveDefinition ArgumentDefinition where
-  selectOr fb f key DirectiveDefinition {directiveDefinitionArgs} =
-    selectOr fb f key directiveDefinitionArgs
-
-lookupDeprecated :: [Directive VALID] -> Maybe (Directive VALID)
-lookupDeprecated = find isDeprecation
-  where
-    isDeprecation Directive {directiveName = "deprecated"} = True
-    isDeprecation _ = False
-
-lookupDeprecatedReason :: Directive VALID -> Maybe Description
-lookupDeprecatedReason Directive {directiveArgs} =
-  selectOr Nothing (Just . maybeString) "reason" directiveArgs
-  where
-    maybeString :: Argument VALID -> Description
-    maybeString Argument {argumentValue = (Scalar (String x))} = x
-    maybeString _ = "can't read deprecated Reason Value"
+#if MIN_VERSION_template_haskell(2,16,0)
+  liftTyped _ = [||ScalarDefinition pure||]
+#endif
 
 -- ENUM VALUE
-data DataEnumValue = DataEnumValue
+data DataEnumValue s = DataEnumValue
   { enumName :: TypeName,
     enumDescription :: Maybe Description,
-    enumDirectives :: [Directive VALID]
+    enumDirectives :: [Directive s]
   }
   deriving (Show, Lift)
 
-instance RenderGQL DataEnumValue where
+instance RenderGQL (DataEnumValue s) where
   render DataEnumValue {enumName} = render enumName
 
 -- 3.2 Schema : https://graphql.github.io/graphql-spec/June2018/#sec-Schema
@@ -264,47 +236,195 @@
 -- RootOperationTypeDefinition :
 --    OperationType: NamedType
 
-data Schema = Schema
-  { types :: TypeLib,
-    query :: TypeDefinition 'Out,
-    mutation :: Maybe (TypeDefinition 'Out),
-    subscription :: Maybe (TypeDefinition 'Out)
+data Schema (s :: Stage) = Schema
+  { types :: TypeLib s,
+    query :: TypeDefinition OBJECT s,
+    mutation :: Maybe (TypeDefinition OBJECT s),
+    subscription :: Maybe (TypeDefinition OBJECT s),
+    directiveDefinitions :: [DirectiveDefinition s]
   }
+  deriving (Show, Lift)
+
+instance Merge (Schema s) where
+  merge _ s1 s2 =
+    Schema
+      <$> (types s1 <:> types s2)
+      <*> mergeOperation (query s1) (query s2)
+      <*> mergeOptional (mutation s1) (mutation s2)
+      <*> mergeOptional (subscription s1) (subscription s2)
+      <*> pure (directiveDefinitions s1 <> directiveDefinitions s2)
+
+mergeOptional ::
+  (Monad m, Failure ValidationErrors m) =>
+  Maybe (TypeDefinition OBJECT s) ->
+  Maybe (TypeDefinition OBJECT s) ->
+  m (Maybe (TypeDefinition OBJECT s))
+mergeOptional Nothing y = pure y
+mergeOptional (Just x) Nothing = pure (Just x)
+mergeOptional (Just x) (Just y) = Just <$> mergeOperation x y
+
+mergeOperation ::
+  (Monad m, Failure ValidationErrors m) =>
+  TypeDefinition OBJECT s ->
+  TypeDefinition OBJECT s ->
+  m (TypeDefinition OBJECT s)
+mergeOperation
+  TypeDefinition {typeContent = DataObject i1 fields1}
+  TypeDefinition {typeContent = DataObject i2 fields2, ..} =
+    do
+      fields <- fields1 <:> fields2
+      pure $ TypeDefinition {typeContent = DataObject (i1 <> i2) fields, ..}
+
+data SchemaDefinition = SchemaDefinition
+  { schemaDirectives :: Directives CONST,
+    unSchemaDefinition :: OrdMap OperationType RootOperationTypeDefinition
+  }
   deriving (Show)
 
-type TypeLib = HashMap TypeName (TypeDefinition ANY)
+instance Selectable OperationType RootOperationTypeDefinition SchemaDefinition where
+  selectOr fallback f key SchemaDefinition {unSchemaDefinition} =
+    selectOr fallback f key unSchemaDefinition
 
-instance Selectable Schema (TypeDefinition ANY) where
+instance NameCollision SchemaDefinition where
+  nameCollision _ = "There can Be only One SchemaDefinition."
+
+instance KeyOf TypeName SchemaDefinition where
+  keyOf _ = "schema"
+
+data RawTypeDefinition
+  = RawSchemaDefinition SchemaDefinition
+  | RawTypeDefinition (TypeDefinition ANY CONST)
+  | RawDirectiveDefinition (DirectiveDefinition CONST)
+  deriving (Show)
+
+data RootOperationTypeDefinition = RootOperationTypeDefinition
+  { rootOperationType :: OperationType,
+    rootOperationTypeDefinitionName :: TypeName
+  }
+  deriving (Show, Eq)
+
+instance NameCollision RootOperationTypeDefinition where
+  nameCollision RootOperationTypeDefinition {rootOperationType} =
+    "There can Be only One TypeDefinition for schema." <> msgValidation rootOperationType
+
+instance KeyOf OperationType RootOperationTypeDefinition where
+  keyOf = rootOperationType
+
+type TypeLib s = SafeHashMap TypeName (TypeDefinition ANY s)
+
+instance Selectable TypeName (TypeDefinition ANY s) (Schema s) where
   selectOr fb f name lib = maybe fb f (lookupDataType name lib)
 
-instance Listable (TypeDefinition ANY) Schema where
-  elems = HM.elems . typeRegister
-  fromElems types = case popByKey "Query" types of
-    (Nothing, _) -> failure (globalErrorMessage "INTERNAL: Query Not Defined")
-    (Just query, lib1) -> do
-      let (mutation, lib2) = popByKey "Mutation" lib1
-      let (subscription, lib3) = popByKey "Subscription" lib2
-      pure $ (foldr defineType (initTypeLib query) lib3) {mutation, subscription}
+instance Listable (TypeDefinition ANY s) (Schema s) where
+  elems Schema {..} =
+    elems types
+      <> concatMap fromOperation [Just query, mutation, subscription]
+  fromElems types =
+    traverse3
+      (popByKey types)
+      ( RootOperationTypeDefinition Query "Query",
+        RootOperationTypeDefinition Mutation "Mutation",
+        RootOperationTypeDefinition Subscription "Subscription"
+      )
+      >>= buildWith types
 
-initTypeLib :: TypeDefinition 'Out -> Schema
+buildWith ::
+  ( Monad f,
+    Failure ValidationErrors f
+  ) =>
+  [TypeDefinition cat s] ->
+  ( Maybe (TypeDefinition OBJECT s),
+    Maybe (TypeDefinition OBJECT s),
+    Maybe (TypeDefinition OBJECT s)
+  ) ->
+  f (Schema s)
+buildWith otypes (Just query, mutation, subscription) = do
+  let types = excludeTypes [Just query, mutation, subscription] otypes
+  let schema = (initTypeLib query) {mutation, subscription}
+  foldM (flip safeDefineType) schema types
+buildWith _ (Nothing, _, _) = failure ["Query root type must be provided." :: ValidationError]
+
+excludeTypes :: [Maybe (TypeDefinition c1 s)] -> [TypeDefinition c2 s] -> [TypeDefinition c2 s]
+excludeTypes excusionTypes = filter ((`notElem` blacklist) . typeName)
+  where
+    blacklist :: [TypeName]
+    blacklist = fmap typeName (catMaybes excusionTypes)
+
+withDirectives ::
+  [DirectiveDefinition s] ->
+  Schema s ->
+  Schema s
+withDirectives dirs Schema {..} =
+  Schema
+    { directiveDefinitions = directiveDefinitions <> dirs,
+      ..
+    }
+
+buildSchema ::
+  (Monad m, Failure ValidationErrors m) =>
+  ( Maybe SchemaDefinition,
+    [TypeDefinition ANY s],
+    [DirectiveDefinition s]
+  ) ->
+  m (Schema s)
+buildSchema (Nothing, types, dirs) = withDirectives dirs <$> fromElems types
+buildSchema (Just schemaDef, types, dirs) =
+  withDirectives
+    dirs
+    <$> ( traverse3 selectOp (Query, Mutation, Subscription)
+            >>= buildWith types
+        )
+  where
+    selectOp op = selectOperation schemaDef op types
+
+traverse3 :: Applicative t => (a -> t b) -> (a, a, a) -> t (b, b, b)
+traverse3 f (a1, a2, a3) = (,,) <$> f a1 <*> f a2 <*> f a3
+
+typeReference ::
+  (Monad m, Failure ValidationErrors m) =>
+  [TypeDefinition ANY s] ->
+  RootOperationTypeDefinition ->
+  m (Maybe (TypeDefinition OBJECT s))
+typeReference types rootOperation =
+  popByKey types rootOperation
+    >>= maybe
+      (failure ["Unknown type " <> msgValidation (rootOperationTypeDefinitionName rootOperation) <> "."])
+      (pure . Just)
+
+selectOperation ::
+  ( Monad f,
+    Failure ValidationErrors f
+  ) =>
+  SchemaDefinition ->
+  OperationType ->
+  [TypeDefinition ANY s] ->
+  f (Maybe (TypeDefinition OBJECT s))
+selectOperation schemaDef operationType lib =
+  selectOr (pure Nothing) (typeReference lib) operationType schemaDef
+
+initTypeLib :: TypeDefinition OBJECT s -> Schema s
 initTypeLib query =
   Schema
     { types = empty,
       query = query,
       mutation = Nothing,
-      subscription = Nothing
+      subscription = Nothing,
+      directiveDefinitions = empty
     }
 
-typeRegister :: Schema -> TypeLib
-typeRegister Schema {types, query, mutation, subscription} =
-  types
-    `union` HM.fromList
-      (concatMap fromOperation [Just query, mutation, subscription])
+isType :: TypeName -> TypeDefinition OBJECT s -> Maybe (TypeDefinition ANY s)
+isType name x
+  | name == typeName x = Just (toAny x)
+  | otherwise = Nothing
 
-lookupDataType :: TypeName -> Schema -> Maybe (TypeDefinition ANY)
-lookupDataType name = HM.lookup name . typeRegister
+lookupDataType :: TypeName -> Schema s -> Maybe (TypeDefinition ANY s)
+lookupDataType name Schema {types, query, mutation, subscription} =
+  isType name query
+    <|> (mutation >>= isType name)
+    <|> (subscription >>= isType name)
+    <|> selectOr Nothing Just name types
 
-isTypeDefined :: TypeName -> Schema -> Maybe DataFingerprint
+isTypeDefined :: TypeName -> Schema s -> Maybe DataFingerprint
 isTypeDefined name lib = typeFingerprint <$> lookupDataType name lib
 
 -- 3.4 Types : https://graphql.github.io/graphql-spec/June2018/#sec-Types
@@ -317,123 +437,142 @@
 --   EnumTypeDefinition
 --   InputObjectTypeDefinition
 
-data TypeDefinition (a :: TypeCategory) = TypeDefinition
+data TypeDefinition (a :: TypeCategory) (s :: Stage) = TypeDefinition
   { typeName :: TypeName,
     typeFingerprint :: DataFingerprint,
     typeDescription :: Maybe Description,
-    typeDirectives :: Directives VALID,
-    typeContent :: TypeContent TRUE a
+    typeDirectives :: Directives s,
+    typeContent :: TypeContent TRUE a s
   }
   deriving (Show, Lift)
 
-instance KeyOf (TypeDefinition a) where
-  type KEY (TypeDefinition a) = TypeName
+instance KeyOf TypeName (TypeDefinition a s) where
   keyOf = typeName
 
-data TypeCategory = In | Out | Any
-
-type IN = 'In
-
-type OUT = 'Out
-
-type ANY = 'Any
-
-class ToAny a where
-  toAny :: a (k :: TypeCategory) -> a ANY
-
-instance ToAny TypeDefinition where
-  toAny TypeDefinition {typeContent, ..} = TypeDefinition {typeContent = toAny typeContent, ..}
+instance NameCollision (TypeDefinition cat s) where
+  nameCollision x = "There can Be only One TypeDefinition Named " <> msgValidation (typeName x) <> "."
 
-instance ToAny (TypeContent TRUE) where
-  toAny DataScalar {..} = DataScalar {..}
-  toAny DataEnum {..} = DataEnum {..}
-  toAny DataInputObject {..} = DataInputObject {..}
-  toAny DataInputUnion {..} = DataInputUnion {..}
-  toAny DataObject {..} = DataObject {..}
-  toAny DataUnion {..} = DataUnion {..}
-  toAny DataInterface {..} = DataInterface {..}
+instance
+  ToCategory (TypeContent TRUE) cat cat' =>
+  ToCategory TypeDefinition cat cat'
+  where
+  toCategory TypeDefinition {typeContent, ..} =
+    TypeDefinition
+      { typeContent = toCategory typeContent,
+        ..
+      }
 
-instance ToAny FieldDefinition where
-  toAny FieldDefinition {fieldContent, ..} = FieldDefinition {fieldContent = toAny <$> fieldContent, ..}
+possibleTypes :: TypeDefinition a s -> Schema s' -> [TypeName]
+possibleTypes
+  TypeDefinition
+    { typeName,
+      typeContent = DataObject {objectImplements}
+    }
+  _ = typeName : objectImplements
+possibleTypes TypeDefinition {typeName = name, typeContent = DataInterface {}} schema =
+  name : fmap typeName (possibleInterfaceTypes name schema)
+possibleTypes TypeDefinition {typeName} _ = [typeName]
 
-instance ToAny (FieldContent TRUE) where
-  toAny (FieldArgs x) = FieldArgs x
-  toAny (DefaultInputValue x) = DefaultInputValue x
+possibleInterfaceTypes ::
+  TypeName ->
+  Schema s ->
+  [TypeDefinition ANY s]
+possibleInterfaceTypes name schema = mapMaybe (isPosibleInterfaceType name) (elems schema)
 
-class FromAny a (k :: TypeCategory) where
-  fromAny :: a ANY -> Maybe (a k)
+isPosibleInterfaceType ::
+  TypeName ->
+  TypeDefinition c s ->
+  Maybe (TypeDefinition c s)
+isPosibleInterfaceType name typeDef@TypeDefinition {typeName, typeContent = DataObject {objectImplements}}
+  | name `elem` (typeName : objectImplements) = Just typeDef
+isPosibleInterfaceType _ _ = Nothing
 
-instance (FromAny (TypeContent TRUE) a) => FromAny TypeDefinition a where
-  fromAny TypeDefinition {typeContent, ..} = bla <$> fromAny typeContent
+instance
+  (FromCategory (TypeContent TRUE) cat cat') =>
+  FromCategory TypeDefinition cat cat'
+  where
+  fromCategory TypeDefinition {typeContent, ..} = bla <$> fromCategory typeContent
     where
       bla x = TypeDefinition {typeContent = x, ..}
 
-instance FromAny (TypeContent TRUE) IN where
-  fromAny DataScalar {..} = Just DataScalar {..}
-  fromAny DataEnum {..} = Just DataEnum {..}
-  fromAny DataInputObject {..} = Just DataInputObject {..}
-  fromAny DataInputUnion {..} = Just DataInputUnion {..}
-  fromAny _ = Nothing
-
-instance FromAny (TypeContent TRUE) OUT where
-  fromAny DataScalar {..} = Just DataScalar {..}
-  fromAny DataEnum {..} = Just DataEnum {..}
-  fromAny DataObject {..} = Just DataObject {..}
-  fromAny DataUnion {..} = Just DataUnion {..}
-  fromAny DataInterface {..} = Just DataInterface {..}
-  fromAny _ = Nothing
-
-type family IsSelected (c :: TypeCategory) (a :: TypeCategory) :: Bool
-
-type instance IsSelected ANY a = TRUE
-
-type instance IsSelected OUT OUT = TRUE
-
-type instance IsSelected IN IN = TRUE
-
-type instance IsSelected IN OUT = FALSE
-
-type instance IsSelected OUT IN = FALSE
-
-type instance IsSelected a ANY = TRUE
-
-data TypeContent (b :: Bool) (a :: TypeCategory) where
+data
+  TypeContent
+    (b :: Bool)
+    (a :: TypeCategory)
+    (s :: Stage)
+  where
   DataScalar ::
     { dataScalar :: ScalarDefinition
     } ->
-    TypeContent TRUE a
+    TypeContent (ELEM LEAF a) a s
   DataEnum ::
-    { enumMembers :: DataEnum
+    { enumMembers :: DataEnum s
     } ->
-    TypeContent TRUE a
+    TypeContent (ELEM LEAF a) a s
   DataInputObject ::
-    { inputObjectFields :: FieldsDefinition IN
+    { inputObjectFields :: FieldsDefinition IN s
     } ->
-    TypeContent (IsSelected a IN) a
+    TypeContent (ELEM IN a) a s
   DataInputUnion ::
-    { inputUnionMembers :: DataInputUnion
+    { inputUnionMembers :: DataInputUnion s
     } ->
-    TypeContent (IsSelected a IN) a
+    TypeContent (ELEM IN a) a s
   DataObject ::
     { objectImplements :: [TypeName],
-      objectFields :: FieldsDefinition OUT
+      objectFields :: FieldsDefinition OUT s
     } ->
-    TypeContent (IsSelected a OUT) a
+    TypeContent (ELEM OBJECT a) a s
   DataUnion ::
-    { unionMembers :: DataUnion
+    { unionMembers :: DataUnion s
     } ->
-    TypeContent (IsSelected a OUT) a
+    TypeContent (ELEM OUT a) a s
   DataInterface ::
-    { interfaceFields :: FieldsDefinition OUT
+    { interfaceFields :: FieldsDefinition OUT s
     } ->
-    TypeContent (IsSelected a OUT) a
+    TypeContent (ELEM IMPLEMENTABLE a) a s
 
-deriving instance Show (TypeContent a b)
+deriving instance Show (TypeContent a b s)
 
-deriving instance Lift (TypeContent a b)
+deriving instance Lift (TypeContent a b s)
 
-createType :: TypeName -> TypeContent TRUE a -> TypeDefinition a
-createType typeName typeContent =
+instance ToCategory (TypeContent TRUE) a ANY where
+  toCategory DataScalar {..} = DataScalar {..}
+  toCategory DataEnum {..} = DataEnum {..}
+  toCategory DataInputObject {..} = DataInputObject {..}
+  toCategory DataInputUnion {..} = DataInputUnion {..}
+  toCategory DataObject {..} = DataObject {..}
+  toCategory DataUnion {..} = DataUnion {..}
+  toCategory DataInterface {..} = DataInterface {..}
+
+instance ToCategory (TypeContent TRUE) OBJECT IMPLEMENTABLE where
+  toCategory DataObject {..} = DataObject {..}
+
+instance FromCategory (TypeContent TRUE) ANY IN where
+  fromCategory DataScalar {..} = Just DataScalar {..}
+  fromCategory DataEnum {..} = Just DataEnum {..}
+  fromCategory DataInputObject {..} = Just DataInputObject {..}
+  fromCategory DataInputUnion {..} = Just DataInputUnion {..}
+  fromCategory _ = Nothing
+
+instance FromCategory (TypeContent TRUE) ANY OUT where
+  fromCategory DataScalar {..} = Just DataScalar {..}
+  fromCategory DataEnum {..} = Just DataEnum {..}
+  fromCategory DataObject {..} = Just DataObject {..}
+  fromCategory DataUnion {..} = Just DataUnion {..}
+  fromCategory DataInterface {..} = Just DataInterface {..}
+  fromCategory _ = Nothing
+
+instance FromCategory (TypeContent TRUE) ANY OBJECT where
+  fromCategory DataObject {..} = Just DataObject {..}
+  fromCategory _ = Nothing
+
+instance FromCategory (TypeContent TRUE) ANY IMPLEMENTABLE where
+  fromCategory DataObject {..} = Just DataObject {..}
+  fromCategory DataInterface {..} = Just DataInterface {..}
+  fromCategory _ = Nothing
+
+mkType :: TypeName -> TypeContent TRUE a s -> TypeDefinition a s
+mkType typeName typeContent =
   TypeDefinition
     { typeName,
       typeDescription = Nothing,
@@ -442,31 +581,29 @@
       typeContent
     }
 
-createScalarType :: TypeName -> TypeDefinition a
-createScalarType typeName = createType typeName $ DataScalar (ScalarDefinition pure)
+createScalarType :: ELEM LEAF a ~ TRUE => TypeName -> TypeDefinition a s
+createScalarType typeName = mkType typeName $ DataScalar (ScalarDefinition pure)
 
-createEnumType :: TypeName -> [TypeName] -> TypeDefinition a
-createEnumType typeName typeData = createType typeName (DataEnum enumValues)
-  where
-    enumValues = map createEnumValue typeData
+mkEnumContent :: ELEM LEAF a ~ TRUE => [TypeName] -> TypeContent TRUE a s
+mkEnumContent typeData = DataEnum (fmap mkEnumValue typeData)
 
-createEnumValue :: TypeName -> DataEnumValue
-createEnumValue enumName =
+mkUnionContent :: [TypeName] -> TypeContent TRUE OUT s
+mkUnionContent typeData = DataUnion $ fmap mkUnionMember typeData
+
+mkEnumValue :: TypeName -> DataEnumValue s
+mkEnumValue enumName =
   DataEnumValue
     { enumName,
       enumDescription = Nothing,
       enumDirectives = []
     }
 
-createUnionType :: TypeName -> [TypeName] -> TypeDefinition OUT
-createUnionType typeName typeData = createType typeName (DataUnion $ map mkUnionMember typeData)
-
-isEntNode :: TypeContent TRUE a -> Bool
+isEntNode :: TypeContent TRUE a s -> Bool
 isEntNode DataScalar {} = True
 isEntNode DataEnum {} = True
 isEntNode _ = False
 
-kindOf :: TypeDefinition a -> TypeKind
+kindOf :: TypeDefinition a s -> TypeKind
 kindOf TypeDefinition {typeName, typeContent} = __kind typeContent
   where
     __kind DataScalar {} = KindScalar
@@ -477,268 +614,95 @@
     __kind DataInputUnion {} = KindInputUnion
     __kind DataInterface {} = KindInterface
 
-fromOperation :: Maybe (TypeDefinition OUT) -> [(TypeName, TypeDefinition ANY)]
-fromOperation (Just datatype) = [(typeName datatype, toAny datatype)]
+fromOperation :: Maybe (TypeDefinition OBJECT s) -> [TypeDefinition ANY s]
+fromOperation (Just datatype) = [toAny datatype]
 fromOperation Nothing = []
 
-defineType :: TypeDefinition cat -> Schema -> Schema
-defineType dt@TypeDefinition {typeName, typeContent = DataInputUnion enumKeys, typeFingerprint} lib =
-  lib {types = HM.insert name unionTags (HM.insert typeName (toAny dt) (types lib))}
+safeDefineType ::
+  ( Monad m,
+    Failure ValidationErrors m
+  ) =>
+  TypeDefinition cat s ->
+  Schema s ->
+  m (Schema s)
+safeDefineType dt@TypeDefinition {typeName, typeContent = DataInputUnion enumKeys, typeFingerprint} lib = do
+  types <- insert unionTags (types lib) >>= insert (toAny dt)
+  pure lib {types}
   where
-    name = typeName <> "Tags"
     unionTags =
       TypeDefinition
-        { typeName = name,
+        { typeName = typeName <> "Tags",
           typeFingerprint,
           typeDescription = Nothing,
           typeDirectives = [],
-          typeContent = DataEnum $ map (createEnumValue . memberName) enumKeys
+          typeContent = mkEnumContent (fmap memberName enumKeys)
         }
-defineType datatype lib =
-  lib {types = HM.insert (typeName datatype) (toAny datatype) (types lib)}
+safeDefineType datatype lib = do
+  types <- insert (toAny datatype) (types lib)
+  pure lib {types}
 
 insertType ::
-  TypeDefinition ANY ->
-  TypeUpdater
-insertType datatype@TypeDefinition {typeName} lib = case isTypeDefined typeName lib of
-  Nothing -> resolveUpdates (defineType datatype lib) []
-  Just fingerprint
-    | fingerprint == typeFingerprint datatype -> return lib
-    -- throw error if 2 different types has same name
-    | otherwise -> failure $ nameCollisionError typeName
+  (Monad m, Failure ValidationErrors m) =>
+  TypeDefinition cat s ->
+  UpdateT m (Schema s)
+insertType datatype@TypeDefinition {typeName, typeFingerprint} =
+  updateSchema typeName typeFingerprint [] (const datatype) ()
 
 updateSchema ::
+  (Monad m, Failure ValidationErrors m) =>
   TypeName ->
   DataFingerprint ->
-  [TypeUpdater] ->
-  (a -> TypeDefinition cat) ->
+  [UpdateT m (Schema s)] ->
+  (a -> TypeDefinition cat s) ->
   a ->
-  TypeUpdater
-updateSchema name fingerprint stack f x lib =
-  case isTypeDefined name lib of
-    Nothing ->
-      resolveUpdates
-        (defineType (f x) lib)
-        stack
-    Just fingerprint' | fingerprint' == fingerprint -> return lib
-    -- throw error if 2 different types has same name
-    Just _ -> failure $ nameCollisionError name
+  UpdateT m (Schema s)
+updateSchema name fingerprint stack f x
+  | isNotSystemTypeName name = UpdateT $ \lib ->
+    case isTypeDefined name lib of
+      Nothing -> do
+        t <- safeDefineType (f x) lib
+        resolveUpdates t stack
+      Just fingerprint' | fingerprint' == fingerprint -> pure lib
+      -- throw error if 2 different types has same name
+      Just _ -> failure [nameCollisionError name]
+  | otherwise = concatUpdates stack
 
 lookupWith :: Eq k => (a -> k) -> k -> [a] -> Maybe a
 lookupWith f key = find ((== key) . f)
 
--- lookups and removes TypeDefinition from hashmap
-popByKey :: TypeName -> [TypeDefinition ANY] -> (Maybe (TypeDefinition OUT), [TypeDefinition ANY])
-popByKey name types = case lookupWith typeName name types of
+popByKey ::
+  (Applicative m, Failure ValidationErrors m) =>
+  [TypeDefinition ANY s] ->
+  RootOperationTypeDefinition ->
+  m (Maybe (TypeDefinition OBJECT s))
+popByKey types (RootOperationTypeDefinition opType name) = case lookupWith typeName name types of
   Just dt@TypeDefinition {typeContent = DataObject {}} ->
-    (fromAny dt, filter ((/= name) . typeName) types)
-  _ -> (Nothing, types)
-
-newtype Fields def = Fields
-  {unFields :: OrderedMap FieldName def}
-  deriving
-    ( Show,
-      Lift,
-      Functor,
-      Foldable,
-      Traversable
-    )
-
-deriving instance (KEY def ~ FieldName, KeyOf def) => Collection def (Fields def)
-
-instance Merge (FieldsDefinition cat) where
-  merge path (Fields x) (Fields y) = Fields <$> merge path x y
-
-instance Selectable (Fields (FieldDefinition cat)) (FieldDefinition cat) where
-  selectOr fb f name (Fields lib) = selectOr fb f name lib
-
-unsafeFromFields :: [FieldDefinition cat] -> FieldsDefinition cat
-unsafeFromFields = Fields . unsafeFromValues
-
-fieldsToArguments :: FieldsDefinition IN -> ArgumentsDefinition
-fieldsToArguments = ArgumentsDefinition Nothing . unFields
-
-instance (KEY def ~ FieldName, KeyOf def, NameCollision def) => Listable def (Fields def) where
-  fromElems = fmap Fields . fromElems
-  elems = elems . unFields
-
--- 3.6 Objects : https://graphql.github.io/graphql-spec/June2018/#sec-Objects
-------------------------------------------------------------------------------
---  ObjectTypeDefinition:
---    Description(opt) type Name ImplementsInterfaces(opt) Directives(Const)(opt) FieldsDefinition(opt)
---
---  ImplementsInterfaces
---    implements &(opt) NamedType
---    ImplementsInterfaces & NamedType
---
---  FieldsDefinition
---    { FieldDefinition(list) }
---
-type FieldsDefinition cat = Fields (FieldDefinition cat)
-
---  FieldDefinition
---    Description(opt) Name ArgumentsDefinition(opt) : Type Directives(Const)(opt)
---
--- https://spec.graphql.org/June2018/#InputValueDefinition
--- InputValueDefinition
---   Description(opt) Name: Type DefaultValue(opt) Directives[Const](opt)
-
-data FieldDefinition (cat :: TypeCategory) = FieldDefinition
-  { fieldName :: FieldName,
-    fieldDescription :: Maybe Description,
-    fieldType :: TypeRef,
-    fieldContent :: Maybe (FieldContent TRUE cat),
-    fieldDirectives :: [Directive VALID]
-  }
-  deriving (Show, Lift)
-
-data FieldContent (bool :: Bool) (cat :: TypeCategory) where
-  DefaultInputValue ::
-    { defaultInputValue :: Value RESOLVED
-    } ->
-    FieldContent (IsSelected cat IN) cat
-  FieldArgs ::
-    { fieldArgsDef :: ArgumentsDefinition
-    } ->
-    FieldContent (IsSelected cat OUT) cat
-
-fieldContentArgs :: FieldContent b cat -> OrderedMap FieldName ArgumentDefinition
-fieldContentArgs (FieldArgs (ArgumentsDefinition _ argsD)) = argsD
-fieldContentArgs _ = empty
-
-deriving instance Show (FieldContent bool cat)
-
-deriving instance Lift (FieldContent bool cat)
-
-instance KeyOf (FieldDefinition cat) where
-  keyOf = fieldName
-
-instance Selectable (FieldDefinition OUT) ArgumentDefinition where
-  selectOr fb f key FieldDefinition {fieldContent = Just (FieldArgs args)} = selectOr fb f key args
-  selectOr fb _ _ _ = fb
-
-instance NameCollision (FieldDefinition cat) where
-  nameCollision name _ =
-    GQLError
-      { message = "There can Be only One field Named " <> msg name,
-        locations = []
-      }
-
-instance RenderGQL (FieldDefinition cat) where
-  render FieldDefinition {fieldName = FieldName name, fieldType, fieldContent = Just (FieldArgs args)} =
-    name <> render args <> ": " <> render fieldType
-  render FieldDefinition {fieldName = FieldName name, fieldType} =
-    name <> ": " <> render fieldType
-
-instance RenderGQL (FieldsDefinition OUT) where
-  render = renderObject render . ignoreHidden . elems
-
-instance RenderGQL (FieldsDefinition IN) where
-  render = renderObject render . ignoreHidden . elems
-
-fieldVisibility :: FieldDefinition cat -> Bool
-fieldVisibility FieldDefinition {fieldName} = fieldName `notElem` sysFields
-
-isFieldNullable :: FieldDefinition cat -> Bool
-isFieldNullable = isNullable . fieldType
-
-createField :: Maybe (FieldContent TRUE cat) -> FieldName -> ([TypeWrapper], TypeName) -> FieldDefinition cat
-createField fieldContent fieldName (typeWrappers, typeConName) =
-  FieldDefinition
-    { fieldName,
-      fieldContent,
-      fieldDescription = Nothing,
-      fieldType = TypeRef {typeConName, typeWrappers, typeArgs = Nothing},
-      fieldDirectives = []
-    }
-
-mkField :: FieldName -> ([TypeWrapper], TypeName) -> FieldDefinition cat
-mkField = createField Nothing
-
-mkObjectField :: ArgumentsDefinition -> FieldName -> ([TypeWrapper], TypeName) -> FieldDefinition OUT
-mkObjectField args = createField (Just $ FieldArgs args)
-
-toNullableField :: FieldDefinition cat -> FieldDefinition cat
-toNullableField dataField
-  | isNullable (fieldType dataField) = dataField
-  | otherwise = dataField {fieldType = nullable (fieldType dataField)}
-  where
-    nullable alias@TypeRef {typeWrappers} =
-      alias {typeWrappers = TypeMaybe : typeWrappers}
-
-toListField :: FieldDefinition cat -> FieldDefinition cat
-toListField dataField = dataField {fieldType = listW (fieldType dataField)}
-  where
-    listW alias@TypeRef {typeWrappers} =
-      alias {typeWrappers = TypeList : typeWrappers}
-
--- 3.10 Input Objects: https://spec.graphql.org/June2018/#sec-Input-Objects
----------------------------------------------------------------------------
--- InputObjectTypeDefinition
--- Description(opt) input Name Directives(const,opt) InputFieldsDefinition(opt)
---
---- InputFieldsDefinition
--- { InputValueDefinition(list) }
-
-type InputFieldsDefinition = Fields InputValueDefinition
-
-type InputValueDefinition = FieldDefinition IN
-
--- 3.6.1 Field Arguments : https://graphql.github.io/graphql-spec/June2018/#sec-Field-Arguments
------------------------------------------------------------------------------------------------
--- ArgumentsDefinition:
---   (InputValueDefinition(list))
-
-data ArgumentsDefinition = ArgumentsDefinition
-  { argumentsTypename :: Maybe TypeName,
-    arguments :: OrderedMap FieldName ArgumentDefinition
-  }
-  deriving (Show, Lift)
-
-instance RenderGQL ArgumentsDefinition where
-  render ArgumentsDefinition {arguments}
-    | null arguments =
-      ""
-    | otherwise = "(" <> intercalate ", " (map render $ elems arguments) <> ")"
-
-type ArgumentDefinition = FieldDefinition IN
-
-instance Selectable ArgumentsDefinition ArgumentDefinition where
-  selectOr fb f key (ArgumentsDefinition _ args) = selectOr fb f key args
-
-instance Collection ArgumentDefinition ArgumentsDefinition where
-  empty = ArgumentsDefinition Nothing empty
-  singleton = ArgumentsDefinition Nothing . singleton
-
-instance Listable ArgumentDefinition ArgumentsDefinition where
-  elems (ArgumentsDefinition _ args) = elems args
-  fromElems args = ArgumentsDefinition Nothing <$> fromElems args
-
-createArgument :: FieldName -> ([TypeWrapper], TypeName) -> FieldDefinition IN
-createArgument = mkField
-
--- https://spec.graphql.org/June2018/#InputValueDefinition
--- InputValueDefinition
---   Description(opt) Name: TypeDefaultValue(opt) Directives[Const](opt)
--- TODO: implement inputValue
+    pure (fromAny dt)
+  Just {} ->
+    failure
+      [ msgValidation (show opType)
+          <> " root type must be Object type if provided, it cannot be "
+          <> msgValidation name
+      ]
+  _ -> pure Nothing
 
 __inputname :: FieldName
 __inputname = "inputname"
 
-createInputUnionFields :: TypeName -> [UnionMember IN] -> [FieldDefinition IN]
-createInputUnionFields name members = fieldTag : map unionField members
+mkInputUnionFields :: TypeName -> [UnionMember IN s] -> FieldsDefinition IN s
+mkInputUnionFields name members = unsafeFromFields $ fieldTag : fmap mkUnionField members
   where
     fieldTag =
       FieldDefinition
         { fieldName = __inputname,
           fieldDescription = Nothing,
           fieldContent = Nothing,
-          fieldType = createAlias (name <> "Tags"),
+          fieldType = mkTypeRef (name <> "Tags"),
           fieldDirectives = []
         }
 
-unionField :: UnionMember IN -> FieldDefinition IN
-unionField UnionMember {memberName} =
+mkUnionField :: UnionMember IN s -> FieldDefinition IN s
+mkUnionField UnionMember {memberName} =
   FieldDefinition
     { fieldName = toFieldName memberName,
       fieldDescription = Nothing,
@@ -756,35 +720,24 @@
 -- OTHER
 --------------------------------------------------------------------------------------------------
 
-createAlias :: TypeName -> TypeRef
-createAlias typeConName =
-  TypeRef {typeConName, typeWrappers = [], typeArgs = Nothing}
-
-type TypeUpdater = LibUpdater Schema
-
-instance RenderGQL Schema where
-  render schema = intercalate "\n\n" $ map render visibleTypes
+instance RenderGQL (Schema s) where
+  render schema = intercalate newline (fmap render visibleTypes)
     where
-      visibleTypes = filter (not . isSystemTypeName . typeName) (elems schema)
+      visibleTypes = filter (isNotSystemTypeName . typeName) (elems schema)
 
-instance RenderGQL (TypeDefinition a) where
-  render TypeDefinition {typeName, typeContent} = __render typeContent
+instance RenderGQL (TypeDefinition a s) where
+  render TypeDefinition {typeName, typeContent} = __render typeContent <> newline
     where
       __render DataInterface {interfaceFields} = "interface " <> render typeName <> render interfaceFields
       __render DataScalar {} = "scalar " <> render typeName
-      __render (DataEnum tags) = "enum " <> render typeName <> renderObject render tags
+      __render (DataEnum tags) = "enum " <> render typeName <> renderObject tags
       __render (DataUnion members) =
         "union "
           <> render typeName
-          <> " =\n    "
-          <> intercalate ("\n" <> renderIndent <> "| ") (map render members)
+          <> " = "
+          <> renderMembers members
       __render (DataInputObject fields) = "input " <> render typeName <> render fields
-      __render (DataInputUnion members) = "input " <> render typeName <> render fieldsDef
+      __render (DataInputUnion members) = "input " <> render typeName <> render fields
         where
-          fieldsDef = unsafeFromFields fields
-          fields :: [FieldDefinition IN]
-          fields = createInputUnionFields typeName members
+          fields = mkInputUnionFields typeName members
       __render DataObject {objectFields} = "type " <> render typeName <> render objectFields
-
-ignoreHidden :: [FieldDefinition cat] -> [FieldDefinition cat]
-ignoreHidden = filter fieldVisibility
diff --git a/src/Data/Morpheus/Types/Internal/AST/Value.hs b/src/Data/Morpheus/Types/Internal/AST/Value.hs
--- a/src/Data/Morpheus/Types/Internal/AST/Value.hs
+++ b/src/Data/Morpheus/Types/Internal/AST/Value.hs
@@ -1,14 +1,17 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE DataKinds #-}
 {-# LANGUAGE DeriveGeneric #-}
 {-# LANGUAGE DeriveLift #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE GADTs #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE StandaloneDeriving #-}
 {-# LANGUAGE TemplateHaskell #-}
 {-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Types.Internal.AST.Value
   ( Value (..),
@@ -30,6 +33,10 @@
   )
 where
 
+-- MORPHEUS
+
+import Control.Applicative (pure)
+import Control.Monad.Fail (MonadFail (fail))
 import qualified Data.Aeson as A
   ( (.=),
     FromJSON (..),
@@ -38,10 +45,13 @@
     object,
     pairs,
   )
+import Data.Either (Either (..))
+import Data.Foldable (foldl, foldl1, null)
+import Data.Functor (fmap)
 import qualified Data.HashMap.Strict as M
   ( toList,
   )
--- MORPHEUS
+import Data.Maybe (Maybe (..))
 import Data.Morpheus.Error.NameCollision
   ( NameCollision (..),
   )
@@ -54,22 +64,25 @@
 import Data.Morpheus.Types.Internal.AST.Base
   ( FieldName,
     FieldName (..),
-    GQLError (..),
     Msg (..),
     Position,
-    RAW,
-    RESOLVED,
     Ref (..),
-    Stage,
     TypeName (..),
     TypeRef,
-    TypeRef (..),
-    VALID,
+    ValidationError (..),
+    msgValidation,
   )
-import Data.Morpheus.Types.Internal.AST.OrderedMap
-  ( OrderedMap,
+import Data.Morpheus.Types.Internal.AST.OrdMap
+  ( OrdMap,
     unsafeFromValues,
   )
+import Data.Morpheus.Types.Internal.AST.Stage
+  ( CONST,
+    CONST_OR_VALID,
+    RAW,
+    Stage,
+    VALID,
+  )
 import Data.Scientific
   ( Scientific,
     floatingOrInteger,
@@ -84,6 +97,16 @@
 import GHC.Generics (Generic)
 import Instances.TH.Lift ()
 import Language.Haskell.TH.Syntax (Lift (..))
+import Prelude
+  ( ($),
+    (.),
+    Bool,
+    Eq,
+    Float,
+    Int,
+    Show (..),
+    otherwise,
+  )
 
 -- | Primitive Values for GQLScalar: 'Int', 'Float', 'String', 'Boolean'.
 -- for performance reason type 'Text' represents GraphQl 'String' value
@@ -112,22 +135,18 @@
   parseJSON (A.String v) = pure $ String v
   parseJSON notScalar = fail $ "Expected Scalar got :" <> show notScalar
 
-type family VAR (a :: Stage) :: Stage
-
-type instance VAR RAW = RESOLVED
-
-type instance VAR RESOLVED = RESOLVED
-
-type instance VAR VALID = VALID
-
 data VariableContent (stage :: Stage) where
-  DefaultValue :: Maybe ResolvedValue -> VariableContent RESOLVED
+  DefaultValue :: Maybe ResolvedValue -> VariableContent CONST
   ValidVariableValue :: {validVarContent :: ValidValue} -> VariableContent VALID
 
 instance Lift (VariableContent a) where
   lift (DefaultValue x) = [|DefaultValue x|]
   lift (ValidVariableValue x) = [|ValidVariableValue x|]
 
+#if MIN_VERSION_template_haskell(2,16,0)
+  liftTyped (DefaultValue x) = [||DefaultValue x||]
+  liftTyped (ValidVariableValue x) = [||ValidVariableValue x||]
+#endif
 deriving instance Show (VariableContent a)
 
 deriving instance Eq (VariableContent a)
@@ -136,24 +155,24 @@
   { variableName :: FieldName,
     variableType :: TypeRef,
     variablePosition :: Position,
-    variableValue :: VariableContent (VAR stage)
+    variableValue :: VariableContent (CONST_OR_VALID stage)
   }
   deriving (Show, Eq, Lift)
 
-instance KeyOf (Variable s) where
+instance KeyOf FieldName (Variable s) where
   keyOf = variableName
 
 instance NameCollision (Variable s) where
-  nameCollision _ Variable {variableName, variablePosition} =
-    GQLError
-      { message = "There can Be only One Variable Named " <> msg variableName,
-        locations = [variablePosition]
+  nameCollision Variable {variableName, variablePosition} =
+    ValidationError
+      { validationMessage = "There can Be only One Variable Named " <> msg variableName,
+        validationLocations = [variablePosition]
       }
 
-type VariableDefinitions s = OrderedMap FieldName (Variable s)
+type VariableDefinitions s = OrdMap FieldName (Variable s)
 
 data Value (stage :: Stage) where
-  ResolvedVariable :: Ref -> Variable VALID -> Value RESOLVED
+  ResolvedVariable :: Ref -> Variable VALID -> Value CONST
   VariableValue :: Ref -> Value RAW
   Object :: Object stage -> Value stage
   List :: [Value stage] -> Value stage
@@ -175,39 +194,34 @@
   render (ObjectEntry (FieldName name) value) = name <> ": " <> render value
 
 instance NameCollision (ObjectEntry s) where
-  nameCollision _ ObjectEntry {entryName} =
-    GQLError
-      { message = "There can Be only One field Named " <> msg entryName,
-        locations = []
-      }
+  nameCollision ObjectEntry {entryName} =
+    "There can Be only One field Named " <> msgValidation entryName :: ValidationError
 
-instance KeyOf (ObjectEntry s) where
+instance KeyOf FieldName (ObjectEntry s) where
   keyOf = entryName
 
-type Object a = OrderedMap FieldName (ObjectEntry a)
+type Object a = OrdMap FieldName (ObjectEntry a)
 
 type ValidObject = Object VALID
 
 type RawObject = Object RAW
 
-type ResolvedObject = Object RESOLVED
+type ResolvedObject = Object CONST
 
 type RawValue = Value RAW
 
 type ValidValue = Value VALID
 
-type ResolvedValue = Value RESOLVED
+type ResolvedValue = Value CONST
 
 deriving instance Lift (Value a)
 
 deriving instance Lift (ObjectEntry a)
 
 instance RenderGQL (Value a) where
-  -- TODO: fix
   render (ResolvedVariable Ref {refName} _) =
     "$" <> readName refName
   render (VariableValue Ref {refName}) = "$" <> readName refName <> " "
-  -- TODO: fix
   render Null = "null"
   render (Enum x) = readTypeName x
   render (Scalar x) = render x
@@ -236,7 +250,7 @@
   toJSON (Enum (TypeName x)) = A.String x
   toJSON (Scalar x) = A.toJSON x
   toJSON (List x) = A.toJSON x
-  toJSON (Object fields) = A.object $ map toEntry (elems fields)
+  toJSON (Object fields) = A.object $ fmap toEntry (elems fields)
     where
       toEntry (ObjectEntry (FieldName name) value) = name A..= A.toJSON value
 
@@ -251,7 +265,7 @@
   toEncoding (List x) = A.toEncoding x
   toEncoding (Object ordmap)
     | null ordmap = A.toEncoding $ A.object []
-    | otherwise = A.pairs $ foldl1 (<>) $ map encodeField (elems ordmap)
+    | otherwise = A.pairs $ foldl1 (<>) $ fmap encodeField (elems ordmap)
     where
       encodeField (ObjectEntry (FieldName key) value) = key A..= value
 
@@ -266,10 +280,10 @@
 replaceValue (A.String v) = gqlString v
 replaceValue (A.Object v) =
   gqlObject $
-    map
+    fmap
       (mapTuple FieldName replaceValue)
       (M.toList v)
-replaceValue (A.Array li) = gqlList (map replaceValue (V.toList li))
+replaceValue (A.Array li) = gqlList (fmap replaceValue (V.toList li))
 replaceValue A.Null = gqlNull
 
 instance A.FromJSON (Value a) where
@@ -291,6 +305,6 @@
   gqlBoolean = Scalar . Boolean
   gqlString = Scalar . String
   gqlList = List
-  gqlObject = Object . unsafeFromValues . map toEntry
+  gqlObject = Object . unsafeFromValues . fmap toEntry
     where
       toEntry (key, value) = ObjectEntry key value
diff --git a/src/Data/Morpheus/Types/Internal/Config.hs b/src/Data/Morpheus/Types/Internal/Config.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Morpheus/Types/Internal/Config.hs
@@ -0,0 +1,40 @@
+{-# LANGUAGE NoImplicitPrelude #-}
+
+module Data.Morpheus.Types.Internal.Config
+  ( Config (..),
+    VALIDATION_MODE (..),
+    defaultConfig,
+    debugConfig,
+  )
+where
+
+import Prelude
+  ( Bool (..),
+    Eq,
+    Show,
+  )
+
+data VALIDATION_MODE
+  = WITHOUT_VARIABLES
+  | FULL_VALIDATION
+  deriving (Eq, Show)
+
+data Config = Config
+  { debug :: Bool,
+    validationMode :: VALIDATION_MODE
+  }
+  deriving (Show)
+
+defaultConfig :: Config
+defaultConfig =
+  Config
+    { debug = False,
+      validationMode = FULL_VALIDATION
+    }
+
+debugConfig :: Config
+debugConfig =
+  Config
+    { debug = True,
+      validationMode = FULL_VALIDATION
+    }
diff --git a/src/Data/Morpheus/Types/Internal/Resolving.hs b/src/Data/Morpheus/Types/Internal/Resolving.hs
--- a/src/Data/Morpheus/Types/Internal/Resolving.hs
+++ b/src/Data/Morpheus/Types/Internal/Resolving.hs
@@ -1,38 +1,32 @@
 {-# LANGUAGE NamedFieldPuns #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Types.Internal.Resolving
   ( Event (..),
-    UnSubResolver,
     Resolver,
-    MapStrategy (..),
     LiftOperation,
     runRootResModel,
-    toResolver,
     lift,
     SubEvent,
     Eventless,
     Failure (..),
-    GQLChannel (..),
+    eventChannels,
     ResponseEvent (..),
     ResponseStream,
     cleanEvents,
     Result (..),
     ResultT (..),
     unpackEvents,
-    LibUpdater,
-    resolveUpdates,
-    setTypeName,
     ObjectResModel (..),
     ResModel (..),
     FieldResModel,
     WithOperation,
     PushEvents (..),
     subscribe,
-    Context (..),
+    ResolverContext (..),
     unsafeInternalContext,
     RootResModel (..),
-    unsafeBind,
-    liftStateless,
     resultOr,
     withArguments,
     -- Dynamic Resolver
@@ -45,17 +39,48 @@
     mkObject,
     mkNull,
     mkString,
+    SubscriptionField (..),
+    getArguments,
+    Channel (..),
+    ResolverState,
+    liftResolverState,
+    mkValue,
   )
 where
 
+import Control.Applicative (pure)
+import Control.Monad (Monad)
+import qualified Data.Aeson as A
+import Data.Functor (fmap)
+import qualified Data.HashMap.Strict as HM
+  ( lookup,
+    toList,
+  )
+import Data.Maybe (maybe)
+import Data.Morpheus.Internal.Utils
+  ( mapTuple,
+  )
 import Data.Morpheus.Types.Internal.AST
-  ( FieldName,
+  ( FieldName (..),
     ScalarValue (..),
     Token,
-    TypeName,
+    TypeName (..),
+    decodeScientific,
   )
 import Data.Morpheus.Types.Internal.Resolving.Core
+import Data.Morpheus.Types.Internal.Resolving.Event
 import Data.Morpheus.Types.Internal.Resolving.Resolver
+import Data.Morpheus.Types.Internal.Resolving.ResolverState
+import qualified Data.Vector as V
+  ( toList,
+  )
+import Prelude
+  ( ($),
+    (.),
+    Bool,
+    Float,
+    Int,
+  )
 
 mkString :: Token -> ResModel o e m
 mkString = ResScalar . String
@@ -80,6 +105,26 @@
 
 mkNull :: ResModel o e m
 mkNull = ResNull
+
+unPackName :: A.Value -> TypeName
+unPackName (A.String x) = TypeName x
+unPackName _ = "__JSON__"
+
+mkValue ::
+  (LiftOperation o, Monad m) =>
+  A.Value ->
+  ResModel o e m
+mkValue (A.Object v) =
+  mkObject
+    (maybe "__JSON__" unPackName $ HM.lookup "__typename" v)
+    $ fmap
+      (mapTuple FieldName (pure . mkValue))
+      (HM.toList v)
+mkValue (A.Array ls) = mkList (fmap mkValue (V.toList ls))
+mkValue A.Null = mkNull
+mkValue (A.Number x) = ResScalar (decodeScientific x)
+mkValue (A.String x) = ResScalar (String x)
+mkValue (A.Bool x) = ResScalar (Boolean x)
 
 mkObject ::
   TypeName ->
diff --git a/src/Data/Morpheus/Types/Internal/Resolving/Core.hs b/src/Data/Morpheus/Types/Internal/Resolving/Core.hs
--- a/src/Data/Morpheus/Types/Internal/Resolving/Core.hs
+++ b/src/Data/Morpheus/Types/Internal/Resolving/Core.hs
@@ -1,13 +1,10 @@
-{-# LANGUAGE DataKinds #-}
 {-# LANGUAGE DeriveFunctor #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE PolyKinds #-}
-{-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Types.Internal.Resolving.Core
   ( Eventless,
@@ -15,32 +12,31 @@
     Failure (..),
     ResultT (..),
     unpackEvents,
-    LibUpdater,
-    resolveUpdates,
     mapEvent,
     cleanEvents,
-    Event (..),
-    Channel (..),
-    GQLChannel (..),
     PushEvents (..),
-    statelessToResultT,
     resultOr,
   )
 where
 
-import Control.Applicative (liftA2)
-import Control.Monad (foldM)
+import Control.Applicative (Applicative (..), liftA2)
+import Control.Monad (Monad (..))
 import Control.Monad.Trans.Class (MonadTrans (..))
-import Data.Function ((&))
+import Data.Functor ((<$>), Functor (..))
 import Data.Morpheus.Internal.Utils
   ( Failure (..),
   )
 import Data.Morpheus.Types.Internal.AST.Base
   ( GQLError (..),
     GQLErrors,
-    Message,
+    ValidationError (..),
+    toGQLError,
   )
 import Data.Semigroup ((<>))
+import Prelude
+  ( ($),
+    (.),
+  )
 
 type Eventless = Result ()
 
@@ -48,29 +44,6 @@
 class PushEvents e m where
   pushEvents :: [e] -> m ()
 
--- Channel
-newtype Channel event = Channel
-  { _unChannel :: StreamChannel event
-  }
-
-instance (Eq (StreamChannel event)) => Eq (Channel event) where
-  Channel x == Channel y = x == y
-
-class GQLChannel a where
-  type StreamChannel a :: *
-  streamChannels :: a -> [Channel a]
-
-instance GQLChannel () where
-  type StreamChannel () = ()
-  streamChannels _ = []
-
-instance GQLChannel (Event channel content) where
-  type StreamChannel (Event channel content) = channel
-  streamChannels Event {channels} = map Channel channels
-
-data Event e c = Event
-  {channels :: [e], content :: c}
-
 unpackEvents :: Result event a -> [event]
 unpackEvents Success {events} = events
 unpackEvents _ = []
@@ -101,13 +74,12 @@
 instance Failure [GQLError] (Result ev) where
   failure = Failure
 
-instance Failure Message (Result e) where
-  failure text =
-    Failure [GQLError {message = "INTERNAL: " <> text, locations = []}]
-
 instance PushEvents events (Result events) where
   pushEvents events = Success {result = (), warnings = [], events}
 
+instance Failure [ValidationError] (Result ev) where
+  failure = failure . fmap toGQLError
+
 resultOr :: (GQLErrors -> a') -> (a -> a') -> Result e a -> a'
 resultOr _ f (Success x _ _) = f x
 resultOr f _ (Failure e) = f e
@@ -118,15 +90,6 @@
   }
   deriving (Functor)
 
-statelessToResultT ::
-  Applicative m =>
-  Eventless a ->
-  ResultT e m a
-statelessToResultT =
-  cleanEvents
-    . ResultT
-    . pure
-
 instance Applicative m => Applicative (ResultT event m) where
   pure = ResultT . pure . pure
   ResultT app1 <*> ResultT app2 = ResultT $ liftA2 (<*>) app1 app2
@@ -146,16 +109,9 @@
 instance MonadTrans (ResultT event) where
   lift = ResultT . fmap pure
 
--- instance Applicative m => Failure String (ResultT event m) where
---   failure x =
---     ResultT $ pure $ Failure [GQLError {message = pack x, locations = []}]
-
 instance Monad m => Failure GQLErrors (ResultT event m) where
   failure = ResultT . pure . failure
 
-instance Applicative m => Failure Message (ResultT event m) where
-  failure = ResultT . pure . failure
-
 instance Applicative m => PushEvents event (ResultT event m) where
   pushEvents = ResultT . pure . pushEvents
 
@@ -176,11 +132,5 @@
 mapEvent func (ResultT ma) = ResultT $ mapEv <$> ma
   where
     mapEv Success {result, warnings, events} =
-      Success {result, warnings, events = map func events}
+      Success {result, warnings, events = fmap func events}
     mapEv (Failure err) = Failure err
-
--- Helper Functions
-type LibUpdater lib = lib -> Eventless lib
-
-resolveUpdates :: Monad m => lib -> [lib -> m lib] -> m lib
-resolveUpdates = foldM (&)
diff --git a/src/Data/Morpheus/Types/Internal/Resolving/Event.hs b/src/Data/Morpheus/Types/Internal/Resolving/Event.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Morpheus/Types/Internal/Resolving/Event.hs
@@ -0,0 +1,32 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE KindSignatures #-}
+{-# LANGUAGE NamedFieldPuns #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+module Data.Morpheus.Types.Internal.Resolving.Event
+  ( Event (..),
+    Channel (..),
+    eventChannels,
+  )
+where
+
+import Prelude
+  ( Eq (..),
+    fmap,
+  )
+
+-- Channel
+data Channel (event :: *) where
+  Channel :: a -> Channel (Event a c)
+
+data Event e c = Event
+  { channels :: [e],
+    content :: c
+  }
+
+eventChannels :: Event e c -> [Channel (Event e c)]
+eventChannels Event {channels} = fmap Channel channels
+
+instance (Eq ch) => Eq (Channel (Event ch con)) where
+  Channel x == Channel y = x == y
diff --git a/src/Data/Morpheus/Types/Internal/Resolving/Resolver.hs b/src/Data/Morpheus/Types/Internal/Resolving/Resolver.hs
--- a/src/Data/Morpheus/Types/Internal/Resolving/Resolver.hs
+++ b/src/Data/Morpheus/Types/Internal/Resolving/Resolver.hs
@@ -6,7 +6,6 @@
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE GADTs #-}
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE InstanceSigs #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE OverloadedStrings #-}
@@ -15,47 +14,48 @@
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE StandaloneDeriving #-}
 {-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE TypeOperators #-}
 {-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Types.Internal.Resolving.Resolver
   ( Event (..),
-    UnSubResolver,
     Resolver,
-    MapStrategy (..),
     LiftOperation,
-    unsafeBind,
-    toResolver,
     lift,
     subscribe,
     SubEvent,
-    GQLChannel (..),
     ResponseEvent (..),
     ResponseStream,
     ObjectResModel (..),
     ResModel (..),
     FieldResModel,
     WithOperation,
-    Context (..),
+    ResolverContext (..),
     unsafeInternalContext,
     runRootResModel,
-    setTypeName,
     RootResModel (..),
-    liftStateless,
     withArguments,
+    getArguments,
+    SubscriptionField (..),
+    liftResolverState,
   )
 where
 
+import Control.Applicative (Applicative (..))
+import Control.Monad (Monad (..), join)
 import Control.Monad.Fail (MonadFail (..))
 import Control.Monad.IO.Class (MonadIO (..))
+import Control.Monad.Reader (MonadReader (..), asks)
 import Control.Monad.Trans.Class (MonadTrans (..))
-import Control.Monad.Trans.Reader (ReaderT (..), ask, mapReaderT, withReaderT)
-import Data.Maybe (maybe)
--- MORPHEUS
-import Data.Morpheus.Error.Internal (internalResolvingError)
+import Control.Monad.Trans.Reader
+  ( ReaderT (..),
+    mapReaderT,
+  )
+import Data.Functor ((<$>), Functor (..))
+import Data.Maybe (Maybe (..), maybe)
 import Data.Morpheus.Error.Selection (subfieldsNotSelected)
 import Data.Morpheus.Internal.Utils
-  ( Merge (..),
+  ( SemigroupM (..),
     empty,
     keyOf,
     selectOr,
@@ -64,60 +64,72 @@
   ( GQLResponse,
     renderResponse,
   )
-import Data.Morpheus.Types.Internal.AST.Base
-  ( FieldName,
-    GQLError (..),
+import Data.Morpheus.Types.Internal.AST
+  ( Arguments,
+    FieldName,
     GQLErrors,
+    GQLValue (..),
+    InternalError,
     MUTATION,
     Message,
+    ObjectEntry (..),
+    Operation (..),
     OperationType,
     OperationType (..),
     QUERY,
     SUBSCRIPTION,
-    TypeName (..),
-    VALID,
-    msg,
-  )
-import Data.Morpheus.Types.Internal.AST.MergeSet
-  ( toOrderedMap,
-  )
-import Data.Morpheus.Types.Internal.AST.Selection
-  ( Operation (..),
+    ScalarValue (..),
     Selection (..),
     SelectionContent (..),
     SelectionSet,
+    TypeName (..),
     UnionSelection,
     UnionTag (..),
-  )
-import Data.Morpheus.Types.Internal.AST.TypeSystem
-  ( Arguments,
-    Schema,
-  )
-import Data.Morpheus.Types.Internal.AST.Value
-  ( GQLValue (..),
-    ObjectEntry (..),
-    ScalarValue (..),
+    VALID,
     ValidValue,
     Value (..),
+    msg,
+    toGQLError,
   )
+import Data.Morpheus.Types.Internal.AST.MergeSet
+  ( toOrdMap,
+  )
 import Data.Morpheus.Types.Internal.Resolving.Core
-  ( Channel (..),
-    Event (..),
-    Eventless,
+  ( Eventless,
     Failure (..),
-    GQLChannel (..),
     PushEvents (..),
     Result (..),
     ResultT (..),
-    StreamChannel,
     cleanEvents,
     mapEvent,
-    statelessToResultT,
   )
+import Data.Morpheus.Types.Internal.Resolving.Event
+  ( Channel (..),
+    Event (..),
+  )
+import Data.Morpheus.Types.Internal.Resolving.ResolverState
+  ( ResolverContext (..),
+    ResolverState,
+    ResolverStateT (..),
+    clearStateResolverEvents,
+    resolverFailureMessage,
+    runResolverState,
+    runResolverStateM,
+    runResolverStateT,
+    toResolverStateT,
+  )
 import Data.Semigroup
-  ( (<>),
-    Semigroup (..),
+  ( Semigroup (..),
   )
+import Data.Traversable (traverse)
+import Prelude
+  ( ($),
+    (.),
+    Eq (..),
+    Show (..),
+    lookup,
+    otherwise,
+  )
 
 type WithOperation (o :: OperationType) = LiftOperation o
 
@@ -129,74 +141,24 @@
 
 type SubEvent event m = Event (Channel event) (event -> m GQLResponse)
 
--- | A datatype to expose 'Schema' and the query's AST information ('Selection', 'Operation').
-data Context = Context
-  { currentSelection :: Selection VALID,
-    schema :: Schema,
-    operation :: Operation VALID,
-    currentTypeName :: TypeName
-  }
-  deriving (Show)
-
--- Resolver Internal State
-newtype ResolverState event m a = ResolverState
-  { runResolverState :: ReaderT Context (ResultT event m) a
-  }
-  deriving
-    ( Functor,
-      Applicative,
-      Monad
-    )
-
-instance MonadTrans (ResolverState e) where
-  lift = ResolverState . lift . lift
-
-instance (Monad m) => Failure Message (ResolverState e m) where
-  failure message = ResolverState $ do
-    selection <- currentSelection <$> ask
-    lift $ failure [resolverFailureMessage selection message]
-
-instance (Monad m) => Failure GQLErrors (ResolverState e m) where
-  failure = ResolverState . lift . failure
-
-instance (Monad m) => PushEvents e (ResolverState e m) where
-  pushEvents = ResolverState . lift . pushEvents
-
-mapResolverState ::
-  ( ReaderT Context (ResultT e m) a ->
-    ReaderT Context (ResultT e' m') a'
-  ) ->
-  ResolverState e m a ->
-  ResolverState e' m' a'
-mapResolverState f (ResolverState x) = ResolverState (f x)
-
-getState :: (Monad m) => ResolverState e m (Selection VALID)
-getState = ResolverState $ currentSelection <$> ask
-
-mapState :: (Context -> Context) -> ResolverState e m a -> ResolverState e m a
-mapState f = mapResolverState (withReaderT f)
-
--- clear evets and starts new resolver with diferenct type of events but with same value
--- use properly. only if you know what you are doing
-clearStateResolverEvents :: (Functor m) => ResolverState e m a -> ResolverState e' m a
-clearStateResolverEvents = mapResolverState (mapReaderT cleanEvents)
-
-resolverFailureMessage :: Selection VALID -> Message -> GQLError
-resolverFailureMessage Selection {selectionName, selectionPosition} message =
-  GQLError
-    { message = "Failure on Resolving Field " <> msg selectionName <> ": " <> message,
-      locations = [selectionPosition]
-    }
+data SubscriptionField (a :: *) where
+  SubscriptionField ::
+    { channel :: forall e m v. a ~ Resolver SUBSCRIPTION e m v => Channel e,
+      unSubscribe :: a
+    } ->
+    SubscriptionField a
 
 --
 -- GraphQL Field Resolver
 --
 ---------------------------------------------------------------
 data Resolver (o :: OperationType) event (m :: * -> *) value where
-  ResolverQ :: {runResolverQ :: ResolverState () m value} -> Resolver QUERY event m value
-  ResolverM :: {runResolverM :: ResolverState event m value} -> Resolver MUTATION event m value
-  ResolverS :: {runResolverS :: ResolverState (Channel event) m (ReaderT event (Resolver QUERY event m) value)} -> Resolver SUBSCRIPTION event m value
+  ResolverQ :: {runResolverQ :: ResolverStateT () m value} -> Resolver QUERY event m value
+  ResolverM :: {runResolverM :: ResolverStateT event m value} -> Resolver MUTATION event m value
+  ResolverS :: {runResolverS :: ResolverStateT () m (SubEventRes event m value)} -> Resolver SUBSCRIPTION event m value
 
+type SubEventRes event m value = ReaderT event (ResolverStateT () m) value
+
 instance Show (Resolver o e m value) where
   show ResolverQ {} = "Resolver QUERY e m a"
   show ResolverM {} = "Resolver MUTATION e m a"
@@ -214,12 +176,24 @@
 -- Monad
 instance (Monad m, LiftOperation o) => Monad (Resolver o e m) where
   return = pure
-  (>>=) = unsafeBind
+  (ResolverQ x) >>= m2 = ResolverQ (x >>= runResolverQ . m2)
+  (ResolverM x) >>= m2 = ResolverM (x >>= runResolverM . m2)
+  (ResolverS res) >>= m2 = ResolverS (liftSubResolver m2 <$> res)
 
 #if __GLASGOW_HASKELL__ < 808
   fail = failure . msg
 # endif
 
+liftSubResolver ::
+  (Monad m) =>
+  (t -> Resolver SUBSCRIPTION r m a) ->
+  ReaderT r (ResolverStateT () m) t ->
+  ReaderT r (ResolverStateT () m) a
+liftSubResolver m2 readResA = ReaderT $ \e -> do
+  a <- runReaderT readResA e
+  readResB <- runResolverS (m2 a)
+  runReaderT readResB e
+
 -- MonadIO
 instance (MonadIO m, LiftOperation o) => MonadIO (Resolver o e m) where
   liftIO = lift . liftIO
@@ -245,137 +219,74 @@
 instance (Monad m, Semigroup a, LiftOperation o) => Semigroup (Resolver o e m a) where
   x <> y = fmap (<>) x <*> y
 
-liftStateless ::
-  ( LiftOperation o,
-    Monad m
-  ) =>
-  Eventless a ->
-  Resolver o e m a
-liftStateless =
-  packResolver
-    . ResolverState
-    . ReaderT
-    . const
-    . statelessToResultT
+instance (LiftOperation o, Monad m) => MonadReader ResolverContext (Resolver o e m) where
+  ask = packResolver ask
+  local f (ResolverQ res) = ResolverQ (local f res)
+  local f (ResolverM res) = ResolverM (local f res)
+  local f (ResolverS resM) = ResolverS $ mapReaderT (local f) <$> resM
 
+-- | A function to return the internal 'ResolverContext' within a resolver's monad.
+-- Using the 'ResolverContext' itself is unsafe because it expposes internal structures
+-- of the AST, but you can use the "Data.Morpheus.Types.SelectionTree" typeclass to manipulate
+-- the internal AST with a safe interface.
+unsafeInternalContext :: (Monad m, LiftOperation o) => Resolver o e m ResolverContext
+unsafeInternalContext = ask
+
+liftResolverState :: (LiftOperation o, Monad m) => ResolverState a -> Resolver o e m a
+liftResolverState = packResolver . toResolverStateT
+
 class LiftOperation (o :: OperationType) where
-  packResolver :: Monad m => ResolverState e m a -> Resolver o e m a
-  withResolver :: Monad m => ResolverState e m a -> (a -> Resolver o e m b) -> Resolver o e m b
+  packResolver :: Monad m => ResolverStateT e m a -> Resolver o e m a
 
--- packResolver
 instance LiftOperation QUERY where
   packResolver = ResolverQ . clearStateResolverEvents
-  withResolver ctxRes toRes = ResolverQ $ do
-    v <- clearStateResolverEvents ctxRes
-    runResolverQ $ toRes v
 
 instance LiftOperation MUTATION where
   packResolver = ResolverM
-  withResolver ctxRes toRes = ResolverM $ ctxRes >>= runResolverM . toRes
 
 instance LiftOperation SUBSCRIPTION where
-  packResolver = ResolverS . pure . lift . packResolver
-  withResolver ctxRes toRes = ResolverS $ do
-    value <- clearStateResolverEvents ctxRes
-    runResolverS $ toRes value
-
-mapResolverContext :: Monad m => (Context -> Context) -> Resolver o e m a -> Resolver o e m a
-mapResolverContext f (ResolverQ res) = ResolverQ (mapState f res)
-mapResolverContext f (ResolverM res) = ResolverM (mapState f res)
-mapResolverContext f (ResolverS resM) = ResolverS $ do
-  res <- resM
-  pure $ ReaderT $ \e -> ResolverQ $ mapState f (runResolverQ (runReaderT res e))
-
-setSelection :: Monad m => Selection VALID -> Resolver o e m a -> Resolver o e m a
-setSelection currentSelection =
-  mapResolverContext (\ctx -> ctx {currentSelection})
-
-setTypeName :: Monad m => TypeName -> Resolver o e m a -> Resolver o e m a
-setTypeName currentTypeName =
-  mapResolverContext (\ctx -> ctx {currentTypeName})
-
--- unsafe variant of >>= , not for public api. user can be confused:
---  ignores `channels` on second Subsciption, only returns events from first Subscription monad.
---    reason: second monad is waiting for `event` until he does not have some event can't tell which
---            channel does it have to listen
-unsafeBind ::
-  forall o e m a b.
-  Monad m =>
-  Resolver o e m a ->
-  (a -> Resolver o e m b) ->
-  Resolver o e m b
-unsafeBind (ResolverQ x) m2 = ResolverQ (x >>= runResolverQ . m2)
-unsafeBind (ResolverM x) m2 = ResolverM (x >>= runResolverM . m2)
-unsafeBind (ResolverS res) m2 = ResolverS $ do
-  (readResA :: ReaderT e (Resolver QUERY e m) a) <- res
-  pure $ ReaderT $ \e -> ResolverQ $ do
-    let (resA :: Resolver QUERY e m a) = runReaderT readResA e
-    (valA :: a) <- runResolverQ resA
-    (readResB :: ReaderT e (Resolver QUERY e m) b) <- clearStateResolverEvents $ runResolverS (m2 valA)
-    runResolverQ $ runReaderT readResB e
+  packResolver = ResolverS . pure . lift . clearStateResolverEvents
 
 subscribe ::
-  forall e m a.
-  ( PushEvents (Channel e) (ResolverState (Channel e) m),
-    Monad m
-  ) =>
-  [StreamChannel e] ->
-  Resolver QUERY e m (e -> Resolver QUERY e m a) ->
-  Resolver SUBSCRIPTION e m a
-subscribe ch res = ResolverS $ do
-  pushEvents (map Channel ch :: [Channel e])
-  (eventRes :: e -> Resolver QUERY e m a) <- clearStateResolverEvents (runResolverQ res)
-  pure $ ReaderT eventRes
-
--- | A function to return the internal 'Context' within a resolver's monad.
--- Using the 'Context' itself is unsafe because it expposes internal structures
--- of the AST, but you can use the "Data.Morpheus.Types.SelectionTree" typeclass to manipulate
--- the internal AST with a safe interface.
-unsafeInternalContext :: (Monad m, LiftOperation o) => Resolver o e m Context
-unsafeInternalContext = packResolver $ ResolverState ask
-
--- Converts Subscription Resolver Type to Query Resolver
-type family UnSubResolver (a :: * -> *) :: (* -> *)
-
-type instance UnSubResolver (Resolver SUBSCRIPTION e m) = Resolver QUERY e m
+  forall e channel cont m a.
+  (Monad m, Event channel cont ~ e) =>
+  channel ->
+  Resolver QUERY e m (e -> Resolver SUBSCRIPTION e m a) ->
+  SubscriptionField (Resolver SUBSCRIPTION e m a)
+subscribe ch res =
+  SubscriptionField (Channel ch)
+    $ ResolverS
+    $ fromSub <$> runResolverQ res
+  where
+    fromSub :: (e -> Resolver SUBSCRIPTION e m a) -> ReaderT e (ResolverStateT () m) a
+    fromSub f = join (ReaderT $ \e -> runResolverS (f e))
 
 withArguments ::
-  forall o e m a.
   (LiftOperation o, Monad m) =>
   (Arguments VALID -> Resolver o e m a) ->
   Resolver o e m a
-withArguments = withResolver args
-  where
-    args :: ResolverState e m (Arguments VALID)
-    args = selectionArguments <$> getState
+withArguments = (getArguments >>=)
 
---
--- Selection Processing
-toResolver ::
-  forall o e m a b.
+getArguments ::
   (LiftOperation o, Monad m) =>
-  (Arguments VALID -> Eventless a) ->
-  (a -> Resolver o e m b) ->
-  Resolver o e m b
-toResolver toArgs = withResolver args
-  where
-    args :: ResolverState e m a
-    args =
-      ResultT . pure . toArgs . selectionArguments <$> getState
-        >>= ResolverState . lift . cleanEvents
+  Resolver o e m (Arguments VALID)
+getArguments = selectionArguments . currentSelection <$> unsafeInternalContext
 
 pickSelection :: TypeName -> UnionSelection VALID -> SelectionSet VALID
 pickSelection = selectOr empty unionTagSelection
 
 withObject ::
   (LiftOperation o, Monad m) =>
+  TypeName ->
   (SelectionSet VALID -> Resolver o e m value) ->
   Selection VALID ->
   Resolver o e m value
-withObject f Selection {selectionName, selectionContent, selectionPosition} = checkContent selectionContent
+withObject __typename f Selection {selectionName, selectionContent, selectionPosition} = checkContent selectionContent
   where
     checkContent (SelectionSet selection) = f selection
-    checkContent _ = failure (subfieldsNotSelected selectionName "" selectionPosition)
+    checkContent (UnionSelection unionSel) =
+      f (selectOr empty unionTagSelection __typename unionSel)
+    checkContent _ = failure [toGQLError $ subfieldsNotSelected selectionName "" selectionPosition]
 
 lookupRes ::
   (LiftOperation o, Monad m) =>
@@ -388,7 +299,7 @@
   | otherwise =
     maybe
       (pure gqlNull)
-      (`unsafeBind` runDataResolver)
+      (>>= runDataResolver)
       . lookup selectionName
       . objectFields
 
@@ -399,30 +310,23 @@
   ResModel o e m ->
   Resolver o e m ValidValue
 resolveObject selectionSet (ResObject drv@ObjectResModel {__typename}) =
-  Object . toOrderedMap <$> traverse resolver selectionSet
+  Object . toOrdMap <$> traverse resolver selectionSet
   where
     resolver :: Selection VALID -> Resolver o e m (ObjectEntry VALID)
-    resolver sel =
-      setSelection sel
-        $ setTypeName __typename
-        $ ObjectEntry (keyOf sel) <$> lookupRes sel drv
-resolveObject _ _ =
-  failure $ internalResolvingError "expected object as resolver"
-
-toEventResolver :: Monad m => ReaderT event (Resolver QUERY event m) ValidValue -> Context -> event -> m GQLResponse
-toEventResolver (ReaderT subRes) sel event = do
-  value <- runResultT $ runReaderT (runResolverState $ runResolverQ (subRes event)) sel
-  pure $ renderResponse value
+    resolver currentSelection =
+      local (\ctx -> ctx {currentSelection, currentTypeName = __typename}) $
+        ObjectEntry (keyOf currentSelection) <$> lookupRes currentSelection drv
+resolveObject _ _ = packResolver $ failure ("expected object as resolver" :: InternalError)
 
 runDataResolver :: (Monad m, LiftOperation o) => ResModel o e m -> Resolver o e m ValidValue
-runDataResolver = withResolver getState . __encode
+runDataResolver res = asks currentSelection >>= __encode res
   where
     __encode obj sel@Selection {selectionContent} = encodeNode obj selectionContent
       where
         -- LIST
         encodeNode (ResList x) _ = List <$> traverse runDataResolver x
         -- Object -----------------
-        encodeNode objDrv@ResObject {} _ = withObject (`resolveObject` objDrv) sel
+        encodeNode objDrv@(ResObject ObjectResModel {__typename}) _ = withObject __typename (`resolveObject` objDrv) sel
         -- ENUM
         encodeNode (ResEnum _ enum) SelectionField = pure $ gqlString $ readTypeName enum
         encodeNode (ResEnum typename enum) unionSel@UnionSelection {} =
@@ -450,23 +354,39 @@
 
 runResolver ::
   Monad m =>
+  Maybe (Selection VALID -> ResolverState (Channel event)) ->
   Resolver o event m ValidValue ->
-  Context ->
+  ResolverContext ->
   ResponseStream event m ValidValue
-runResolver (ResolverQ resT) sel = cleanEvents $ runReaderT (runResolverState resT) sel
-runResolver (ResolverM resT) sel = mapEvent Publish $ runReaderT (runResolverState resT) sel
-runResolver (ResolverS resT) sel = ResultT $ do
-  readResValue <- runResultT $ runReaderT (runResolverState resT) sel
-  pure $ case readResValue of
+runResolver _ (ResolverQ resT) sel = cleanEvents $ runResolverStateT resT sel
+runResolver _ (ResolverM resT) sel = mapEvent Publish $ runResolverStateT resT sel
+runResolver toChannel (ResolverS resT) ctx = ResultT $ do
+  readResValue <- runResolverStateM resT ctx
+  pure $ case readResValue >>= subscriptionEvents ctx toChannel . toEventResolver ctx of
     Failure x -> Failure x
-    Success {warnings, result, events = channels} -> do
-      let eventRes = toEventResolver result sel
+    Success {warnings, result} ->
       Success
-        { events = [Subscribe $ Event channels eventRes],
+        { events = [result],
           warnings,
           result = gqlNull
         }
 
+toEventResolver :: Monad m => ResolverContext -> SubEventRes event m ValidValue -> (event -> m GQLResponse)
+toEventResolver sel (ReaderT subRes) event = renderResponse <$> runResolverStateM (subRes event) sel
+
+subscriptionEvents ::
+  ResolverContext ->
+  Maybe (Selection VALID -> ResolverState (Channel e)) ->
+  (e -> m GQLResponse) ->
+  Eventless (ResponseEvent e m)
+subscriptionEvents ctx@ResolverContext {currentSelection} (Just channelGenerator) res =
+  runResolverState handle ctx
+  where
+    handle = do
+      channel <- channelGenerator currentSelection
+      pure $ Subscribe (Event [channel] res)
+subscriptionEvents ctx Nothing _ = failure [resolverFailureMessage ctx "channel Resolver is not defined"]
+
 -- Resolver Models -------------------------------------------------------------------
 type FieldResModel o e m =
   (FieldName, Resolver o e m (ResModel o e m))
@@ -478,8 +398,8 @@
   }
   deriving (Show)
 
-instance Merge (ObjectResModel o e m) where
-  merge _ (ObjectResModel tyname x) (ObjectResModel _ y) =
+instance Applicative f => SemigroupM f (ObjectResModel o e m) where
+  mergeM _ (ObjectResModel tyname x) (ObjectResModel _ y) =
     pure $ ObjectResModel tyname (x <> y)
 
 data ResModel (o :: OperationType) e (m :: * -> *)
@@ -491,86 +411,46 @@
   | ResUnion TypeName (Resolver o e m (ResModel o e m))
   deriving (Show)
 
-instance Merge (ResModel o e m) where
-  merge p (ResObject x) (ResObject y) =
-    ResObject <$> merge p x y
-  merge _ _ _ =
-    failure $ internalResolvingError "can't merge: incompatible resolvers"
+instance (Monad f, Failure InternalError f) => SemigroupM f (ResModel o e m) where
+  mergeM p (ResObject x) (ResObject y) =
+    ResObject <$> mergeM p x y
+  mergeM _ _ _ = failure ("can't merge: incompatible resolvers" :: InternalError)
 
 data RootResModel e m = RootResModel
-  { query :: Eventless (ResModel QUERY e m),
-    mutation :: Eventless (ResModel MUTATION e m),
-    subscription :: Eventless (ResModel SUBSCRIPTION e m)
+  { query :: ResolverState (ResModel QUERY e m),
+    mutation :: ResolverState (ResModel MUTATION e m),
+    subscription :: ResolverState (ResModel SUBSCRIPTION e m),
+    channelMap :: Maybe (Selection VALID -> ResolverState (Channel e))
   }
 
 runRootDataResolver ::
   (Monad m, LiftOperation o) =>
-  Eventless (ResModel o e m) ->
-  Context ->
+  Maybe (Selection VALID -> ResolverState (Channel e)) ->
+  ResolverState (ResModel o e m) ->
+  ResolverContext ->
   ResponseStream e m (Value VALID)
 runRootDataResolver
+  channels
   res
-  ctx@Context {operation = Operation {operationSelection}} =
+  ctx@ResolverContext {operation = Operation {operationSelection}} =
     do
-      root <- statelessToResultT res
-      runResolver (resolveObject operationSelection root) ctx
+      root <- runResolverStateT (toResolverStateT res) ctx
+      runResolver channels (resolveObject operationSelection root) ctx
 
-runRootResModel :: Monad m => RootResModel e m -> Context -> ResponseStream e m (Value VALID)
+runRootResModel :: Monad m => RootResModel e m -> ResolverContext -> ResponseStream e m (Value VALID)
 runRootResModel
   RootResModel
     { query,
       mutation,
-      subscription
+      subscription,
+      channelMap
     }
-  ctx@Context {operation = Operation {operationType}} =
+  ctx@ResolverContext {operation = Operation {operationType}} =
     selectByOperation operationType
     where
       selectByOperation Query =
-        runRootDataResolver query ctx
+        runRootDataResolver channelMap query ctx
       selectByOperation Mutation =
-        runRootDataResolver mutation ctx
+        runRootDataResolver channelMap mutation ctx
       selectByOperation Subscription =
-        runRootDataResolver subscription ctx
-
--- map Resolving strategies
-class
-  MapStrategy
-    (from :: OperationType)
-    (to :: OperationType)
-  where
-  mapStrategy ::
-    Monad m =>
-    Resolver from e m (ResModel from e m) ->
-    Resolver to e m (ResModel to e m)
-
-instance MapStrategy o o where
-  mapStrategy = id
-
-instance MapStrategy QUERY SUBSCRIPTION where
-  mapStrategy = ResolverS . pure . lift . fmap mapDeriving
-
-mapDeriving ::
-  ( MapStrategy o o',
-    Monad m
-  ) =>
-  ResModel o e m ->
-  ResModel o' e m
-mapDeriving ResNull = ResNull
-mapDeriving (ResScalar x) = ResScalar x
-mapDeriving (ResEnum typeName enum) = ResEnum typeName enum
-mapDeriving (ResList x) = ResList $ map mapDeriving x
-mapDeriving (ResObject x) = ResObject (mapObjectDeriving x)
-mapDeriving (ResUnion name x) = ResUnion name (mapStrategy x)
-
-mapObjectDeriving ::
-  ( MapStrategy o o',
-    Monad m
-  ) =>
-  ObjectResModel o e m ->
-  ObjectResModel o' e m
-mapObjectDeriving (ObjectResModel tyname x) =
-  ObjectResModel tyname $
-    map (mapEntry mapStrategy) x
-
-mapEntry :: (a -> b) -> (k, a) -> (k, b)
-mapEntry f (name, value) = (name, f value)
+        runRootDataResolver channelMap subscription ctx
diff --git a/src/Data/Morpheus/Types/Internal/Resolving/ResolverState.hs b/src/Data/Morpheus/Types/Internal/Resolving/ResolverState.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Morpheus/Types/Internal/Resolving/ResolverState.hs
@@ -0,0 +1,202 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE NamedFieldPuns #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE PolyKinds #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+module Data.Morpheus.Types.Internal.Resolving.ResolverState
+  ( ResolverContext (..),
+    ResolverStateT (..),
+    resolverFailureMessage,
+    clearStateResolverEvents,
+    ResolverState,
+    toResolverStateT,
+    runResolverStateT,
+    runResolverStateM,
+    runResolverState,
+  )
+where
+
+import Control.Applicative (Applicative (..))
+import Control.Monad (Monad (..))
+import Control.Monad.Reader (MonadReader (..), asks)
+import Control.Monad.Trans.Class (MonadTrans (..))
+import Control.Monad.Trans.Reader
+  ( ReaderT (..),
+    mapReaderT,
+  )
+import Data.Functor (Functor (..))
+import Data.Functor.Identity (Identity (..))
+import Data.Morpheus.Rendering.RenderGQL
+  ( RenderGQL (..),
+  )
+import Data.Morpheus.Types.Internal.AST
+  ( GQLError (..),
+    GQLErrors,
+    InternalError,
+    Message,
+    Operation,
+    Schema,
+    Selection (..),
+    TypeName,
+    VALID,
+    msg,
+  )
+import Data.Morpheus.Types.Internal.Config (Config (..))
+import Data.Morpheus.Types.Internal.Resolving.Core
+  ( Eventless,
+    Failure (..),
+    PushEvents (..),
+    Result,
+    ResultT (..),
+    cleanEvents,
+  )
+import Data.Semigroup
+  ( Semigroup (..),
+  )
+import Prelude
+  ( ($),
+    (.),
+    Bool (..),
+    Int,
+    Show (..),
+    id,
+  )
+
+data ResolverContext = ResolverContext
+  { currentSelection :: Selection VALID,
+    schema :: Schema VALID,
+    operation :: Operation VALID,
+    currentTypeName :: TypeName,
+    config :: Config
+  }
+  deriving (Show)
+
+type ResolverState = ResolverStateT () Identity
+
+runResolverStateT :: ResolverStateT e m a -> ResolverContext -> ResultT e m a
+runResolverStateT = runReaderT . _runResolverStateT
+
+runResolverStateM :: ResolverStateT e m a -> ResolverContext -> m (Result e a)
+runResolverStateM res = runResultT . runResolverStateT res
+
+runResolverState :: ResolverState a -> ResolverContext -> Eventless a
+runResolverState res = runIdentity . runResolverStateM res
+
+-- Resolver Internal State
+newtype ResolverStateT event m a = ResolverStateT
+  { _runResolverStateT :: ReaderT ResolverContext (ResultT event m) a
+  }
+  deriving
+    ( Functor,
+      Applicative,
+      Monad,
+      MonadReader ResolverContext
+    )
+
+instance MonadTrans (ResolverStateT e) where
+  lift = ResolverStateT . lift . lift
+
+instance (Monad m) => Failure Message (ResolverStateT e m) where
+  failure message = do
+    cxt <- asks id
+    failure [resolverFailureMessage cxt message]
+
+instance (Monad m) => Failure InternalError (ResolverStateT e m) where
+  failure message = do
+    ctx <- asks id
+    failure [renderInternalResolverError ctx message]
+
+instance (Monad m) => Failure GQLErrors (ResolverStateT e m) where
+  failure = ResolverStateT . lift . failure
+
+instance (Monad m) => PushEvents e (ResolverStateT e m) where
+  pushEvents = ResolverStateT . lift . pushEvents
+
+mapResolverState ::
+  ( ResultT e m a ->
+    ResultT e' m' a'
+  ) ->
+  ResolverStateT e m a ->
+  ResolverStateT e' m' a'
+mapResolverState f (ResolverStateT x) = ResolverStateT (mapReaderT f x)
+
+toResolverStateT ::
+  Applicative m =>
+  ResolverState a ->
+  ResolverStateT e m a
+toResolverStateT = mapResolverState injectResult
+
+injectResult ::
+  (Applicative m) =>
+  ResultT () Identity a ->
+  ResultT e m a
+injectResult (ResultT (Identity x)) =
+  cleanEvents $ ResultT (pure x)
+
+-- clear evets and starts new resolver with diferenct type of events but with same value
+-- use properly. only if you know what you are doing
+clearStateResolverEvents :: (Functor m) => ResolverStateT e m a -> ResolverStateT e' m a
+clearStateResolverEvents = mapResolverState cleanEvents
+
+resolverFailureMessage :: ResolverContext -> Message -> GQLError
+resolverFailureMessage
+  ctx@ResolverContext
+    { currentSelection =
+        Selection {selectionName, selectionPosition}
+    }
+  message =
+    GQLError
+      { message =
+          "Failure on Resolving Field "
+            <> msg selectionName
+            <> ": "
+            <> message
+            <> withInternalContext ctx,
+        locations = [selectionPosition]
+      }
+
+renderInternalResolverError :: ResolverContext -> InternalError -> GQLError
+renderInternalResolverError ctx@ResolverContext {currentSelection} message =
+  GQLError
+    { message = msg message <> ". " <> renderContext ctx,
+      locations = [selectionPosition currentSelection]
+    }
+
+withInternalContext :: ResolverContext -> Message
+withInternalContext ResolverContext {config = Config {debug = False}} = ""
+withInternalContext resCTX = renderContext resCTX
+
+renderContext :: ResolverContext -> Message
+renderContext
+  ResolverContext
+    { currentSelection,
+      schema,
+      operation,
+      currentTypeName
+    } =
+    renderSection "Current Type" currentTypeName
+      <> renderSection "Current Selection" currentSelection
+      <> renderSection "OperationDefinition" operation
+      <> renderSection "SchemaDefinition" schema
+
+renderSection :: RenderGQL a => Message -> a -> Message
+renderSection label content =
+  "\n\n" <> label <> ":\n" <> line
+    <> "\n\n"
+    <> msg (render content)
+    <> "\n\n"
+  where
+    line = stimes (50 :: Int) "-"
diff --git a/src/Data/Morpheus/Types/Internal/Validation.hs b/src/Data/Morpheus/Types/Internal/Validation.hs
--- a/src/Data/Morpheus/Types/Internal/Validation.hs
+++ b/src/Data/Morpheus/Types/Internal/Validation.hs
@@ -1,14 +1,13 @@
 {-# LANGUAGE DataKinds #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE GADTs #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE RankNTypes #-}
 {-# LANGUAGE RecordWildCards #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Types.Internal.Validation
   ( Validator,
@@ -18,7 +17,8 @@
     InputSource (..),
     OperationContext (..),
     runValidator,
-    askFieldType,
+    DirectiveValidator,
+    askType,
     askTypeMember,
     selectRequired,
     selectKnown,
@@ -28,11 +28,10 @@
     withScopeType,
     withPosition,
     asks,
+    asksScope,
     selectWithDefaultValue,
-    askInputFieldType,
-    askInputMember,
     startInput,
-    withInputScope,
+    inField,
     inputMessagePrefix,
     checkUnused,
     Prop (..),
@@ -51,14 +50,25 @@
     askFragments,
     MonadContext,
     CurrentSelection (..),
+    getOperationType,
+    selectType,
+    FragmentValidator,
+    askInterfaceTypes,
   )
 where
 
+-- MORPHEUS
+
+import Control.Applicative (pure)
+import Control.Monad ((>>=))
 import Control.Monad.Trans.Reader
   ( ask,
   )
--- MORPHEUS
-
+import Data.Either (Either)
+import Data.Foldable (null)
+import Data.Functor ((<$>), fmap)
+import Data.List (filter)
+import Data.Maybe (Maybe (..), fromMaybe, maybe)
 import Data.Morpheus.Internal.Utils
   ( Failure (..),
     KeyOf (..),
@@ -73,41 +83,45 @@
     FieldContent (..),
     FieldDefinition (..),
     FieldName,
-    FieldsDefinition,
-    GQLErrors,
     IN,
     Message,
-    OUT,
     Object,
     ObjectEntry (..),
-    RESOLVED,
+    Position (..),
     Ref (..),
-    Schema,
     TRUE,
     TypeContent (..),
     TypeDefinition (..),
-    TypeName (..),
-    TypeRef (..),
+    TypeName,
     UnionMember (..),
+    ValidationError,
     Value (..),
     __inputname,
     entryValue,
     fromAny,
-    isFieldNullable,
+    isNullable,
     msg,
+    msgValidation,
     toFieldName,
   )
 import Data.Morpheus.Types.Internal.Validation.Error
-  ( InternalError (..),
-    KindViolation (..),
+  ( KindViolation (..),
     MissingRequired (..),
     Unknown (..),
     Unused (..),
   )
+import Data.Morpheus.Types.Internal.Validation.Internal
+  ( askInterfaceTypes,
+    askType,
+    askTypeMember,
+    getOperationType,
+  )
 import Data.Morpheus.Types.Internal.Validation.Validator
   ( BaseValidator,
     Constraint (..),
     CurrentSelection (..),
+    DirectiveValidator,
+    FragmentValidator,
     GetWith (..),
     InputContext,
     InputSource (..),
@@ -122,16 +136,18 @@
     SetWith (..),
     Target (..),
     Validator (..),
+    ValidatorContext (..),
     askFragments,
     askSchema,
     askVariables,
     asks,
+    asksScope,
+    inField,
     inputMessagePrefix,
     inputValueSource,
     runValidator,
     startInput,
     withDirective,
-    withInputScope,
     withPosition,
     withScope,
     withScopeType,
@@ -139,62 +155,75 @@
 import Data.Semigroup
   ( (<>),
   )
+import Prelude
+  ( ($),
+    (.),
+    not,
+    otherwise,
+  )
 
-getUnused :: (KeyOf b, KEY a ~ KEY b, Selectable ca a) => ca -> [b] -> [b]
+getUnused :: (KeyOf k b, Selectable k a c) => c -> [b] -> [b]
 getUnused uses = filter (not . (`member` uses) . keyOf)
 
-failOnUnused :: Unused ctx b => [b] -> Validator ctx ()
+failOnUnused :: Unused ctx b => [b] -> Validator s ctx ()
 failOnUnused x
-  | null x = return ()
+  | null x = pure ()
   | otherwise = do
-    ctx <- Validator ask
-    failure $ map (unused ctx) x
+    ctx <- validatorCTX <$> Validator ask
+    failure $ fmap (unused ctx) x
 
-checkUnused :: (KeyOf b, KEY a ~ KEY b, Selectable ca a, Unused ctx b) => ca -> [b] -> Validator ctx ()
+checkUnused ::
+  ( KeyOf k b,
+    Selectable k a ca,
+    Unused ctx b
+  ) =>
+  ca ->
+  [b] ->
+  Validator s ctx ()
 checkUnused uses = failOnUnused . getUnused uses
 
 constraint ::
-  forall (a :: Target) inp ctx.
   KindViolation a inp =>
   Constraint (a :: Target) ->
   inp ->
-  TypeDefinition ANY ->
-  Validator ctx (Resolution a)
-constraint OBJECT _ TypeDefinition {typeContent = DataObject {objectFields}, typeName} =
-  pure (typeName, objectFields)
+  TypeDefinition ANY s ->
+  Validator s ctx (Resolution s a)
+constraint IMPLEMENTABLE _ TypeDefinition {typeContent = DataObject {objectFields, ..}, ..} =
+  pure TypeDefinition {typeContent = DataObject {objectFields, ..}, ..}
+constraint IMPLEMENTABLE _ TypeDefinition {typeContent = DataInterface fields, ..} =
+  pure TypeDefinition {typeContent = DataInterface fields, ..}
 constraint INPUT ctx x = maybe (failure [kindViolation INPUT ctx]) pure (fromAny x)
 constraint target ctx _ = failure [kindViolation target ctx]
 
 selectRequired ::
-  ( Selectable c value,
-    MissingRequired c ctx,
-    KEY Ref ~ KEY value
+  ( Selectable FieldName value c,
+    MissingRequired c ctx
   ) =>
   Ref ->
   c ->
-  Validator ctx value
+  Validator s ctx value
 selectRequired selector container =
   do
-    ctx <- Validator ask
+    ValidatorContext {scope, validatorCTX} <- Validator ask
     selectBy
-      [missingRequired ctx selector container]
+      [missingRequired scope validatorCTX selector container]
       (keyOf selector)
       container
 
 selectWithDefaultValue ::
-  forall ctx values value.
-  ( Selectable values value,
+  forall ctx values value s validValue.
+  ( Selectable FieldName value values,
     MissingRequired values ctx,
-    KEY value ~ FieldName,
-    GetWith ctx Scope,
-    MonadContext Validator ctx
+    MonadContext (Validator s) s ctx
   ) =>
-  (Value RESOLVED -> value) ->
-  FieldDefinition IN ->
+  (Value s -> Validator s ctx validValue) ->
+  (value -> Validator s ctx validValue) ->
+  FieldDefinition IN s ->
   values ->
-  Validator ctx value
+  Validator s ctx validValue
 selectWithDefaultValue
   f
+  validateF
   field@FieldDefinition
     { fieldName,
       fieldContent
@@ -202,175 +231,53 @@
   values =
     selectOr
       (handeNull fieldContent)
-      pure
+      validateF
       fieldName
       values
     where
       ------------------
-      handeNull :: Maybe (FieldContent TRUE IN) -> Validator ctx value
-      handeNull (Just (DefaultInputValue value)) = pure $ f value
+      handeNull ::
+        Maybe (FieldContent TRUE IN s) ->
+        Validator s ctx validValue
+      handeNull (Just (DefaultInputValue value)) = f value
       handeNull Nothing
-        | isFieldNullable field = pure $ f Null
+        | isNullable field = f Null
         | otherwise = failSelection
       -----------------
       failSelection = do
-        ctx <- Validator ask
-        position <- asks position
-        failure [missingRequired ctx (Ref fieldName position) values]
+        ValidatorContext {scope, validatorCTX} <- Validator ask
+        position <- asksScope position
+        failure [missingRequired scope validatorCTX (Ref fieldName (fromMaybe (Position 0 0) position)) values]
 
+selectType ::
+  TypeName ->
+  Validator s ctx (TypeDefinition ANY s)
+selectType name =
+  askSchema >>= selectBy err name
+  where
+    err = "Unknown Type " <> msgValidation name <> "." :: ValidationError
+
 selectKnown ::
-  ( Selectable c a,
-    Unknown c ctx,
-    KeyOf sel,
-    sel ~ UnknownSelector c,
-    KEY sel ~ KEY a
+  ( Selectable k a c,
+    Unknown c sel ctx,
+    KeyOf k sel
   ) =>
   sel ->
   c ->
-  Validator ctx a
+  Validator s ctx a
 selectKnown selector lib =
   do
-    ctx <- Validator ask
+    ValidatorContext {scope, validatorCTX} <- Validator ask
     selectBy
-      (unknown ctx lib selector)
+      (unknown scope validatorCTX lib selector)
       (keyOf selector)
       lib
 
-askFieldType ::
-  FieldDefinition OUT ->
-  SelectionValidator (TypeDefinition OUT)
-askFieldType field@FieldDefinition {fieldType = TypeRef {typeConName}} =
-  do
-    schema <- askSchema
-    anyType <-
-      selectBy
-        [internalError field]
-        typeConName
-        schema
-    case fromAny anyType of
-      Just x -> pure x
-      Nothing ->
-        failure $
-          "Type \"" <> msg (typeName anyType)
-            <> "\" referenced by OBJECT \""
-            <> "\" must be an OUTPUT_TYPE."
-
-askTypeMember ::
-  UnionMember OUT ->
-  SelectionValidator (TypeName, FieldsDefinition OUT)
-askTypeMember UnionMember {memberName} =
-  askSchema
-    >>= selectOr notFound pure memberName
-    >>= constraintOBJECT
-  where
-    notFound = do
-      scopeType <- asks typename
-      failure $
-        "Type \""
-          <> msg memberName
-          <> "\" referenced by union \""
-          <> msg scopeType
-          <> "\" can't found in Schema."
-    --------------------------------------
-    constraintOBJECT :: TypeDefinition ANY -> SelectionValidator (TypeName, FieldsDefinition OUT)
-    constraintOBJECT TypeDefinition {typeName, typeContent} = con typeContent
-      where
-        con DataObject {objectFields} = pure (typeName, objectFields)
-        con _ = do
-          scopeType <- asks typename
-          failure $
-            "Type \"" <> msg typeName
-              <> "\" referenced by union \""
-              <> msg scopeType
-              <> "\" must be an OBJECT."
-
-askInputFieldType ::
-  ( Failure GQLErrors (m c),
-    Failure Message (m c),
-    Monad (m c),
-    GetWith c Schema,
-    MonadContext m c
-  ) =>
-  FieldDefinition IN ->
-  m c (TypeDefinition IN)
-askInputFieldType field@FieldDefinition {fieldName, fieldType = TypeRef {typeConName}} =
-  askSchema
-    >>= selectBy
-      [internalError field]
-      typeConName
-    >>= constraintINPUT
-  where
-    constraintINPUT ::
-      ( Failure Message m,
-        Monad m
-      ) =>
-      TypeDefinition ANY ->
-      m (TypeDefinition IN)
-    constraintINPUT x = case (fromAny x :: Maybe (TypeDefinition IN)) of
-      Just inputType -> pure inputType
-      Nothing ->
-        failure $
-          "Type \""
-            <> msg (typeName x)
-            <> "\" referenced by field \""
-            <> msg fieldName
-            <> "\" must be an input type."
-
-askInputMember ::
-  ( GetWith c Schema,
-    GetWith c Scope,
-    Failure Message (m c),
-    Monad (m c),
-    MonadContext m c
-  ) =>
-  TypeName ->
-  m c (TypeDefinition IN)
-askInputMember name =
-  askSchema
-    >>= selectOr notFound pure name
-    >>= constraintINPUT_OBJECT
-  where
-    typeInfo tName =
-      "Type \"" <> msg tName <> "\" referenced by inputUnion "
-    notFound = do
-      scopeType <- asks typename
-      failure $
-        typeInfo name
-          <> msg scopeType
-          <> "\" can't found in Schema."
-    --------------------------------------
-    constraintINPUT_OBJECT ::
-      ( Monad (m c),
-        GetWith c Scope,
-        Failure Message (m c),
-        MonadContext m c
-      ) =>
-      TypeDefinition ANY ->
-      m c (TypeDefinition IN)
-    constraintINPUT_OBJECT TypeDefinition {typeContent, ..} = con (fromAny typeContent)
-      where
-        con ::
-          ( Monad (m c),
-            GetWith c Scope,
-            Failure Message (m c),
-            MonadContext m c
-          ) =>
-          Maybe (TypeContent a IN) ->
-          m c (TypeDefinition IN)
-        con (Just content@DataInputObject {}) = pure TypeDefinition {typeContent = content, ..}
-        con _ = do
-          scopeType <- asks typename
-          failure $
-            typeInfo typeName
-              <> "\""
-              <> msg scopeType
-              <> "\" must be an INPUT_OBJECT."
-
 constraintInputUnion ::
-  forall stage.
-  [UnionMember IN] ->
+  forall stage schemaStage.
+  [UnionMember IN schemaStage] ->
   Object stage ->
-  Either Message (TypeName, Maybe (Value stage))
+  Either Message (UnionMember IN schemaStage, Maybe (Value stage))
 constraintInputUnion tags hm = do
   (enum :: Value stage) <-
     entryValue
@@ -381,24 +288,26 @@
         )
         __inputname
         hm
-  tyName <- isPosibeInputUnion tags enum
+  unionMember <- isPosibeInputUnion tags enum
   case size hm of
-    1 -> pure (tyName, Nothing)
+    1 -> pure (unionMember, Nothing)
     2 -> do
       value <-
         entryValue
           <$> selectBy
             ( "value for Union \""
-                <> msg tyName
+                <> msg unionMember
                 <> "\" was not Provided."
             )
-            (toFieldName tyName)
+            (toFieldName $ memberName unionMember)
             hm
-      pure (tyName, Just value)
+      pure (unionMember, Just value)
     _ -> failure ("input union can have only one variant." :: Message)
 
-isPosibeInputUnion :: [UnionMember IN] -> Value stage -> Either Message TypeName
-isPosibeInputUnion tags (Enum name)
-  | name `elem` map memberName tags = pure name
-  | otherwise = failure $ msg name <> " is not posible union type"
+isPosibeInputUnion :: [UnionMember IN s] -> Value stage -> Either Message (UnionMember IN s)
+isPosibeInputUnion tags (Enum name) =
+  selectBy
+    (msg name <> " is not posible union type")
+    name
+    tags
 isPosibeInputUnion _ _ = failure $ "\"" <> msg __inputname <> "\" must be Enum"
diff --git a/src/Data/Morpheus/Types/Internal/Validation/Error.hs b/src/Data/Morpheus/Types/Internal/Validation/Error.hs
--- a/src/Data/Morpheus/Types/Internal/Validation/Error.hs
+++ b/src/Data/Morpheus/Types/Internal/Validation/Error.hs
@@ -1,27 +1,28 @@
 {-# LANGUAGE DataKinds #-}
+{-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Types.Internal.Validation.Error
   ( MissingRequired (..),
     KindViolation (..),
     Unknown (..),
-    InternalError (..),
     Target (..),
     Unused (..),
   )
 where
 
 -- MORPHEUS
-
+import Data.Maybe (maybeToList)
 import Data.Morpheus.Error.Selection (unknownSelectionField)
-import Data.Morpheus.Error.Utils (errorMessage)
 import Data.Morpheus.Types.Internal.AST
   ( Argument (..),
     Arguments,
+    CONST,
     Directive (..),
     DirectiveDefinition (..),
     DirectiveDefinitions,
@@ -29,25 +30,21 @@
     FieldsDefinition,
     Fragment (..),
     Fragments,
-    GQLError (..),
-    GQLErrors,
     IN,
     OUT,
     Object,
     ObjectEntry (..),
-    RAW,
-    RESOLVED,
     Ref (..),
     Schema,
     TypeNameRef (..),
     TypeRef (..),
+    ValidationError (..),
     Variable (..),
     VariableDefinitions,
     getOperationName,
     msg,
-  )
-import Data.Morpheus.Types.Internal.Validation.SchemaValidator
-  ( TypeSystemContext,
+    msgValidation,
+    withPosition,
   )
 import Data.Morpheus.Types.Internal.Validation.Validator
   ( CurrentSelection (..),
@@ -59,206 +56,155 @@
     renderInputPrefix,
   )
 import Data.Semigroup ((<>))
-
-class InternalError a where
-  internalError :: a -> GQLError
-
-instance InternalError (FieldDefinition cat) where
-  internalError
-    FieldDefinition
-      { fieldName,
-        fieldType = TypeRef {typeConName}
-      } =
-      GQLError
-        { message =
-            "INTERNAL: Type " <> msg typeConName
-              <> " referenced by field "
-              <> msg fieldName
-              <> " can't found in Schema ",
-          locations = []
-        }
+import Prelude (($))
 
 class Unused ctx c where
-  unused :: ctx -> c -> GQLError
+  unused :: ctx -> c -> ValidationError
 
 -- query M ( $v : String ) { a } -> "Variable \"$bla\" is never used in operation \"MyMutation\".",
-instance Unused (OperationContext v) (Variable s) where
+instance Unused (OperationContext s1 s2) (Variable s) where
   unused
     OperationContext {selection = CurrentSelection {operationName}}
     Variable {variableName, variablePosition} =
-      GQLError
-        { message =
+      ValidationError
+        { validationMessage =
             "Variable " <> msg ("$" <> variableName)
               <> " is never used in operation "
               <> msg (getOperationName operationName)
               <> ".",
-          locations = [variablePosition]
+          validationLocations = [variablePosition]
         }
 
-instance Unused (OperationContext v) Fragment where
+instance Unused (OperationContext s1 s2) (Fragment s) where
   unused
     _
     Fragment {fragmentName, fragmentPosition} =
-      GQLError
-        { message =
+      ValidationError
+        { validationMessage =
             "Fragment " <> msg fragmentName
               <> " is never used.",
-          locations = [fragmentPosition]
+          validationLocations = [fragmentPosition]
         }
 
 class MissingRequired c ctx where
-  missingRequired :: ctx -> Ref -> c -> GQLError
+  missingRequired :: Scope -> ctx -> Ref -> c -> ValidationError
 
-instance MissingRequired (Arguments s) (OperationContext v) where
+instance MissingRequired (Arguments s) ctx where
   missingRequired
-    OperationContext
-      { scope = Scope {position, kind},
-        selection = CurrentSelection {selectionName}
-      }
+    Scope {position, kind, fieldname}
+    _
     Ref {refName}
     _ =
-      GQLError
-        { message =
+      ValidationError
+        { validationMessage =
             inScope kind
               <> " argument "
               <> msg refName
               <> " is required but not provided.",
-          locations = [position]
+          validationLocations = maybeToList position
         }
       where
-        inScope DIRECTIVE = "Directive " <> msg ("@" <> selectionName)
-        inScope _ = "Field " <> msg selectionName
-
-instance MissingRequired (Object s) (InputContext (OperationContext v)) where
-  missingRequired
-    input@InputContext
-      { sourceContext =
-          OperationContext
-            { scope = Scope {position}
-            }
-      }
-    Ref {refName}
-    _ =
-      GQLError
-        { message =
-            renderInputPrefix input
-              <> "Undefined Field "
-              <> msg refName
-              <> ".",
-          locations = [position]
-        }
+        inScope DIRECTIVE = "Directive " <> msg ("@" <> fieldname)
+        inScope _ = "Field " <> msg fieldname
 
-instance MissingRequired (Object s) (InputContext (TypeSystemContext ctx)) where
+instance MissingRequired (Object s) (InputContext ctx) where
   missingRequired
-    input
+    Scope {position}
+    ctx
     Ref {refName}
     _ =
-      GQLError
-        { message =
-            renderInputPrefix input
-              <> "Undefined Field "
-              <> msg refName
-              <> ".",
-          locations = []
-        }
+      withPosition
+        position
+        ( renderInputPrefix
+            ctx
+            <> "Undefined Field "
+            <> msgValidation refName
+            <> "."
+        )
 
-instance MissingRequired (VariableDefinitions s) (OperationContext v) where
+instance MissingRequired (VariableDefinitions s) (OperationContext s1 s2) where
   missingRequired
+    _
     OperationContext
       { selection = CurrentSelection {operationName}
       }
     Ref {refName, refPosition}
     _ =
-      GQLError
-        { message =
+      ValidationError
+        { validationMessage =
             "Variable "
               <> msg refName
               <> " is not defined by operation "
               <> msg (getOperationName operationName)
               <> ".",
-          locations = [refPosition]
+          validationLocations = [refPosition]
         }
 
-class Unknown c ctx where
-  type UnknownSelector c
-  unknown :: ctx -> c -> UnknownSelector c -> GQLErrors
+class Unknown c ref ctx where
+  -- type UnknownSelector c
+  unknown :: Scope -> ctx -> c -> ref -> ValidationError
 
 -- {...H} -> "Unknown fragment \"H\"."
-instance Unknown Fragments ctx where
-  type UnknownSelector Fragments = Ref
-  unknown _ _ (Ref name pos) =
-    errorMessage
-      pos
-      ("Unknown Fragment " <> msg name <> ".")
-
-instance Unknown Schema ctx where
-  type UnknownSelector Schema = TypeNameRef
-  unknown _ _ TypeNameRef {typeNameRef, typeNamePosition} =
-    errorMessage typeNamePosition ("Unknown type " <> msg typeNameRef <> ".")
+instance Unknown (Fragments s) Ref ctx where
+  unknown _ _ _ (Ref name pos) =
+    ValidationError
+      { validationMessage = "Unknown Fragment " <> msg name <> ".",
+        validationLocations = [pos]
+      }
 
-instance Unknown (FieldDefinition OUT) ctx where
-  type UnknownSelector (FieldDefinition OUT) = Argument RESOLVED
-  unknown _ FieldDefinition {fieldName} Argument {argumentName, argumentPosition} =
-    errorMessage
-      argumentPosition
-      ("Unknown Argument " <> msg argumentName <> " on Field " <> msg fieldName <> ".")
+instance Unknown (Schema s) TypeNameRef ctx where
+  unknown _ _ _ TypeNameRef {typeNameRef, typeNamePosition} =
+    ValidationError
+      { validationMessage = "Unknown type " <> msg typeNameRef <> ".",
+        validationLocations = [typeNamePosition]
+      }
 
-instance Unknown (FieldsDefinition IN) (InputContext (OperationContext v)) where
-  type UnknownSelector (FieldsDefinition IN) = ObjectEntry RESOLVED
-  unknown
-    input@InputContext {sourceContext = OperationContext {scope = Scope {position}}}
-    _
-    ObjectEntry {entryName} =
-      [ GQLError
-          { message = renderInputPrefix input <> "Unknown Field " <> msg entryName <> ".",
-            locations = [position]
-          }
-      ]
+instance Unknown (FieldDefinition OUT s) (Argument CONST) ctx where
+  unknown _ _ FieldDefinition {fieldName} Argument {argumentName, argumentPosition} =
+    ValidationError
+      { validationMessage = "Unknown Argument " <> msg argumentName <> " on Field " <> msg fieldName <> ".",
+        validationLocations = [argumentPosition]
+      }
 
-instance Unknown (FieldsDefinition IN) (InputContext (TypeSystemContext ctx)) where
-  type UnknownSelector (FieldsDefinition IN) = ObjectEntry RESOLVED
+instance Unknown (FieldsDefinition IN s) (ObjectEntry valueS) (InputContext ctx) where
   unknown
-    input
+    Scope {position}
+    ctx
     _
     ObjectEntry {entryName} =
-      [ GQLError
-          { message = renderInputPrefix input <> "Unknown Field " <> msg entryName <> ".",
-            locations = []
-          }
-      ]
+      withPosition position $
+        renderInputPrefix ctx <> "Unknown Field " <> msgValidation entryName <> "."
 
-instance Unknown DirectiveDefinition ctx where
-  type UnknownSelector DirectiveDefinition = Argument RESOLVED
-  unknown _ DirectiveDefinition {directiveDefinitionName} Argument {argumentName, argumentPosition} =
-    errorMessage
-      argumentPosition
-      ("Unknown Argument " <> msg argumentName <> " on Directive " <> msg directiveDefinitionName <> ".")
+instance Unknown (DirectiveDefinition s) (Argument s') ctx where
+  unknown _ _ DirectiveDefinition {directiveDefinitionName} Argument {argumentName, argumentPosition} =
+    ValidationError
+      { validationMessage = "Unknown Argument " <> msg argumentName <> " on Directive " <> msg directiveDefinitionName <> ".",
+        validationLocations = [argumentPosition]
+      }
 
-instance Unknown DirectiveDefinitions ctx where
-  type UnknownSelector DirectiveDefinitions = Directive RAW
-  unknown _ _ Directive {directiveName, directivePosition} =
-    errorMessage
-      directivePosition
-      ("Unknown Directive " <> msg directiveName <> ".")
+instance Unknown (DirectiveDefinitions s) (Directive s') ctx where
+  unknown _ _ _ Directive {directiveName, directivePosition} =
+    ValidationError
+      { validationMessage = "Unknown Directive " <> msg directiveName <> ".",
+        validationLocations = [directivePosition]
+      }
 
-instance Unknown (FieldsDefinition OUT) (OperationContext v) where
-  type UnknownSelector (FieldsDefinition OUT) = Ref
-  unknown OperationContext {scope = Scope {typename}} _ =
-    unknownSelectionField typename
+instance Unknown (FieldsDefinition OUT s) Ref (OperationContext s1 s2) where
+  unknown Scope {currentTypeName} _ _ = unknownSelectionField currentTypeName
 
 class KindViolation (t :: Target) ctx where
-  kindViolation :: c t -> ctx -> GQLError
+  kindViolation :: c t -> ctx -> ValidationError
 
-instance KindViolation 'TARGET_OBJECT Fragment where
+instance KindViolation 'TARGET_IMPLEMENTABLE (Fragment s) where
   kindViolation _ Fragment {fragmentName, fragmentType, fragmentPosition} =
-    GQLError
-      { message =
+    ValidationError
+      { validationMessage =
           "Fragment "
             <> msg fragmentName
             <> " cannot condition on non composite type "
             <> msg fragmentType
             <> ".",
-        locations = [fragmentPosition]
+        validationLocations = [fragmentPosition]
       }
 
 instance KindViolation 'TARGET_INPUT (Variable s) where
@@ -269,12 +215,12 @@
         variablePosition,
         variableType = TypeRef {typeConName}
       } =
-      GQLError
-        { message =
+      ValidationError
+        { validationMessage =
             "Variable "
               <> msg ("$" <> variableName)
               <> " cannot be non-input type "
               <> msg typeConName
               <> ".",
-          locations = [variablePosition]
+          validationLocations = [variablePosition]
         }
diff --git a/src/Data/Morpheus/Types/Internal/Validation/Internal.hs b/src/Data/Morpheus/Types/Internal/Validation/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Morpheus/Types/Internal/Validation/Internal.hs
@@ -0,0 +1,184 @@
+{-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE NamedFieldPuns #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+module Data.Morpheus.Types.Internal.Validation.Internal
+  ( askType,
+    askTypeMember,
+    getOperationType,
+    askInterfaceTypes,
+  )
+where
+
+-- MORPHEUS
+
+import Control.Applicative (Applicative, pure)
+import Control.Monad ((>=>), Monad ((>>=)))
+import Data.Functor ((<$>))
+import Data.Maybe (Maybe (..), maybe)
+import Data.Morpheus.Internal.Utils
+  ( Failure (..),
+    selectBy,
+  )
+import Data.Morpheus.Types.Internal.AST
+  ( ANY,
+    FieldsDefinition,
+    FromCategory,
+    IMPLEMENTABLE,
+    IN,
+    InternalError,
+    OBJECT,
+    OUT,
+    Operation,
+    Operation (..),
+    Stage,
+    TRUE,
+    Token,
+    TypeCategory,
+    TypeContent (..),
+    TypeContent,
+    TypeDefinition (..),
+    TypeName (..),
+    TypeRef,
+    Typed,
+    UnionMember (..),
+    VALID,
+    fromAny,
+    fromCategory,
+    getOperationDataType,
+    msgInternal,
+    possibleInterfaceTypes,
+    typeConName,
+    typed,
+    untyped,
+  )
+import Data.Morpheus.Types.Internal.Validation.Validator
+  ( MonadContext,
+    SelectionValidator,
+    askSchema,
+  )
+import Data.Semigroup
+  ( (<>),
+  )
+import Data.Traversable (traverse)
+import Prelude
+  ( ($),
+    (.),
+  )
+
+askType ::
+  Constraints m c cat s =>
+  Typed cat s TypeRef ->
+  m c (TypeDefinition cat s)
+askType = untyped (__askType . typeConName)
+
+askType2 ::
+  Constraints m c cat s =>
+  Typed cat s TypeName ->
+  m c (TypeDefinition cat s)
+askType2 = untyped __askType
+
+__askType ::
+  Constraints m c cat s => TypeName -> m c (TypeDefinition cat s)
+__askType name =
+  askSchema
+    >>= selectBy (unknownType name) name
+    >>= kindConstraint
+
+askTypeMember ::
+  Constraints m c cat s =>
+  UnionMember cat s ->
+  m c (TypeMemberResponse cat s)
+askTypeMember = askType2 . typed memberName >=> constraintObject
+
+askInterfaceTypes ::
+  ( Failure InternalError (m c),
+    Monad (m c),
+    MonadContext m s c,
+    FromCategory (TypeContent TRUE) ANY IMPLEMENTABLE
+  ) =>
+  TypeDefinition IMPLEMENTABLE s ->
+  m c [TypeDefinition IMPLEMENTABLE s]
+askInterfaceTypes typeDef@TypeDefinition {typeName} =
+  (typeDef :)
+    <$> ( askSchema
+            >>= traverse (validate . fromCategory) . possibleInterfaceTypes typeName
+        )
+  where
+    validate (Just x) = pure x
+    validate Nothing = failure ("TODO: invalid interface Types" :: InternalError)
+
+type family TypeMemberResponse (cat :: TypeCategory) (s :: Stage)
+
+type instance TypeMemberResponse OUT s = TypeDefinition OBJECT s
+
+type instance TypeMemberResponse IN s = (TypeDefinition IN s, FieldsDefinition IN s)
+
+type Constraints m c cat s =
+  ( Failure InternalError (m c),
+    Monad (m c),
+    MonadContext m s c,
+    KindErrors cat,
+    FromCategory (TypeContent TRUE) ANY cat
+  )
+
+getOperationType :: Operation a -> SelectionValidator (TypeDefinition OBJECT VALID)
+getOperationType operation = askSchema >>= getOperationDataType operation
+
+unknownType :: TypeName -> InternalError
+unknownType name = "Type \"" <> msgInternal name <> "\" can't found in Schema."
+
+type KindConstraint f c =
+  ( Failure InternalError f,
+    FromCategory TypeDefinition ANY c
+  )
+
+_kindConstraint ::
+  KindConstraint f k =>
+  Token ->
+  TypeDefinition ANY s ->
+  f (TypeDefinition k s)
+_kindConstraint err anyType =
+  maybe
+    (failure $ violation err (typeName anyType))
+    pure
+    (fromAny anyType)
+
+class KindErrors c where
+  kindConstraint :: KindConstraint f c => TypeDefinition ANY s -> f (TypeDefinition c s)
+  constraintObject ::
+    ( Applicative f,
+      Failure InternalError f
+    ) =>
+    TypeDefinition c s ->
+    f (TypeMemberResponse c s)
+
+instance KindErrors IN where
+  kindConstraint = _kindConstraint "input type"
+  constraintObject typeDef@TypeDefinition {typeContent = DataInputObject inputFields} = pure (typeDef, inputFields)
+  constraintObject TypeDefinition {typeName} = failure (violation "input object" typeName)
+
+instance KindErrors OUT where
+  kindConstraint = _kindConstraint "output type"
+  constraintObject TypeDefinition {typeContent = DataObject {..}, ..} = pure TypeDefinition {typeContent = DataObject {..}, ..}
+  constraintObject TypeDefinition {typeName} = failure (violation "object" typeName)
+
+violation ::
+  Token ->
+  TypeName ->
+  InternalError
+violation kind typeName =
+  "Type \"" <> msgInternal typeName
+    <> "\" must be an"
+    <> msgInternal kind
+    <> "."
diff --git a/src/Data/Morpheus/Types/Internal/Validation/SchemaValidator.hs b/src/Data/Morpheus/Types/Internal/Validation/SchemaValidator.hs
--- a/src/Data/Morpheus/Types/Internal/Validation/SchemaValidator.hs
+++ b/src/Data/Morpheus/Types/Internal/Validation/SchemaValidator.hs
@@ -10,10 +10,10 @@
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TupleSections #-}
 {-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Types.Internal.Validation.SchemaValidator
   ( SchemaValidator,
-    selectType,
     TypeSystemContext (..),
     constraintInterface,
     inField,
@@ -26,35 +26,28 @@
   )
 where
 
-import Control.Monad.Reader (asks)
 --import Data.Morpheus.Error.Document.Interface (unknownInterface)
-import Data.Morpheus.Error.Utils (globalErrorMessage)
+
 -- MORPHEUS
 
+import Control.Applicative (pure)
 import Data.Morpheus.Internal.Utils
   ( Failure (..),
-    fromElems,
-    selectBy,
   )
 import Data.Morpheus.Types.Internal.AST
   ( ANY,
+    CONST,
     FieldName,
     FieldsDefinition,
     OUT,
-    Position (..),
-    Schema,
     TypeContent (..),
     TypeDefinition (..),
     TypeName,
-    msg,
+    ValidationError,
+    msgValidation,
   )
-import Data.Morpheus.Types.Internal.Resolving (Result (..))
 import Data.Morpheus.Types.Internal.Validation.Validator
-  ( GetWith (..),
-    Scope (..),
-    ScopeKind (..),
-    SetWith (..),
-    Validator (..),
+  ( Validator (..),
     renderField,
     withContext,
   )
@@ -62,36 +55,16 @@
   ( (<>),
     Semigroup (..),
   )
+import Prelude
+  ( (.),
+    Show (..),
+    const,
+  )
 
-data TypeSystemContext c = TypeSystemContext
-  { types :: [TypeDefinition ANY],
-    local :: c
-  }
+newtype TypeSystemContext c = TypeSystemContext
+  {local :: c}
   deriving (Show)
 
-instance GetWith (TypeSystemContext ctx) Schema where
-  getWith ctx = case fromElems (types ctx) of
-    Success {result} -> result
-    Failure {errors} -> error (show errors)
-
-instance GetWith (TypeSystemContext a) Scope where
-  getWith _ =
-    Scope
-      { position = Position {line = 0, column = 0},
-        typename = "TODO:",
-        kind = TYPE
-      }
-
-instance SetWith (TypeSystemContext a) Scope where
-  setWith _ = id --TODO:
-
-selectType :: TypeName -> SchemaValidator ctx (TypeDefinition ANY)
-selectType name =
-  asks types
-    >>= selectBy err name
-  where
-    err = globalErrorMessage $ "Unknown Type " <> msg name <> "."
-
 inType ::
   TypeName ->
   SchemaValidator TypeName v ->
@@ -126,19 +99,21 @@
     fieldArgument :: FieldName
   }
 
-withLocalContext :: (a -> b) -> Validator (TypeSystemContext b) v -> Validator (TypeSystemContext a) v
+withLocalContext :: (a -> b) -> SchemaValidator b v -> SchemaValidator a v
 withLocalContext = withContext . updateLocal
 
 updateLocal :: (a -> b) -> TypeSystemContext a -> TypeSystemContext b
 updateLocal f ctx = ctx {local = f (local ctx)}
 
-type SchemaValidator c = Validator (TypeSystemContext c)
+type SchemaValidator c = Validator CONST (TypeSystemContext c)
 
-constraintInterface :: TypeDefinition ANY -> SchemaValidator ctx (TypeName, FieldsDefinition OUT)
+constraintInterface ::
+  TypeDefinition ANY CONST ->
+  SchemaValidator ctx (TypeName, FieldsDefinition OUT CONST)
 constraintInterface
   TypeDefinition
     { typeName,
       typeContent = DataInterface fields
     } = pure (typeName, fields)
 constraintInterface TypeDefinition {typeName} =
-  failure $ globalErrorMessage $ "type " <> msg typeName <> " must be an interface"
+  failure ["type " <> msgValidation typeName <> " must be an interface" :: ValidationError]
diff --git a/src/Data/Morpheus/Types/Internal/Validation/Validator.hs b/src/Data/Morpheus/Types/Internal/Validation/Validator.hs
--- a/src/Data/Morpheus/Types/Internal/Validation/Validator.hs
+++ b/src/Data/Morpheus/Types/Internal/Validation/Validator.hs
@@ -1,16 +1,19 @@
 {-# LANGUAGE DataKinds #-}
+{-# LANGUAGE DeriveFunctor #-}
 {-# LANGUAGE DerivingStrategies #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE FunctionalDependencies #-}
 {-# LANGUAGE GADTs #-}
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE RankNTypes #-}
 {-# LANGUAGE RecordWildCards #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Types.Internal.Validation.Validator
   ( Validator (..),
@@ -22,7 +25,7 @@
     withScope,
     withScopeType,
     withPosition,
-    withInputScope,
+    inField,
     inputMessagePrefix,
     InputSource (..),
     InputContext (..),
@@ -43,53 +46,81 @@
     withContext,
     renderField,
     asks,
+    asksScope,
     askSchema,
     askVariables,
     askFragments,
+    DirectiveValidator,
+    ValidatorContext (..),
+    FragmentValidator,
   )
 where
 
-import Control.Monad.Reader (MonadReader)
+-- MORPHEUS
+
+import Control.Applicative (Applicative)
+import Control.Monad (Monad)
+import Control.Monad.Reader (MonadReader (..))
 import Control.Monad.Trans.Class (MonadTrans (..))
 import Control.Monad.Trans.Reader
   ( ReaderT (..),
-    ask,
     withReaderT,
   )
--- MORPHEUS
+import Data.Functor ((<$>), Functor (..))
+import Data.Maybe (Maybe (..))
+import Data.Morpheus.Error.Utils
+  ( validationErrorMessage,
+  )
 import Data.Morpheus.Internal.Utils
   ( Failure (..),
   )
+import Data.Morpheus.Rendering.RenderGQL (RenderGQL (..))
 import Data.Morpheus.Types.Internal.AST
-  ( Argument (..),
-    Directive (..),
+  ( Directive (..),
+    FieldDefinition (..),
     FieldName (..),
-    FieldsDefinition,
     Fragments,
     GQLError (..),
     GQLErrors,
+    IMPLEMENTABLE,
     IN,
+    InternalError,
     Message,
-    OUT,
     Position,
     RAW,
-    RESOLVED,
     Ref (..),
     Schema,
-    TypeDefinition,
+    Stage,
+    TypeDefinition (..),
+    TypeKind (..),
     TypeName (..),
+    TypeRef (..),
+    TypeWrapper,
     VALID,
+    ValidationError (..),
     Variable (..),
     VariableDefinitions,
     intercalateName,
+    kindOf,
     msg,
+    msgValidation,
   )
+import Data.Morpheus.Types.Internal.Config (Config (..))
 import Data.Morpheus.Types.Internal.Resolving
   ( Eventless,
   )
 import Data.Semigroup
   ( (<>),
+    stimes,
   )
+import Prelude
+  ( ($),
+    (.),
+    Bool,
+    Int,
+    Show,
+    otherwise,
+  )
 
 data Prop = Prop
   { propName :: FieldName,
@@ -99,25 +130,25 @@
 
 type Path = [Prop]
 
-renderPath :: Path -> Message
+renderPath :: Path -> ValidationError
 renderPath [] = ""
-renderPath path = "in field " <> msg (intercalateName "." $ map propName path) <> ": "
+renderPath path = "in field " <> msgValidation (intercalateName "." $ fmap propName path) <> ": "
 
-renderInputPrefix :: InputContext c -> Message
+renderInputPrefix :: InputContext c -> ValidationError
 renderInputPrefix InputContext {inputPath, inputSource} =
   renderSource inputSource <> renderPath inputPath
 
-renderSource :: InputSource -> Message
-renderSource (SourceArgument Argument {argumentName}) =
-  "Argument " <> msg argumentName <> " got invalid value. "
+renderSource :: InputSource -> ValidationError
+renderSource (SourceArgument argumentName) =
+  "Argument " <> msgValidation argumentName <> " got invalid value. "
 renderSource (SourceVariable Variable {variableName} _) =
-  "Variable " <> msg ("$" <> variableName) <> " got invalid value. "
+  "Variable " <> msgValidation ("$" <> variableName) <> " got invalid value. "
 renderSource SourceInputField {sourceTypeName, sourceFieldName, sourceArgumentName} =
   "Field " <> renderField sourceTypeName sourceFieldName sourceArgumentName <> " got invalid default value. "
 
-renderField :: TypeName -> FieldName -> Maybe FieldName -> Message
+renderField :: TypeName -> FieldName -> Maybe FieldName -> ValidationError
 renderField (TypeName tname) (FieldName fname) arg =
-  msg (tname <> "." <> fname <> renderArg arg)
+  msgValidation (tname <> "." <> fname <> renderArg arg)
   where
     renderArg (Just (FieldName argName)) = "(" <> argName <> ":)"
     renderArg Nothing = ""
@@ -128,24 +159,27 @@
   | TYPE
   deriving (Show)
 
-data OperationContext vars = OperationContext
-  { schema :: Schema,
-    scope :: Scope,
-    fragments :: Fragments,
-    selection :: CurrentSelection,
-    variables :: vars
+data
+  OperationContext
+    (s1 :: Stage)
+    (s2 :: Stage) = OperationContext
+  { fragments :: Fragments s2,
+    variables :: VariableDefinitions s1,
+    selection :: CurrentSelection
   }
   deriving (Show)
 
-data CurrentSelection = CurrentSelection
-  { operationName :: Maybe FieldName,
-    selectionName :: FieldName
+newtype CurrentSelection = CurrentSelection
+  { operationName :: Maybe FieldName
   }
   deriving (Show)
 
 data Scope = Scope
-  { position :: Position,
-    typename :: TypeName,
+  { position :: Maybe Position,
+    currentTypeName :: TypeName,
+    currentTypeKind :: TypeKind,
+    currentTypeWrappers :: [TypeWrapper],
+    fieldname :: FieldName,
     kind :: ScopeKind
   }
   deriving (Show)
@@ -158,7 +192,7 @@
   deriving (Show)
 
 data InputSource
-  = SourceArgument (Argument RESOLVED)
+  = SourceArgument FieldName
   | SourceVariable
       { sourceVariable :: Variable RAW,
         isDefaultValue :: Bool
@@ -171,95 +205,102 @@
   deriving (Show)
 
 data Target
-  = TARGET_OBJECT
+  = TARGET_IMPLEMENTABLE
   | TARGET_INPUT
 
 data Constraint (a :: Target) where
-  OBJECT :: Constraint 'TARGET_OBJECT
+  IMPLEMENTABLE :: Constraint 'TARGET_IMPLEMENTABLE
   INPUT :: Constraint 'TARGET_INPUT
 
 --  UNION  :: Constraint 'TARGET_UNION
 
-type family Resolution (a :: Target)
+type family Resolution (s :: Stage) (a :: Target)
 
-type instance Resolution 'TARGET_OBJECT = (TypeName, FieldsDefinition OUT)
+type instance Resolution s 'TARGET_IMPLEMENTABLE = TypeDefinition IMPLEMENTABLE s
 
-type instance Resolution 'TARGET_INPUT = TypeDefinition IN
+type instance Resolution s 'TARGET_INPUT = TypeDefinition IN s
 
-withInputScope :: Prop -> InputValidator c a -> InputValidator c a
-withInputScope prop = withContext update
-  where
-    update
-      InputContext
-        { inputPath = old,
-          ..
-        } =
+inField :: FieldDefinition IN s -> InputValidator s c a -> InputValidator s c a
+inField
+  FieldDefinition
+    { fieldName,
+      fieldType = TypeRef {typeConName}
+    } = withContext update
+    where
+      update
         InputContext
-          { inputPath = old <> [prop],
+          { inputPath = old,
             ..
-          }
+          } =
+          InputContext
+            { inputPath = old <> [Prop fieldName typeConName],
+              ..
+            }
 
 inputValueSource ::
-  forall m c.
+  forall m c s.
   ( GetWith c InputSource,
-    MonadContext m c
+    MonadContext m s c
   ) =>
   m c InputSource
 inputValueSource = get
 
 asks ::
-  ( MonadContext m c,
+  ( MonadContext m s c,
     GetWith c t
   ) =>
   (t -> a) ->
   m c a
 asks f = f <$> get
 
-setSelectionName ::
-  ( MonadContext m c,
-    SetWith c CurrentSelection
+asksScope ::
+  ( MonadContext m s c
   ) =>
+  (Scope -> a) ->
+  m c a
+asksScope f = f <$> getGlobalContext scope
+
+setSelectionName ::
+  (MonadContext m s c) =>
   FieldName ->
   m c a ->
   m c a
-setSelectionName selectionName = set update
+setSelectionName fieldname = setScope update
   where
-    update ctx = ctx {selectionName}
+    update ctx = ctx {fieldname}
 
 askSchema ::
-  ( MonadContext m c,
-    GetWith c Schema
+  ( MonadContext m s c
   ) =>
-  m c Schema
-askSchema = get
+  m c (Schema s)
+askSchema = getGlobalContext schema
 
 askVariables ::
-  ( MonadContext m c,
+  ( MonadContext m s c,
     GetWith c (VariableDefinitions VALID)
   ) =>
   m c (VariableDefinitions VALID)
 askVariables = get
 
 askFragments ::
-  ( MonadContext m c,
-    GetWith c Fragments
+  ( MonadContext m s c,
+    GetWith c (Fragments s')
   ) =>
-  m c Fragments
+  m c (Fragments s')
 askFragments = get
 
-runValidator :: Validator ctx a -> ctx -> Eventless a
-runValidator (Validator x) = runReaderT x
+runValidator :: Validator s ctx a -> Config -> Schema s -> Scope -> ctx -> Eventless a
+runValidator (Validator x) config schema scope validatorCTX =
+  runReaderT x ValidatorContext {..}
 
 withContext ::
   (c' -> c) ->
-  Validator c a ->
-  Validator c' a
-withContext f = Validator . withReaderT f . _runValidator
+  Validator s c a ->
+  Validator s c' a
+withContext f = Validator . withReaderT (fmap f) . _runValidator
 
 withDirective ::
-  ( SetWith c CurrentSelection,
-    SetWith c Scope,
-    MonadContext m c
+  ( MonadContext m schemaS c
   ) =>
   Directive s ->
   m c a ->
@@ -268,58 +309,68 @@
   Directive
     { directiveName,
       directivePosition
-    } = setSelectionName directiveName . set update
+    } = setSelectionName directiveName . setScope update
     where
       update Scope {..} =
         Scope
-          { position = directivePosition,
+          { position = Just directivePosition,
             kind = DIRECTIVE,
             ..
           }
 
 withScope ::
-  ( SetWith c CurrentSelection,
-    MonadContext m c,
-    SetWith c Scope
+  ( MonadContext m s c
   ) =>
-  TypeName ->
+  TypeDefinition cat s ->
   Ref ->
   m c a ->
   m c a
-withScope typeName (Ref selName pos) =
-  setSelectionName selName . set update
+withScope t@TypeDefinition {typeName} (Ref selName pos) =
+  setSelectionName selName . setScope update
   where
-    update Scope {..} = Scope {typename = typeName, position = pos, ..}
+    update Scope {..} =
+      Scope
+        { currentTypeName = typeName,
+          currentTypeKind = kindOf t,
+          position = Just pos,
+          ..
+        }
 
-withPosition ::
-  ( MonadContext m c,
-    SetWith c Scope
+withScopeType ::
+  ( MonadContext m s c
   ) =>
-  Position ->
+  (TypeDefinition cat s, [TypeWrapper]) ->
   m c a ->
   m c a
-withPosition pos = set update
+withScopeType (t@TypeDefinition {typeName}, wrappers) = setScope update
   where
-    update Scope {..} = Scope {position = pos, ..}
+    update Scope {..} =
+      Scope
+        { currentTypeName = typeName,
+          currentTypeKind = kindOf t,
+          currentTypeWrappers = wrappers,
+          ..
+        }
 
-withScopeType ::
-  ( MonadContext m c,
-    SetWith c Scope
+withPosition ::
+  ( MonadContext m s c
   ) =>
-  TypeName ->
+  Position ->
   m c a ->
   m c a
-withScopeType name = set update
+withPosition pos = setScope update
   where
-    update Scope {..} = Scope {typename = name, ..}
+    update Scope {..} = Scope {position = Just pos, ..}
 
-inputMessagePrefix :: InputValidator ctx Message
-inputMessagePrefix = renderInputPrefix <$> Validator ask
+inputMessagePrefix :: InputValidator s ctx ValidationError
+inputMessagePrefix =
+  renderInputPrefix
+    . validatorCTX <$> Validator ask
 
 startInput ::
   InputSource ->
-  InputValidator ctx a ->
-  Validator ctx a
+  InputValidator s ctx a ->
+  Validator s ctx a
 startInput inputSource = withContext update
   where
     update sourceContext =
@@ -329,114 +380,166 @@
           sourceContext
         }
 
-newtype Validator ctx a = Validator
+data ValidatorContext (s :: Stage) (ctx :: *) = ValidatorContext
+  { scope :: Scope,
+    schema :: Schema s,
+    validatorCTX :: ctx,
+    config :: Config
+  }
+  deriving (Show, Functor)
+
+newtype Validator s ctx a = Validator
   { _runValidator ::
       ReaderT
-        ctx
+        (ValidatorContext s ctx)
         Eventless
         a
   }
   deriving newtype
     ( Functor,
       Applicative,
-      Monad,
-      MonadReader ctx
+      Monad
     )
 
-type BaseValidator = Validator (OperationContext ())
+instance MonadReader ctx (Validator s ctx) where
+  ask = validatorCTX <$> Validator ask
+  local = withContext
 
-type SelectionValidator = Validator (OperationContext (VariableDefinitions VALID))
+type BaseValidator = Validator VALID (OperationContext RAW RAW)
 
-type InputValidator ctx = Validator (InputContext ctx)
+type FragmentValidator (s :: Stage) = Validator VALID (OperationContext VALID s)
 
--- Helpers
-get :: (MonadContext m ctx, GetWith ctx a) => m ctx a
-get = getContext getWith
+type SelectionValidator = Validator VALID (OperationContext VALID VALID)
 
-set ::
-  ( MonadContext m c,
-    SetWith c a
-  ) =>
-  (a -> a) ->
+type InputValidator s ctx = Validator s (InputContext ctx)
+
+type DirectiveValidator ctx = Validator ctx
+
+setScope ::
+  (MonadContext m s c) =>
+  (Scope -> Scope) ->
   m c b ->
   m c b
-set f = setContext (setWith f)
+setScope f = setGlobalContext (mapScope f)
 
+mapScope :: (Scope -> Scope) -> ValidatorContext s ctx -> ValidatorContext s ctx
+mapScope f ValidatorContext {scope, ..} = ValidatorContext {scope = f scope, ..}
+
+-- Helpers
+get :: (MonadContext m s ctx, GetWith ctx a) => m ctx a
+get = getContext getWith
+
 class
   Monad (m c) =>
-  MonadContext m c
+  MonadContext m s c
+    | m -> s
   where
+  getGlobalContext :: (ValidatorContext s c -> a) -> m c a
+  setGlobalContext :: (ValidatorContext s c -> ValidatorContext s c) -> m c b -> m c b
   getContext :: (c -> a) -> m c a
   setContext :: (c -> c) -> m c b -> m c b
 
-instance MonadContext Validator c where
-  getContext f = f <$> Validator ask
+instance MonadContext (Validator s) s c where
+  getGlobalContext f = f <$> Validator ask
+  getContext f = f . validatorCTX <$> Validator ask
+  setGlobalContext f = Validator . withReaderT f . _runValidator
   setContext = withContext
 
 class GetWith (c :: *) (v :: *) where
   getWith :: c -> v
 
-instance GetWith (OperationContext v) Scope where
-  getWith = scope
-
-instance GetWith c Scope => GetWith (InputContext c) Scope where
-  getWith = getWith . sourceContext
-
-instance GetWith (OperationContext c) Schema where
-  getWith = schema
-
-instance GetWith c Schema => GetWith (InputContext c) Schema where
-  getWith = getWith . sourceContext
-
-instance GetWith (OperationContext (VariableDefinitions VALID)) (VariableDefinitions VALID) where
+instance GetWith (OperationContext VALID fragStage) (VariableDefinitions VALID) where
   getWith = variables
 
 instance GetWith (InputContext ctx) InputSource where
   getWith = inputSource
 
-instance GetWith (OperationContext v) Fragments where
+instance GetWith (OperationContext varStage fragStage) (Fragments fragStage) where
   getWith = fragments
 
 -- Setters
 class SetWith (c :: *) (v :: *) where
   setWith :: (v -> v) -> c -> c
 
-instance SetWith (OperationContext v) CurrentSelection where
+instance SetWith (OperationContext s1 s2) CurrentSelection where
   setWith f OperationContext {selection = selection, ..} =
     OperationContext
       { selection = f selection,
         ..
       }
 
-instance SetWith (OperationContext v) Scope where
-  setWith f OperationContext {..} =
-    OperationContext
-      { scope = f scope,
-        ..
-      }
+instance Failure [ValidationError] (Validator s ctx) where
+  failure errors = do
+    ctx <- Validator ask
+    failValidator (fmap (fromValidatinError ctx) errors)
 
-instance SetWith c Scope => SetWith (InputContext c) Scope where
-  setWith f InputContext {..} =
-    InputContext
-      { sourceContext = setWith f sourceContext,
-        ..
+instance Failure ValidationError (Validator s ctx) where
+  failure err = failure [err]
+
+failValidator :: GQLErrors -> Validator s ctx a
+failValidator = Validator . lift . failure
+
+fromValidatinError :: ValidatorContext s ctx -> ValidationError -> GQLError
+fromValidatinError
+  context@ValidatorContext
+    { config
+    }
+  (ValidationError text locations) =
+    GQLError
+      { message,
+        locations
       }
+    where
+      message
+        | debug config = text <> renderContext context
+        | otherwise = text
 
 -- can be only used for internal errors
 instance
-  ( MonadContext Validator ctx,
-    GetWith ctx Scope
-  ) =>
-  Failure Message (Validator ctx)
+  (MonadContext (Validator s) s ctx) =>
+  Failure InternalError (Validator s ctx)
   where
   failure inputMessage = do
-    position <- asks position
+    ctx <- Validator ask
     failure
-      [ GQLError
-          { message = "INTERNAL: " <> inputMessage,
-            locations = [position]
-          }
-      ]
+      ( validationErrorMessage
+          (position $ scope ctx)
+          $ msg
+            inputMessage
+            <> renderContext ctx
+      )
 
-instance Failure GQLErrors (Validator ctx) where
-  failure = Validator . lift . failure
+renderContext :: ValidatorContext s ctx -> Message
+renderContext
+  ValidatorContext
+    { schema,
+      scope
+    } =
+    renderScope scope
+      <> renderSection "SchemaDefinition" schema
+
+renderScope :: Scope -> Message
+renderScope
+  Scope
+    { currentTypeName,
+      currentTypeKind,
+      fieldname
+    } =
+    renderSection
+      "Scope"
+      ( "referenced by type "
+          <> render currentTypeName
+          <> " of kind "
+          <> render currentTypeKind
+          <> " in field "
+          <> render fieldname
+      )
+
+renderSection :: RenderGQL a => Message -> a -> Message
+renderSection label content =
+  "\n\n" <> label <> ":\n" <> line
+    <> "\n\n"
+    <> msg (render content)
+    <> "\n\n"
+  where
+    line = stimes (50 :: Int) "-"
diff --git a/src/Data/Morpheus/Types/SelectionTree.hs b/src/Data/Morpheus/Types/SelectionTree.hs
--- a/src/Data/Morpheus/Types/SelectionTree.hs
+++ b/src/Data/Morpheus/Types/SelectionTree.hs
@@ -1,18 +1,30 @@
 {-# LANGUAGE AllowAmbiguousTypes #-}
 {-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 -- |
 -- Module      : Data.Morpheus.Types.SelectionTree
 -- Description : A simple interface for Morpheus internal Selection Set's representation.
 module Data.Morpheus.Types.SelectionTree where
 
+import Data.Bool (Bool (..))
+import Data.Foldable (concatMap)
+import Data.Monoid (mempty)
 import Data.Morpheus.Internal.Utils (elems, keyOf)
-import Data.Morpheus.Types.Internal.AST.Base (FieldName, VALID)
-import Data.Morpheus.Types.Internal.AST.Selection
-  ( Selection (..),
+import Data.Morpheus.Types.Internal.AST
+  ( FieldName (..),
+    Selection (..),
     Selection (selectionContent),
-    SelectionContent (SelectionField, SelectionSet),
+    SelectionContent (SelectionField, SelectionSet, UnionSelection),
+    UnionTag (..),
+    VALID,
   )
+import Data.String
+  ( IsString (..),
+  )
+import Data.Text (unpack)
+import Prelude ((.))
 
 -- | The 'SelectionTree' instance is a simple interface for interacting
 -- with morpheus's internal AST while keeping the ability to safely change the concrete
@@ -26,7 +38,7 @@
   getChildrenList :: nodeType -> [nodeType]
 
   -- | get a node's name
-  getName :: nodeType -> FieldName
+  getName :: IsString name => nodeType -> name
 
 instance SelectionTree (Selection VALID) where
   isLeaf node = case selectionContent node of
@@ -36,5 +48,13 @@
   getChildrenList node = case selectionContent node of
     SelectionField -> mempty
     (SelectionSet deeperSel) -> elems deeperSel
+    (UnionSelection sel) ->
+      concatMap
+        (elems . unionTagSelection)
+        (elems sel)
 
-  getName = keyOf
+  getName =
+    fromString
+      . unpack
+      . readName
+      . keyOf
diff --git a/src/Data/Morpheus/Validation/Document/Validation.hs b/src/Data/Morpheus/Validation/Document/Validation.hs
--- a/src/Data/Morpheus/Validation/Document/Validation.hs
+++ b/src/Data/Morpheus/Validation/Document/Validation.hs
@@ -1,62 +1,84 @@
+{-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE DataKinds #-}
 {-# LANGUAGE DuplicateRecordFields #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE GADTs #-}
+{-# LANGUAGE KindSignatures #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE NamedFieldPuns #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Validation.Document.Validation
-  ( validatePartialDocument,
-    validateSchema,
+  ( ValidateSchema (..),
   )
 where
 
+import Control.Applicative ((*>), (<*>), Applicative (..), pure)
 import Control.Monad ((>=>))
 import Control.Monad.Reader (asks)
 import Data.Foldable (traverse_)
-import Data.Functor (($>))
---
--- Morpheus
-
+import Data.Functor ((<$>), fmap)
+import Data.Maybe (Maybe (..), maybe)
 import Data.Morpheus.Error.Document.Interface
   ( ImplementsError (..),
     PartialImplements (..),
   )
 import Data.Morpheus.Internal.Utils
-  ( KeyOf (..),
+  ( (<:>),
+    KeyOf (..),
     Selectable (..),
     elems,
     empty,
     failure,
+    ordTraverse,
   )
-import Data.Morpheus.Schema.Schema (systemTypes)
+import Data.Morpheus.Schema.Schema
+  ( internalSchema,
+  )
 import Data.Morpheus.Types.Internal.AST
-  ( ANY,
-    ArgumentDefinition,
+  ( ArgumentDefinition,
     ArgumentsDefinition (..),
+    CONST,
+    DataEnumValue (..),
+    DirectiveDefinition (..),
+    DirectiveLocation (..),
     FieldContent (..),
     FieldDefinition (..),
     FieldName (..),
     FieldsDefinition,
     IN,
     OUT,
-    ObjectEntry (..),
-    Schema,
+    Schema (..),
+    Schema (..),
     TRUE,
+    TypeCategory,
     TypeContent (..),
     TypeDefinition (..),
+    TypeKind (..),
     TypeName,
     TypeRef (..),
+    Typed (..),
+    UnionMember (..),
+    VALID,
+    Value,
     isWeaker,
   )
+import Data.Morpheus.Types.Internal.Config (Config (..))
 import Data.Morpheus.Types.Internal.Resolving
   ( Eventless,
   )
 import Data.Morpheus.Types.Internal.Validation
   ( InputSource (..),
     InputValidator,
-    askInputFieldType,
+    Scope (..),
+    ScopeKind (..),
     runValidator,
+    selectType,
     startInput,
   )
 import Data.Morpheus.Types.Internal.Validation.SchemaValidator
@@ -69,82 +91,243 @@
     inField,
     inInterface,
     inType,
-    selectType,
   )
-import Data.Morpheus.Validation.Internal.Value (validateInput)
-import Data.Semigroup ((<>))
+import Data.Morpheus.Validation.Internal.Directive
+  ( validateDirectives,
+  )
+import Data.Morpheus.Validation.Internal.Value
+  ( validateInputByTypeRef,
+  )
+import Data.Proxy (Proxy (..))
+import Data.Traversable (traverse)
+import Prelude
+  ( ($),
+    (&&),
+    (.),
+    (==),
+    Bool,
+    not,
+    otherwise,
+  )
 
-validateSchema :: Schema -> Eventless Schema
-validateSchema schema = validatePartialDocument (elems schema) $> schema
+class ValidateSchema s where
+  validateSchema :: Bool -> Config -> Schema s -> Eventless (Schema VALID)
 
-validatePartialDocument :: [TypeDefinition ANY] -> Eventless [TypeDefinition ANY]
-validatePartialDocument types =
-  runValidator
-    (traverse validateType types)
-    TypeSystemContext
-      { types = systemTypes <> types,
-        local = ()
-      }
+instance ValidateSchema CONST where
+  validateSchema
+    withSystem
+    config
+    schema@Schema
+      { types,
+        query,
+        mutation,
+        subscription,
+        directiveDefinitions
+      } = do
+      sysSchema <-
+        if withSystem
+          then internalSchema <:> schema
+          else pure schema
+      runValidator
+        __validateSchema
+        config
+        sysSchema
+        Scope
+          { position = Nothing,
+            currentTypeName = "Root",
+            currentTypeKind = KindObject Nothing,
+            currentTypeWrappers = [],
+            kind = TYPE,
+            fieldname = "Root"
+          }
+        TypeSystemContext
+          { local = ()
+          }
+      where
+        __validateSchema :: SchemaValidator () (Schema VALID)
+        __validateSchema =
+          Schema
+            <$> traverse validateType types
+            <*> validateType query
+            <*> validateOptional validateType mutation
+            <*> validateOptional validateType subscription
+            <*> traverse validateDirectiveDefinition directiveDefinitions
 
+validateOptional :: Applicative f => (a -> f b) -> Maybe a -> f (Maybe b)
+validateOptional f = maybe (pure Nothing) (fmap Just . f)
+
+instance ValidateSchema VALID where
+  validateSchema _ _ = pure
+
 validateType ::
-  TypeDefinition ANY ->
-  SchemaValidator () (TypeDefinition ANY)
+  TypeDefinition cat CONST ->
+  SchemaValidator () (TypeDefinition cat VALID)
 validateType
-  dt@TypeDefinition
+  TypeDefinition
     { typeName,
-      typeContent =
-        DataObject
-          { objectImplements,
-            objectFields
-          }
-    } = inType typeName $
+      typeFingerprint,
+      typeDescription,
+      typeDirectives,
+      typeContent
+    } =
+    inType typeName $
+      TypeDefinition
+        typeName
+        typeFingerprint
+        typeDescription
+        <$> validateDirectives (typeDirectiveLocation typeContent) typeDirectives
+        <*> validateTypeContent typeContent
+
+typeDirectiveLocation :: TypeContent a b c -> DirectiveLocation
+typeDirectiveLocation DataObject {} = OBJECT
+typeDirectiveLocation DataInputObject {} = INPUT_OBJECT
+typeDirectiveLocation DataScalar {} = SCALAR
+typeDirectiveLocation DataEnum {} = ENUM
+typeDirectiveLocation DataInputUnion {} = OBJECT
+typeDirectiveLocation DataUnion {} = UNION
+typeDirectiveLocation DataInterface {} = INTERFACE
+
+validateTypeContent ::
+  TypeContent TRUE cat CONST ->
+  SchemaValidator TypeName (TypeContent TRUE cat VALID)
+validateTypeContent
+  DataObject
+    { objectImplements,
+      objectFields
+    } =
     do
       validateImplements objectImplements objectFields
-      traverse_ checkFieldArgsuments objectFields
-      pure dt
-validateType
-  dt@TypeDefinition
-    { typeContent = DataInputObject {inputObjectFields},
-      typeName
-    } = inType typeName $ do
-    traverse_ validateFieldDefaultValue inputObjectFields
-    pure dt
-validateType x = pure x
+      DataObject objectImplements <$> ordTraverse validateField objectFields
+validateTypeContent DataInputObject {inputObjectFields} =
+  DataInputObject <$> ordTraverse validateField inputObjectFields
+validateTypeContent DataScalar {..} = pure DataScalar {..}
+validateTypeContent DataEnum {enumMembers} = DataEnum <$> traverse validateEnumMember enumMembers
+validateTypeContent DataInputUnion {inputUnionMembers} =
+  DataInputUnion <$> traverse validateUnionMember inputUnionMembers
+validateTypeContent DataUnion {unionMembers} = DataUnion <$> traverse validateUnionMember unionMembers
+validateTypeContent (DataInterface fields) =
+  DataInterface <$> ordTraverse validateField fields
 
+validateEnumMember ::
+  DataEnumValue CONST -> SchemaValidator TypeName (DataEnumValue VALID)
+validateEnumMember DataEnumValue {enumDirectives = directives, ..} = do
+  enumDirectives <- validateDirectives ENUM_VALUE directives
+  pure DataEnumValue {..}
+
+validateUnionMember ::
+  UnionMember cat CONST -> SchemaValidator TypeName (UnionMember cat VALID)
+validateUnionMember UnionMember {..} = pure UnionMember {..}
+
+class FieldDirectiveLocation (cat :: TypeCategory) where
+  directiveLocation :: Proxy cat -> DirectiveLocation
+
+instance FieldDirectiveLocation OUT where
+  directiveLocation _ = FIELD_DEFINITION
+
+instance FieldDirectiveLocation IN where
+  directiveLocation _ = INPUT_FIELD_DEFINITION
+
+validateField ::
+  forall cat.
+  FieldDirectiveLocation cat =>
+  FieldDefinition cat CONST ->
+  SchemaValidator TypeName (FieldDefinition cat VALID)
+validateField field@FieldDefinition {..} =
+  inField
+    fieldName
+    ( FieldDefinition
+        fieldName
+        fieldDescription
+        fieldType
+        <$> validateDirectives (directiveLocation (Proxy @cat)) fieldDirectives
+          <*> validateOptional (checkFieldContent field) fieldContent
+    )
+
+checkFieldContent ::
+  FieldDefinition cat CONST ->
+  FieldContent TRUE cat CONST ->
+  SchemaValidator (TypeName, FieldName) (FieldContent TRUE cat VALID)
+checkFieldContent _ (FieldArgs argsDef) = FieldArgs <$> validateArgumentsDefinition argsDef
+checkFieldContent FieldDefinition {fieldType} (DefaultInputValue value) = do
+  (typeName, fName) <- asks local
+  DefaultInputValue
+    <$> startInput
+      (SourceInputField typeName fName Nothing)
+      (validateDefaultValue fieldType value)
+
+validateArgumentsDefinition ::
+  ArgumentsDefinition CONST ->
+  SchemaValidator (TypeName, FieldName) (ArgumentsDefinition VALID)
+validateArgumentsDefinition (ArgumentsDefinition meta args) =
+  ArgumentsDefinition meta
+    <$> ordTraverse
+      validateArgumentDefinition
+      args
+
+validateArgumentDefinition ::
+  ArgumentDefinition CONST ->
+  SchemaValidator (TypeName, FieldName) (ArgumentDefinition VALID)
+validateArgumentDefinition FieldDefinition {..} =
+  FieldDefinition
+    fieldName
+    fieldDescription
+    fieldType
+    <$> validateDirectives ARGUMENT_DEFINITION fieldDirectives
+    <*> validateOptional (validateArgumentDefaultValue fieldName fieldType) fieldContent
+
+validateArgumentDefaultValue ::
+  FieldName ->
+  TypeRef ->
+  FieldContent TRUE IN CONST ->
+  SchemaValidator (TypeName, FieldName) (FieldContent TRUE IN VALID)
+validateArgumentDefaultValue argName fieldType (DefaultInputValue value) =
+  do
+    (typeName, fName) <- asks local
+    v <-
+      startInput
+        (SourceInputField typeName fName (Just argName))
+        (validateDefaultValue fieldType value)
+    pure (DefaultInputValue v)
+
 -- INETRFACE
 ----------------------------
 validateImplements ::
   [TypeName] ->
-  FieldsDefinition OUT ->
+  FieldsDefinition OUT CONST ->
   SchemaValidator TypeName ()
 validateImplements objectImplements objectFields = do
   interface <- traverse selectInterface objectImplements
   traverse_ (mustBeSubset objectFields) interface
 
 mustBeSubset ::
-  FieldsDefinition OUT -> (TypeName, FieldsDefinition OUT) -> SchemaValidator TypeName ()
+  FieldsDefinition OUT CONST ->
+  (TypeName, FieldsDefinition OUT CONST) ->
+  SchemaValidator TypeName ()
 mustBeSubset objFields (typeName, fields) =
   inInterface typeName $
     traverse_ (checkInterfaceField objFields) (elems fields)
 
 checkInterfaceField ::
-  FieldsDefinition OUT ->
-  FieldDefinition OUT ->
+  FieldsDefinition OUT CONST ->
+  FieldDefinition OUT CONST ->
   SchemaValidator Interface ()
 checkInterfaceField
   objFields
   interfaceField@FieldDefinition
-    { fieldName
+    { fieldName,
+      fieldDirectives
     } =
     inField fieldName $
-      selectOr err (isSuptype interfaceField) fieldName objFields
+      do
+        _ <- validateDirectives FIELD_DEFINITION fieldDirectives
+        selectOr err (isSuptype interfaceField) fieldName objFields
     where
       err = failImplements Missing
 
 class PartialImplements ctx => TypeEq a ctx where
   isSuptype :: a -> a -> SchemaValidator ctx ()
 
-instance TypeEq (FieldDefinition OUT) (Interface, FieldName) where
+instance TypeEq (FieldDefinition OUT CONST) (Interface, FieldName) where
   FieldDefinition
     { fieldType,
       fieldContent = args1
@@ -154,10 +337,10 @@
         fieldContent = args2
       } = (fieldType `isSuptype` fieldType') *> (args1 `isSuptype` args2)
 
-instance TypeEq (Maybe (FieldContent TRUE OUT)) (Interface, FieldName) where
+instance TypeEq (Maybe (FieldContent TRUE OUT s)) (Interface, FieldName) where
   f1 `isSuptype` f2 = toARgs f1 `isSuptype` toARgs f2
     where
-      toARgs :: Maybe (FieldContent TRUE OUT) -> ArgumentsDefinition
+      toARgs :: Maybe (FieldContent TRUE OUT s) -> ArgumentsDefinition s
       toARgs (Just (FieldArgs args)) = args
       toARgs _ = empty
 
@@ -175,8 +358,8 @@
         failImplements UnexpectedType {expectedType = t1, foundType = t2}
 
 elemIn ::
-  ( KeyOf a,
-    Selectable c a,
+  ( KeyOf k a,
+    Selectable k a c,
     TypeEq a ctx
   ) =>
   a ->
@@ -184,18 +367,18 @@
   SchemaValidator ctx ()
 elemIn el = selectOr (failImplements Missing) (isSuptype el) (keyOf el)
 
-instance TypeEq ArgumentsDefinition (Interface, FieldName) where
+instance TypeEq (ArgumentsDefinition s) (Interface, FieldName) where
   args1 `isSuptype` args2 = traverse_ validateArg (elems args1)
     where
       validateArg arg = inArgument (keyOf arg) $ elemIn arg args2
 
-instance TypeEq ArgumentDefinition (Interface, Field) where
+instance TypeEq (ArgumentDefinition s) (Interface, Field) where
   arg1 `isSuptype` arg2 = fieldType arg1 `isSuptype` fieldType arg2
 
 -------------------------------
 selectInterface ::
   TypeName ->
-  SchemaValidator ctx (TypeName, FieldsDefinition OUT)
+  SchemaValidator ctx (TypeName, FieldsDefinition OUT CONST)
 selectInterface = selectType >=> constraintInterface
 
 failImplements ::
@@ -206,47 +389,21 @@
   x <- asks local
   failure $ partialImplements x err
 
-checkFieldArgsuments ::
-  FieldDefinition OUT ->
-  SchemaValidator TypeName ()
-checkFieldArgsuments FieldDefinition {fieldContent = Nothing} = pure ()
-checkFieldArgsuments FieldDefinition {fieldContent = Just (FieldArgs args), fieldName} = do
-  typeName <- asks local
-  traverse_ (validateArgumentDefaultValue typeName fieldName) (elems args)
-
-validateArgumentDefaultValue ::
-  TypeName ->
-  FieldName ->
-  ArgumentDefinition ->
-  SchemaValidator TypeName ()
-validateArgumentDefaultValue _ _ FieldDefinition {fieldContent = Nothing} = pure ()
-validateArgumentDefaultValue
-  typeName
-  fName
-  inputField@FieldDefinition {fieldName = argName} =
-    startInput (SourceInputField typeName fName (Just argName)) $
-      validateDefaultValue inputField
-
 -- DEFAULT VALUE
--- TODO: implement default value validation
-validateFieldDefaultValue ::
-  FieldDefinition IN ->
-  SchemaValidator TypeName ()
-validateFieldDefaultValue inputField@FieldDefinition {fieldName} = do
-  typeName <- asks local
-  startInput (SourceInputField typeName fieldName Nothing) $
-    validateDefaultValue inputField
 
 validateDefaultValue ::
-  FieldDefinition IN ->
-  InputValidator (TypeSystemContext TypeName) ()
-validateDefaultValue FieldDefinition {fieldContent = Nothing} = pure ()
-validateDefaultValue
-  inputField@FieldDefinition
-    { fieldName,
-      fieldType = TypeRef {typeWrappers},
-      fieldContent = Just DefaultInputValue {defaultInputValue}
-    } = do
-    datatype <- askInputFieldType inputField
-    _ <- validateInput typeWrappers datatype (ObjectEntry fieldName defaultInputValue)
-    pure ()
+  TypeRef ->
+  Value CONST ->
+  InputValidator
+    CONST
+    (TypeSystemContext (TypeName, FieldName))
+    (Value VALID)
+validateDefaultValue typeRef =
+  validateInputByTypeRef (Typed typeRef)
+
+-- TODO: validate directives
+validateDirectiveDefinition :: DirectiveDefinition CONST -> SchemaValidator () (DirectiveDefinition VALID)
+validateDirectiveDefinition DirectiveDefinition {directiveDefinitionArgs = args, ..} =
+  inType "Directive" $ inField directiveDefinitionName $ do
+    directiveDefinitionArgs <- validateArgumentsDefinition args
+    pure DirectiveDefinition {..}
diff --git a/src/Data/Morpheus/Validation/Internal/Arguments.hs b/src/Data/Morpheus/Validation/Internal/Arguments.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Morpheus/Validation/Internal/Arguments.hs
@@ -0,0 +1,179 @@
+{-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE KindSignatures #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE NamedFieldPuns #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+module Data.Morpheus.Validation.Internal.Arguments
+  ( validateDirectiveArguments,
+    validateFieldArguments,
+    ArgumentsConstraints,
+    Resolve,
+  )
+where
+
+import Control.Applicative ((*>), pure)
+import Control.Monad ((>=>), (>>=))
+import Data.Functor ((<$>), fmap)
+import Data.Maybe (fromMaybe, maybe)
+import Data.Morpheus.Internal.Utils
+  ( empty,
+    ordTraverse,
+    ordTraverse_,
+  )
+import Data.Morpheus.Types.Internal.AST
+  ( Argument (..),
+    ArgumentDefinition,
+    Arguments,
+    ArgumentsDefinition (..),
+    CONST,
+    DirectiveDefinition,
+    DirectiveDefinition (..),
+    FieldDefinition (..),
+    IN,
+    OUT,
+    ObjectEntry (..),
+    Position (..),
+    RAW,
+    VALID,
+    Value (..),
+    VariableDefinitions,
+    fieldContentArgs,
+    typed,
+  )
+import Data.Morpheus.Types.Internal.Validation
+  ( FragmentValidator,
+    GetWith,
+    InputSource (..),
+    MissingRequired,
+    Scope (..),
+    Validator,
+    askVariables,
+    asksScope,
+    selectKnown,
+    selectRequired,
+    selectWithDefaultValue,
+    startInput,
+    withPosition,
+  )
+import Data.Morpheus.Validation.Internal.Value
+  ( ValidateWithDefault,
+    validateInputByTypeRef,
+  )
+import Data.Traversable (traverse)
+import Prelude
+  ( ($),
+    (.),
+    flip,
+  )
+
+type VariableConstraints ctx =
+  ( GetWith ctx (VariableDefinitions VALID),
+    MissingRequired (VariableDefinitions VALID) ctx
+  )
+
+type ArgumentsConstraints c schemaS valueS =
+  ( Resolve Argument valueS c,
+    ValidateWithDefault c schemaS schemaS,
+    ValidateWithDefault c schemaS CONST
+  )
+
+validateArgument ::
+  ( ValidateWithDefault ctx schemaS valueS,
+    ValidateWithDefault ctx schemaS schemaS
+  ) =>
+  Arguments valueS ->
+  FieldDefinition IN schemaS ->
+  Validator schemaS ctx (Argument VALID)
+validateArgument
+  requestArgs
+  argumentDef =
+    selectWithDefaultValue
+      (toArgument argumentDef >=> validateArgumentValue argumentDef)
+      (validateArgumentValue argumentDef)
+      argumentDef
+      requestArgs
+
+toArgument :: FieldDefinition IN s -> Value schemaS -> Validator schemaStage ctx (Argument schemaS)
+toArgument
+  FieldDefinition {fieldName}
+  value = flip (Argument fieldName) value . fromMaybe (Position 0 0) <$> asksScope position
+
+validateArgumentValue ::
+  (ValidateWithDefault ctx schemaS valueS) =>
+  FieldDefinition IN schemaS ->
+  Argument valueS ->
+  Validator schemaS ctx (Argument VALID)
+validateArgumentValue
+  field
+  Argument {argumentValue, ..} =
+    withPosition argumentPosition
+      $ startInput (SourceArgument argumentName)
+      $ Argument
+        argumentName
+        argumentPosition
+        <$> validateInputByTypeRef (typed fieldType field) argumentValue
+
+validateFieldArguments ::
+  FieldDefinition OUT VALID ->
+  Arguments RAW ->
+  FragmentValidator s (Arguments VALID)
+validateFieldArguments fieldDef@FieldDefinition {fieldContent} =
+  validateArguments
+    (`selectKnown` fieldDef)
+    argsDef
+  where
+    argsDef = maybe empty fieldContentArgs fieldContent
+
+validateDirectiveArguments ::
+  ArgumentsConstraints ctx schemaStage valueStage =>
+  DirectiveDefinition schemaStage ->
+  Arguments valueStage ->
+  Validator schemaStage ctx (Arguments VALID)
+validateDirectiveArguments
+  directiveDef@DirectiveDefinition
+    { directiveDefinitionArgs
+    } =
+    validateArguments
+      (`selectKnown` directiveDef)
+      directiveDefinitionArgs
+
+validateArguments ::
+  ArgumentsConstraints ctx schemaStage s =>
+  (Argument CONST -> Validator schemaStage ctx (ArgumentDefinition schemaStage)) ->
+  ArgumentsDefinition schemaStage ->
+  Arguments s ->
+  Validator schemaStage ctx (Arguments VALID)
+validateArguments checkUnknown argsDef rawArgs = do
+  args <- ordTraverse resolve rawArgs
+  ordTraverse_ checkUnknown args
+    *> ordTraverse (validateArgument args) (arguments argsDef)
+
+class Resolve f s ctx where
+  resolve :: f s -> Validator schemaS ctx (f CONST)
+
+instance VariableConstraints ctx => Resolve Argument RAW ctx where
+  resolve (Argument key position val) = Argument key position <$> resolve val
+
+instance Resolve f CONST ctx where
+  resolve = pure
+
+instance VariableConstraints ctx => Resolve Value RAW ctx where
+  resolve Null = pure Null
+  resolve (Scalar x) = pure $ Scalar x
+  resolve (Enum x) = pure $ Enum x
+  resolve (List elems) = List <$> traverse resolve elems
+  resolve (Object fields) = Object <$> traverse resolve fields
+  resolve (VariableValue ref) =
+    askVariables
+      >>= fmap (ResolvedVariable ref)
+        . selectRequired ref
+
+instance VariableConstraints ctx => Resolve ObjectEntry RAW ctx where
+  resolve (ObjectEntry name value) = ObjectEntry name <$> resolve value
diff --git a/src/Data/Morpheus/Validation/Internal/Directive.hs b/src/Data/Morpheus/Validation/Internal/Directive.hs
--- a/src/Data/Morpheus/Validation/Internal/Directive.hs
+++ b/src/Data/Morpheus/Validation/Internal/Directive.hs
@@ -1,12 +1,16 @@
+{-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE DataKinds #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE GADTs #-}
+{-# LANGUAGE KindSignatures #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE RecordWildCards #-}
 {-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Validation.Internal.Directive
   ( shouldIncludeSelection,
@@ -14,14 +18,17 @@
   )
 where
 
--- MORPHEUS
-import Data.Morpheus.Error (errorMessage, globalErrorMessage)
+import Control.Applicative ((*>), pure)
+import Control.Monad ((>>=))
+import Data.Functor ((<$>))
+import Data.List (elem)
+import Data.Morpheus.Error.Utils
+  ( validationErrorMessage,
+  )
 import Data.Morpheus.Internal.Utils
   ( Failure (..),
-    selectBy,
     selectOr,
   )
-import Data.Morpheus.Schema.Directives (defaultDirectives)
 import Data.Morpheus.Types.Internal.AST
   ( Argument (..),
     Directive (..),
@@ -29,35 +36,61 @@
     DirectiveLocation (..),
     Directives,
     FieldName,
-    RAW,
+    Ref (..),
     ScalarValue (..),
+    Schema (..),
     VALID,
     Value (..),
     msg,
   )
 import Data.Morpheus.Types.Internal.Validation
-  ( SelectionValidator,
+  ( Validator,
+    askSchema,
     selectKnown,
+    selectRequired,
     withDirective,
   )
-import Data.Morpheus.Validation.Query.Arguments
-  ( validateDirectiveArguments,
+import Data.Morpheus.Validation.Internal.Arguments
+  ( ArgumentsConstraints,
+    validateDirectiveArguments,
   )
 import Data.Semigroup ((<>))
+import Data.Traversable (traverse)
+import Prelude
+  ( ($),
+    (&&),
+    (==),
+    Bool (..),
+    Maybe (..),
+    otherwise,
+  )
 
-validateDirective :: DirectiveLocation -> [DirectiveDefinition] -> Directive RAW -> SelectionValidator (Directive VALID)
-validateDirective location directiveDefs directive@Directive {directiveArgs, ..} =
+validateDirectives ::
+  ArgumentsConstraints ctx schemaS s =>
+  DirectiveLocation ->
+  Directives s ->
+  Validator schemaS ctx (Directives VALID)
+validateDirectives location = traverse (validate location)
+
+validate ::
+  ArgumentsConstraints c schemaS s =>
+  DirectiveLocation ->
+  Directive s ->
+  Validator schemaS c (Directive VALID)
+validate location directive@Directive {..} =
   withDirective directive $ do
-    directiveDef <- selectKnown directive directiveDefs
-    args <- validateDirectiveArguments directiveDef directiveArgs
-    validateDirectiveLocation location directive directiveDef
-    pure Directive {directiveArgs = args, ..}
+    Schema {directiveDefinitions} <- askSchema
+    directiveDef <- selectKnown directive directiveDefinitions
+    Directive directiveName directivePosition
+      <$> ( validateDirectiveLocation location directive directiveDef
+              *> validateDirectiveArguments directiveDef directiveArgs
+          )
 
 validateDirectiveLocation ::
   DirectiveLocation ->
   Directive s ->
-  DirectiveDefinition ->
-  SelectionValidator ()
+  DirectiveDefinition s' ->
+  Validator schemaS ctx ()
 validateDirectiveLocation
   loc
   Directive {directiveName, directivePosition}
@@ -65,29 +98,40 @@
     | loc `elem` directiveDefinitionLocations = pure ()
     | otherwise =
       failure $
-        errorMessage
-          directivePosition
+        validationErrorMessage
+          (Just directivePosition)
           ("Directive " <> msg directiveName <> " may not to be used on " <> msg loc)
 
-validateDirectives :: DirectiveLocation -> Directives RAW -> SelectionValidator (Directives VALID)
-validateDirectives location = traverse (validateDirective location defaultDirectives)
-
-directiveFulfilled :: Bool -> FieldName -> Directives s -> SelectionValidator Bool
+directiveFulfilled ::
+  Bool ->
+  FieldName ->
+  Directives s ->
+  Validator schemaS ctx Bool
 directiveFulfilled target = selectOr (pure True) (argumentIf target)
 
-shouldIncludeSelection :: Directives VALID -> SelectionValidator Bool
+shouldIncludeSelection ::
+  Directives VALID ->
+  Validator schemaS ctx Bool
 shouldIncludeSelection directives = do
   dontSkip <- directiveFulfilled False "skip" directives
   include <- directiveFulfilled True "include" directives
   pure (dontSkip && include)
 
-argumentIf :: Bool -> Directive s -> SelectionValidator Bool
-argumentIf target Directive {directiveName, directiveArgs} =
-  selectBy err "if" directiveArgs
+argumentIf ::
+  Bool ->
+  Directive s ->
+  Validator schemaS ctx Bool
+argumentIf target Directive {directiveArgs, directivePosition} =
+  selectRequired (Ref "if" directivePosition) directiveArgs
     >>= assertArgument target
-  where
-    err = globalErrorMessage $ "Directive " <> msg ("@" <> directiveName) <> " argument \"if\" of type \"Boolean!\" is required but not provided."
 
-assertArgument :: Bool -> Argument s -> SelectionValidator Bool
+assertArgument ::
+  Bool ->
+  Argument s ->
+  Validator schemaS ctx Bool
 assertArgument asserted Argument {argumentValue = Scalar (Boolean actual)} = pure (asserted == actual)
-assertArgument _ Argument {argumentValue} = failure $ "Expected type Boolean!, found " <> msg argumentValue <> "."
+assertArgument _ Argument {argumentValue, argumentPosition} =
+  failure
+    $ validationErrorMessage
+      (Just argumentPosition)
+    $ "Expected type Boolean!, found " <> msg argumentValue <> "."
diff --git a/src/Data/Morpheus/Validation/Internal/Value.hs b/src/Data/Morpheus/Validation/Internal/Value.hs
--- a/src/Data/Morpheus/Validation/Internal/Value.hs
+++ b/src/Data/Morpheus/Validation/Internal/Value.hs
@@ -1,29 +1,34 @@
-{-# LANGUAGE ConstraintKinds #-}
-{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE GADTs #-}
 {-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
-module Data.Morpheus.Validation.Internal.Value (validateInput) where
+module Data.Morpheus.Validation.Internal.Value
+  ( validateInputByTypeRef,
+    validateInputByType,
+    ValidateWithDefault,
+  )
+where
 
-import Data.Foldable (traverse_)
+import Control.Applicative ((*>), pure)
+import Data.Either (Either (..))
 import Data.Function ((&))
-import Data.List (elem)
-import Data.Maybe (maybe)
--- MORPHEUS
-
+import Data.Functor ((<$>), fmap)
+import Data.List (any, elem)
+import Data.Maybe (Maybe (..), maybe)
 import Data.Morpheus.Error.Input (typeViolation)
-import Data.Morpheus.Error.Utils (errorMessage)
 import Data.Morpheus.Error.Variable (incompatibleVariableType)
 import Data.Morpheus.Internal.Utils
   ( Failure (..),
-    elems,
-    fromElems,
+    ordTraverse_,
+    traverseCollection,
   )
 import Data.Morpheus.Types.Internal.AST
-  ( DataEnumValue (..),
+  ( CONST,
+    DataEnumValue (..),
     DataInputUnion,
     FieldDefinition (..),
     FieldsDefinition,
@@ -31,79 +36,92 @@
     Message,
     Object,
     ObjectEntry (..),
-    RESOLVED,
     Ref (..),
-    ResolvedValue,
     ScalarDefinition (..),
     ScalarValue (..),
-    Schema,
     TRUE,
     TypeContent (..),
     TypeDefinition (..),
     TypeName (..),
     TypeRef (..),
-    TypeRef (..),
     TypeWrapper (..),
+    Typed (..),
+    UnionMember (..),
     VALID,
     ValidValue,
     Value (..),
     Variable (..),
     Variable (..),
     VariableContent (..),
-    isNullableWrapper,
+    isNullable,
     isWeaker,
     msg,
+    msgValidation,
     toFieldName,
+    typed,
+    untyped,
+    withPosition,
   )
-import Data.Morpheus.Types.Internal.AST.OrderedMap
+import Data.Morpheus.Types.Internal.AST.OrdMap
   ( unsafeFromValues,
   )
 import Data.Morpheus.Types.Internal.Validation
-  ( GetWith,
-    InputContext,
+  ( InputContext,
     InputSource (..),
     InputValidator,
-    MissingRequired,
-    MonadContext,
-    Prop (..),
     Scope (..),
-    ScopeKind (..),
-    SetWith,
-    Unknown,
     Validator,
-    askInputFieldType,
-    askInputMember,
-    asks,
+    askType,
+    askTypeMember,
+    asksScope,
     constraintInputUnion,
+    inField,
     inputMessagePrefix,
     inputValueSource,
     selectKnown,
     selectWithDefaultValue,
-    withInputScope,
     withScopeType,
   )
 import Data.Semigroup ((<>))
+import Data.Traversable (traverse)
+import Prelude
+  ( ($),
+    (&&),
+    (.),
+    Bool (..),
+    Eq (..),
+    const,
+    fst,
+    id,
+    not,
+    otherwise,
+  )
 
-castFailure ::
-  ( GetWith ctx Schema,
-    GetWith ctx Scope
-  ) =>
-  TypeRef ->
+violation ::
   Maybe Message ->
-  ResolvedValue ->
-  InputValidator ctx a
-castFailure expected message value = do
-  pos <- asks position
+  Value s ->
+  InputValidator schemaS ctx a
+violation message value = do
+  Scope
+    { position,
+      currentTypeName,
+      currentTypeWrappers
+    } <-
+    asksScope id
   prefix <- inputMessagePrefix
   failure
-    $ errorMessage pos
-    $ prefix <> typeViolation expected value <> maybe "" (" " <>) message
+    $ withPosition position
+    $ prefix
+      <> typeViolation
+        (TypeRef currentTypeName Nothing currentTypeWrappers)
+        value
+      <> maybe "" ((" " <>) . msgValidation) message
 
 checkTypeEquality ::
   (TypeName, [TypeWrapper]) ->
   Ref ->
   Variable VALID ->
-  InputValidator ctx ValidValue
+  InputValidator schemaS ctx ValidValue
 checkTypeEquality (tyConName, tyWrappers) ref var@Variable {variableValue = ValidVariableValue value, variableType}
   | typeConName variableType == tyConName
       && not
@@ -120,202 +138,167 @@
             typeArgs = Nothing
           }
 
-type InputConstraints ctx =
-  ( GetWith ctx Schema,
-    GetWith ctx Scope,
-    GetWith (InputContext ctx) InputSource,
-    SetWith ctx Scope,
-    MissingRequired (Object RESOLVED) (InputContext ctx),
-    Unknown (FieldsDefinition IN) (InputContext ctx)
-  )
+validateInputByTypeRef ::
+  ValidateWithDefault c schemaS s =>
+  Typed IN schemaS TypeRef ->
+  Value s ->
+  Validator schemaS (InputContext c) (Value VALID)
+validateInputByTypeRef
+  ref
+  value = do
+    inputTypeDef <- askType ref
+    validateInputByType
+      (untyped typeWrappers ref)
+      inputTypeDef
+      value
 
+validateValueByField ::
+  ValidateWithDefault c schemaS s =>
+  FieldDefinition IN schemaS ->
+  Value s ->
+  Validator schemaS (InputContext c) (Value VALID)
+validateValueByField field =
+  inField field
+    . validateInputByTypeRef
+      (typed fieldType field)
+
 -- Validate input Values
-validateInput ::
-  forall ctx.
-  ( InputConstraints ctx
-  ) =>
+validateInputByType ::
+  ValidateWithDefault ctx schemaS valueS =>
   [TypeWrapper] ->
-  TypeDefinition IN ->
-  ObjectEntry RESOLVED ->
-  InputValidator ctx ValidValue
-validateInput tyWrappers TypeDefinition {typeContent = tyCont, typeName} =
-  withScopeType typeName
-    . validateWrapped tyWrappers tyCont
-  where
-    mismatchError :: [TypeWrapper] -> Maybe Message -> ResolvedValue -> InputValidator ctx ValidValue
-    mismatchError wrappers = castFailure (TypeRef typeName Nothing wrappers)
-    -- VALIDATION
-    validateWrapped ::
-      [TypeWrapper] ->
-      TypeContent TRUE IN ->
-      ObjectEntry RESOLVED ->
-      InputValidator ctx ValidValue
-    -- Validate Null. value = null ?
-    validateWrapped wrappers _ ObjectEntry {entryValue = ResolvedVariable ref variable} =
-      checkTypeEquality (typeName, wrappers) ref variable
-    validateWrapped wrappers _ ObjectEntry {entryValue = Null}
-      | isNullableWrapper wrappers = pure Null
-      | otherwise = mismatchError wrappers Nothing Null
-    -- Validate LIST
-    validateWrapped [TypeMaybe] dt ObjectEntry {entryValue} =
-      validateUnwrapped (mismatchError [TypeMaybe]) dt entryValue
-    validateWrapped (TypeMaybe : wrappers) _ value =
-      validateWrapped wrappers tyCont value
-    validateWrapped (TypeList : wrappers) _ (ObjectEntry key (List list)) =
-      List <$> traverse validateElement list
-      where
-        validateElement = validateWrapped wrappers tyCont . ObjectEntry key
-    {-- 2. VALIDATE TYPES, all wrappers are already Processed --}
-    {-- VALIDATE OBJECT--}
-    validateWrapped [] dt ObjectEntry {entryValue} =
-      validateUnwrapped (mismatchError []) dt entryValue
-    {-- 3. THROW ERROR: on invalid values --}
-    validateWrapped wrappers _ ObjectEntry {entryValue} = mismatchError wrappers Nothing entryValue
-    validateUnwrapped ::
-      -- error
-      (Maybe Message -> ResolvedValue -> InputValidator ctx ValidValue) ->
-      TypeContent TRUE IN ->
-      Value RESOLVED ->
-      InputValidator ctx ValidValue
-    validateUnwrapped _ (DataInputObject parentFields) (Object fields) =
-      Object <$> validateInputObject parentFields fields
-    validateUnwrapped _ (DataInputUnion inputUnion) (Object rawFields) =
-      validatInputUnion typeName inputUnion rawFields
-    validateUnwrapped err (DataEnum tags) value =
-      validateEnum (err Nothing) tags value
-    validateUnwrapped err (DataScalar dataScalar) value =
-      validateScalar typeName dataScalar value err
-    validateUnwrapped err _ value = err Nothing value
+  TypeDefinition IN schemaS ->
+  Value valueS ->
+  InputValidator schemaS ctx ValidValue
+validateInputByType tyWrappers typeDef =
+  withScopeType (typeDef, tyWrappers) . validateWrapped tyWrappers typeDef
 
+-- VALIDATION
+validateWrapped ::
+  ValidateWithDefault ctx schemaS valueS =>
+  [TypeWrapper] ->
+  TypeDefinition IN schemaS ->
+  Value valueS ->
+  InputValidator schemaS ctx ValidValue
+-- Validate Null. value = null ?
+validateWrapped wrappers _ (ResolvedVariable ref variable) = do
+  typeName <- asksScope currentTypeName
+  checkTypeEquality (typeName, wrappers) ref variable
+validateWrapped wrappers _ Null
+  | isNullable wrappers = pure Null
+  | otherwise = violation Nothing Null
+-- Validate LIST
+validateWrapped [TypeMaybe] TypeDefinition {typeContent} entryValue =
+  validateUnwrapped typeContent entryValue
+validateWrapped (TypeMaybe : wrappers) typeDef value =
+  validateInputByType wrappers typeDef value
+validateWrapped (TypeList : wrappers) tyCont (List list) =
+  List <$> traverse (validateInputByType wrappers tyCont) list
+{-- 2. VALIDATE TYPES, all wrappers are already Processed --}
+{-- VALIDATE OBJECT--}
+validateWrapped [] TypeDefinition {typeContent} entryValue =
+  validateUnwrapped typeContent entryValue
+{-- 3. THROW ERROR: on invalid values --}
+validateWrapped _ _ entryValue = violation Nothing entryValue
+
+validateUnwrapped ::
+  ValidateWithDefault ctx schemaS valueS =>
+  TypeContent TRUE IN schemaS ->
+  Value valueS ->
+  InputValidator schemaS ctx ValidValue
+validateUnwrapped (DataInputObject parentFields) (Object fields) =
+  Object <$> validateInputObject parentFields fields
+validateUnwrapped (DataInputUnion inputUnion) (Object rawFields) =
+  validatInputUnion inputUnion rawFields
+validateUnwrapped (DataEnum tags) value =
+  validateEnum tags value
+validateUnwrapped (DataScalar dataScalar) value =
+  validateScalar dataScalar value
+validateUnwrapped _ value = violation Nothing value
+
 -- INPUT UNION
 validatInputUnion ::
-  ( InputConstraints ctx
-  ) =>
-  TypeName ->
-  DataInputUnion ->
-  Object RESOLVED ->
-  InputValidator ctx (Value VALID)
-validatInputUnion typeName inputUnion rawFields =
+  ValidateWithDefault ctx schemaS s =>
+  DataInputUnion schemaS ->
+  Object s ->
+  InputValidator schemaS ctx (Value VALID)
+validatInputUnion inputUnion rawFields =
   case constraintInputUnion inputUnion rawFields of
-    Left message -> castFailure (TypeRef typeName Nothing []) (Just message) (Object rawFields)
-    Right (name, Nothing) -> pure (mkInputObject name [])
+    Left message -> violation (Just message) (Object rawFields)
+    Right (UnionMember {memberName}, Nothing) -> pure (mkInputObject memberName [])
     Right (name, Just value) -> validatInputUnionMember name value
 
 validatInputUnionMember ::
-  ( InputConstraints ctx
-  ) =>
-  TypeName ->
-  Value RESOLVED ->
-  InputValidator ctx (Value VALID)
-validatInputUnionMember name value = do
-  inputDef <- askInputMember name
-  validValue <-
-    validateInput
-      [TypeMaybe]
-      inputDef
-      (ObjectEntry (toFieldName name) value)
-  pure $ mkInputObject name [ObjectEntry (toFieldName name) validValue]
+  ValidateWithDefault ctx schemaS valueS =>
+  UnionMember IN schemaS ->
+  Value valueS ->
+  InputValidator schemaS ctx (Value VALID)
+validatInputUnionMember member@UnionMember {memberName} value = do
+  inputDef <- fst <$> askTypeMember member
+  validValue <- validateInputByType [TypeMaybe] inputDef value
+  pure $ mkInputObject memberName [ObjectEntry (toFieldName memberName) validValue]
 
 mkInputObject :: TypeName -> [ObjectEntry s] -> Value s
 mkInputObject name xs = Object $ unsafeFromValues $ ObjectEntry "__typename" (Enum name) : xs
 
 -- INUT Object
 validateInputObject ::
-  ( InputConstraints ctx
-  ) =>
-  FieldsDefinition IN ->
-  Object RESOLVED ->
-  InputValidator ctx (Object VALID)
+  ValidateWithDefault ctx schemaS valueS =>
+  FieldsDefinition IN schemaS ->
+  Object valueS ->
+  InputValidator schemaS ctx (Object VALID)
 validateInputObject fieldsDef object =
-  do
-    kind <- asks kind
-    case kind of
-      TYPE ->
-        traverse_ (`requiredFieldIsDefined` object) fieldsDef
-          *> traverse (`validateField` fieldsDef) object
-      _ ->
-        traverse_ (`selectKnown` fieldsDef) object
-          *> validateObjectWithDefaultValue object fieldsDef
-
-validateField ::
-  ( InputConstraints ctx
-  ) =>
-  ObjectEntry RESOLVED ->
-  FieldsDefinition IN ->
-  InputValidator ctx (ObjectEntry VALID)
-validateField entry parentFields = do
-  field <- selectKnown entry parentFields
-  validateInputField field entry
-
-validateObjectWithDefaultValue ::
-  (InputConstraints c) =>
-  Object RESOLVED ->
-  FieldsDefinition IN ->
-  Validator (InputContext c) (Object VALID)
-validateObjectWithDefaultValue object fieldsDef =
-  traverse (validateFieldWithDefaultValue object) (elems fieldsDef)
-    >>= fromElems
+  ordTraverse_ (`selectKnown` fieldsDef) object
+    *> traverseCollection (validateWithDefault object) fieldsDef
 
-validateFieldWithDefaultValue ::
-  (InputConstraints c) =>
-  Object RESOLVED ->
-  FieldDefinition IN ->
-  Validator (InputContext c) (ObjectEntry VALID)
-validateFieldWithDefaultValue object fieldDef@FieldDefinition {fieldName} = do
-  entry <- selectWithDefaultValue (ObjectEntry fieldName) fieldDef object
-  validateInputField fieldDef entry
+class ValidateWithDefault c schemaS s where
+  validateWithDefault ::
+    Object s ->
+    FieldDefinition IN schemaS ->
+    Validator schemaS (InputContext c) (ObjectEntry VALID)
 
-validateInputField ::
-  (InputConstraints c) =>
-  FieldDefinition IN ->
-  ObjectEntry RESOLVED ->
-  Validator (InputContext c) (ObjectEntry VALID)
-validateInputField fieldDef@FieldDefinition {fieldName, fieldType = TypeRef {typeConName, typeWrappers}} entry = do
-  inputTypeDef <- askInputFieldType fieldDef
-  withInputScope (Prop fieldName typeConName) $
+instance ValidateWithDefault c VALID s where
+  validateWithDefault object fieldDef@FieldDefinition {fieldName} =
     ObjectEntry fieldName
-      <$> validateInput
-        typeWrappers
-        inputTypeDef
-        entry
+      <$> selectWithDefaultValue
+        pure
+        (validateValueByField fieldDef . entryValue)
+        fieldDef
+        object
 
-requiredFieldIsDefined ::
-  ( MissingRequired (Object RESOLVED) (InputContext ctx),
-    GetWith ctx Scope
-  ) =>
-  FieldDefinition IN ->
-  Object RESOLVED ->
-  InputValidator ctx (ObjectEntry RESOLVED)
-requiredFieldIsDefined fieldDef@FieldDefinition {fieldName} =
-  selectWithDefaultValue (ObjectEntry fieldName) fieldDef
+instance ValidateWithDefault c CONST s where
+  validateWithDefault object fieldDef@FieldDefinition {fieldName} =
+    ObjectEntry fieldName
+      <$> selectWithDefaultValue
+        (validateValueByField fieldDef)
+        (validateValueByField fieldDef . entryValue)
+        fieldDef
+        object
 
 -- Leaf Validations
 validateScalar ::
-  forall m.
-  (Monad m) =>
-  TypeName ->
   ScalarDefinition ->
-  ResolvedValue ->
-  (Maybe Message -> ResolvedValue -> m ValidValue) ->
-  m ValidValue
-validateScalar typeName ScalarDefinition {validateValue} value err = do
-  scalarValue <- toScalar value
+  Value s ->
+  InputValidator schemaS ctx ValidValue
+validateScalar ScalarDefinition {validateValue} value = do
+  typeName <- asksScope currentTypeName
+  scalarValue <- toScalar typeName value
   case validateValue scalarValue of
     Right _ -> pure scalarValue
-    Left "" -> err Nothing value
-    Left message -> err (Just $ msg message) value
+    Left "" -> violation Nothing value
+    Left message -> violation (Just $ msg message) value
   where
-    toScalar :: ResolvedValue -> m ValidValue
-    toScalar (Scalar x) | isValidDefault typeName x = pure (Scalar x)
-    toScalar _ = err Nothing value
-    isValidDefault :: TypeName -> ScalarValue -> Bool
-    isValidDefault "Boolean" = isBoolean
-    isValidDefault "String" = isString
-    isValidDefault "Float" = oneOf [isFloat, isInt]
-    isValidDefault "Int" = isInt
-    isValidDefault "ID" = oneOf [isInt, isFloat, isString]
-    isValidDefault _ = const True
+    toScalar :: TypeName -> Value s -> InputValidator schemaS ctx ValidValue
+    toScalar typeName (Scalar x) | isValidDefault typeName x = pure (Scalar x)
+    toScalar _ _ = violation Nothing value
 
+isValidDefault :: TypeName -> ScalarValue -> Bool
+isValidDefault "Boolean" = isBoolean
+isValidDefault "String" = isString
+isValidDefault "Float" = oneOf [isFloat, isInt]
+isValidDefault "Int" = isInt
+isValidDefault "ID" = oneOf [isInt, isFloat, isString]
+isValidDefault _ = const True
+
 oneOf :: [a -> Bool] -> a -> Bool
 oneOf ls v = any (v &) ls
 
@@ -335,7 +318,7 @@
 isInt Int {} = True
 isInt _ = False
 
-isVariableValue :: (MonadContext m c, GetWith c InputSource) => m c Bool
+isVariableValue :: InputValidator schemaS c Bool
 isVariableValue =
   \case
     SourceVariable {isDefaultValue} -> not isDefaultValue
@@ -343,22 +326,20 @@
     <$> inputValueSource
 
 validateEnum ::
-  (MonadContext m c, GetWith c InputSource) =>
-  (ResolvedValue -> m c ValidValue) ->
-  [DataEnumValue] ->
-  ResolvedValue ->
-  m c ValidValue
-validateEnum err enumValues value@(Scalar (String enumValue))
+  [DataEnumValue s] ->
+  Value valueS ->
+  InputValidator schemaS c ValidValue
+validateEnum enumValues value@(Scalar (String enumValue))
   | TypeName enumValue `elem` tags = do
     isFromVariable <- isVariableValue
     if isFromVariable
       then pure (Enum (TypeName enumValue))
-      else err value
+      else violation Nothing value
   where
-    tags = map enumName enumValues
-validateEnum err enumValues value@(Enum enumValue)
+    tags = fmap enumName enumValues
+validateEnum enumValues value@(Enum enumValue)
   | enumValue `elem` tags = pure (Enum enumValue)
-  | otherwise = err value
+  | otherwise = violation Nothing value
   where
-    tags = map enumName enumValues
-validateEnum err _ value = err value
+    tags = fmap enumName enumValues
+validateEnum _ value = violation Nothing value
diff --git a/src/Data/Morpheus/Validation/Query/Arguments.hs b/src/Data/Morpheus/Validation/Query/Arguments.hs
deleted file mode 100644
--- a/src/Data/Morpheus/Validation/Query/Arguments.hs
+++ /dev/null
@@ -1,147 +0,0 @@
-{-# LANGUAGE GADTs #-}
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE RecordWildCards #-}
-
-module Data.Morpheus.Validation.Query.Arguments
-  ( validateDirectiveArguments,
-    validateFieldArguments,
-  )
-where
-
-import Data.Foldable (traverse_)
-import Data.Morpheus.Internal.Utils
-  ( elems,
-    empty,
-  )
-import Data.Morpheus.Types.Internal.AST
-  ( Argument (..),
-    ArgumentDefinition,
-    Arguments,
-    ArgumentsDefinition (..),
-    DirectiveDefinition,
-    DirectiveDefinition (..),
-    FieldDefinition (..),
-    OUT,
-    ObjectEntry (..),
-    RAW,
-    RESOLVED,
-    RawValue,
-    ResolvedValue,
-    TypeRef (..),
-    VALID,
-    Value (..),
-    fieldContentArgs,
-  )
-import Data.Morpheus.Types.Internal.Validation
-  ( InputSource (..),
-    Scope (..),
-    SelectionValidator,
-    askInputFieldType,
-    askVariables,
-    asks,
-    selectKnown,
-    selectRequired,
-    selectWithDefaultValue,
-    startInput,
-    withPosition,
-  )
-import Data.Morpheus.Validation.Internal.Value
-  ( validateInput,
-  )
-
--- only Resolves , doesnot checks the types
-resolveObject :: RawValue -> SelectionValidator ResolvedValue
-resolveObject = resolve
-  where
-    resolveEntry :: ObjectEntry RAW -> SelectionValidator (ObjectEntry RESOLVED)
-    resolveEntry (ObjectEntry name v) = ObjectEntry name <$> resolve v
-    ------------------------------------------------
-    resolve :: RawValue -> SelectionValidator ResolvedValue
-    resolve Null = pure Null
-    resolve (Scalar x) = pure $ Scalar x
-    resolve (Enum x) = pure $ Enum x
-    resolve (List x) = List <$> traverse resolve x
-    resolve (Object obj) = Object <$> traverse resolveEntry obj
-    resolve (VariableValue ref) =
-      askVariables
-        >>= fmap (ResolvedVariable ref)
-          . selectRequired ref
-
-resolveArgumentVariables ::
-  Arguments RAW ->
-  SelectionValidator (Arguments RESOLVED)
-resolveArgumentVariables =
-  traverse resolveVariable
-  where
-    resolveVariable :: Argument RAW -> SelectionValidator (Argument RESOLVED)
-    resolveVariable (Argument key val position) = do
-      constValue <- resolveObject val
-      pure $ Argument key constValue position
-
-validateArgument ::
-  Arguments RESOLVED ->
-  ArgumentDefinition ->
-  SelectionValidator (Argument VALID)
-validateArgument
-  requestArgs
-  argumentDef@FieldDefinition
-    { fieldName,
-      fieldType = TypeRef {typeWrappers}
-    } =
-    do
-      argumentPosition <- asks position
-      argument <-
-        selectWithDefaultValue
-          (\argumentValue -> Argument {argumentName = fieldName, argumentValue, argumentPosition})
-          argumentDef
-          requestArgs
-      validateArgumentValue argument
-    where
-      -------------------------------------------------------------------------
-      validateArgumentValue :: Argument RESOLVED -> SelectionValidator (Argument VALID)
-      validateArgumentValue arg@Argument {argumentValue = value, ..} =
-        withPosition argumentPosition
-          $ startInput (SourceArgument arg)
-          $ do
-            datatype <- askInputFieldType argumentDef
-            argumentValue <-
-              validateInput
-                typeWrappers
-                datatype
-                (ObjectEntry fieldName value)
-            pure Argument {argumentValue, ..}
-
-validateFieldArguments ::
-  FieldDefinition OUT ->
-  Arguments RAW ->
-  SelectionValidator (Arguments VALID)
-validateFieldArguments
-  fieldDef@FieldDefinition {fieldContent}
-  rawArgs =
-    do
-      args <- resolveArgumentVariables rawArgs
-      traverse_ checkUnknown (elems args)
-      traverse (validateArgument args) argsDef
-    where
-      argsDef = maybe empty fieldContentArgs fieldContent
-      -------------------------------------------------
-      checkUnknown :: Argument RESOLVED -> SelectionValidator ArgumentDefinition
-      checkUnknown = (`selectKnown` fieldDef)
-
-validateDirectiveArguments ::
-  DirectiveDefinition ->
-  Arguments RAW ->
-  SelectionValidator (Arguments VALID)
-validateDirectiveArguments
-  directiveDef@DirectiveDefinition
-    { directiveDefinitionArgs = ArgumentsDefinition _ argsDef
-    }
-  rawArgs =
-    do
-      args <- resolveArgumentVariables rawArgs
-      traverse_ checkUnknown (elems args)
-      traverse (validateArgument args) argsDef
-    where
-      -------------------------------------------------
-      checkUnknown :: Argument RESOLVED -> SelectionValidator ArgumentDefinition
-      checkUnknown = (`selectKnown` directiveDef)
diff --git a/src/Data/Morpheus/Validation/Query/Fragment.hs b/src/Data/Morpheus/Validation/Query/Fragment.hs
--- a/src/Data/Morpheus/Validation/Query/Fragment.hs
+++ b/src/Data/Morpheus/Validation/Query/Fragment.hs
@@ -1,150 +1,131 @@
+{-# LANGUAGE DataKinds #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE GADTs #-}
+{-# LANGUAGE KindSignatures #-}
 {-# LANGUAGE NamedFieldPuns #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Validation.Query.Fragment
   ( validateFragments,
     castFragmentType,
     resolveSpread,
+    validateFragment,
+    selectFragmentType,
+    ResolveFragment (..),
   )
 where
 
-import Data.Foldable (traverse_)
+import Control.Applicative ((<*>), pure)
+import Control.Monad ((>>=))
+import Data.Functor ((<$>))
+import Data.List (elem)
+import Data.Maybe (Maybe (..))
 -- MORPHEUS
 import Data.Morpheus.Error.Fragment
   ( cannotBeSpreadOnType,
-    cannotSpreadWithinItself,
   )
 import Data.Morpheus.Internal.Utils
   ( Failure (..),
-    elems,
-    selectOr,
   )
 import Data.Morpheus.Types.Internal.AST
-  ( FieldName,
+  ( Directives,
+    FieldName,
     Fragment (..),
     Fragments,
+    IMPLEMENTABLE,
     Position,
     RAW,
     Ref (..),
-    Selection (..),
-    SelectionContent (..),
+    Schema,
     SelectionSet,
+    Stage,
+    Stage,
+    TypeDefinition,
     TypeName,
     TypeNameRef (..),
+    UnionTag (..),
+    VALID,
   )
 import Data.Morpheus.Types.Internal.Validation
-  ( BaseValidator,
-    Constraint (..),
-    OperationContext,
-    Validator,
+  ( Constraint (..),
+    FragmentValidator,
     askFragments,
     askSchema,
-    checkUnused,
     constraint,
     selectKnown,
   )
-import Data.Semigroup ((<>))
+import Data.Traversable (traverse)
+import Prelude
+  ( ($),
+    otherwise,
+  )
 
-validateFragments :: SelectionSet RAW -> BaseValidator ()
-validateFragments selectionSet =
-  fragmentsCycleChecking
-    *> checkUnusedFragments selectionSet
-    *> fragmentsConditionTypeChecking
+class ResolveFragment (s :: Stage) where
+  resolveValidFragment ::
+    (Fragment RAW -> FragmentValidator s (SelectionSet VALID)) ->
+    [TypeName] ->
+    Ref ->
+    FragmentValidator s UnionTag
 
-checkUnusedFragments :: SelectionSet RAW -> BaseValidator ()
-checkUnusedFragments selectionSet = do
-  fragments <- askFragments
-  checkUnused
-    (usedFragments fragments (elems selectionSet))
-    (elems fragments)
+instance ResolveFragment VALID where
+  resolveValidFragment _ allowedTargets ref = do
+    Fragment {fragmentType, fragmentSelection} <- resolveSpread allowedTargets ref
+    pure $ UnionTag fragmentType fragmentSelection
 
+instance ResolveFragment RAW where
+  resolveValidFragment f allowedTargets ref = do
+    fragment@Fragment {fragmentType} <- resolveSpread allowedTargets ref
+    UnionTag fragmentType <$> f fragment
+
+validateFragment ::
+  (Fragment RAW -> FragmentValidator s (SelectionSet VALID)) ->
+  [TypeName] ->
+  Fragment RAW ->
+  FragmentValidator s (Fragment VALID)
+validateFragment validate allowedTypes fragment@Fragment {fragmentPosition} =
+  castFragmentType Nothing fragmentPosition allowedTypes fragment
+    >>= onlyValidateFrag validate
+
+validateFragments ::
+  (Fragment RAW -> FragmentValidator RAW (SelectionSet VALID)) ->
+  FragmentValidator RAW (Fragments VALID)
+validateFragments f = askFragments >>= traverse (onlyValidateFrag f)
+
+onlyValidateFrag ::
+  (Fragment RAW -> FragmentValidator s (SelectionSet VALID)) ->
+  Fragment RAW ->
+  FragmentValidator s (Fragment VALID)
+onlyValidateFrag validate f@Fragment {..} =
+  Fragment
+    fragmentName
+    fragmentType
+    fragmentPosition
+    <$> validate f <*> validateFragmentDirectives fragmentDirectives
+
+validateFragmentDirectives :: Directives RAW -> FragmentValidator s (Directives VALID)
+validateFragmentDirectives _ = pure [] --TODO: validate fragment directives
+
 castFragmentType ::
-  Maybe FieldName -> Position -> [TypeName] -> Fragment -> Validator ctx Fragment
+  Maybe FieldName ->
+  Position ->
+  [TypeName] ->
+  Fragment s ->
+  FragmentValidator s1 (Fragment s)
 castFragmentType key position typeMembers fragment@Fragment {fragmentType}
   | fragmentType `elem` typeMembers = pure fragment
   | otherwise = failure $ cannotBeSpreadOnType key fragmentType position typeMembers
 
-resolveSpread :: [TypeName] -> Ref -> Validator (OperationContext v) Fragment
+resolveSpread :: [TypeName] -> Ref -> FragmentValidator s (Fragment s)
 resolveSpread allowedTargets ref@Ref {refName, refPosition} =
   askFragments
     >>= selectKnown ref
     >>= castFragmentType (Just refName) refPosition allowedTargets
 
-usedFragments :: Fragments -> [Selection RAW] -> [Node]
-usedFragments fragments = concatMap findAllUses
-  where
-    findUsesSelectionContent :: SelectionContent RAW -> [Node]
-    findUsesSelectionContent (SelectionSet selectionSet) =
-      concatMap findAllUses selectionSet
-    findUsesSelectionContent SelectionField = []
-    findAllUses :: Selection RAW -> [Node]
-    findAllUses Selection {selectionContent} =
-      findUsesSelectionContent selectionContent
-    findAllUses (InlineFragment Fragment {fragmentSelection}) =
-      concatMap findAllUses fragmentSelection
-    findAllUses (Spread _ Ref {refName, refPosition}) =
-      [Ref refName refPosition] <> searchInFragment
-      where
-        searchInFragment =
-          selectOr
-            []
-            (concatMap findAllUses . fragmentSelection)
-            refName
-            fragments
-
-fragmentsConditionTypeChecking :: BaseValidator ()
-fragmentsConditionTypeChecking =
-  elems <$> askFragments
-    >>= traverse_ checkTypeExistence
-
-checkTypeExistence :: Fragment -> BaseValidator ()
-checkTypeExistence fr@Fragment {fragmentType, fragmentPosition} =
-  askSchema
-    >>= selectKnown (TypeNameRef fragmentType fragmentPosition)
-    >>= constraint OBJECT fr
-    >> pure ()
-
-fragmentsCycleChecking :: BaseValidator ()
-fragmentsCycleChecking = exploreSpreads >>= fragmentCycleChecking
-
-exploreSpreads :: BaseValidator Graph
-exploreSpreads = map exploreFragmentSpreads . elems <$> askFragments
-
-exploreFragmentSpreads :: Fragment -> NodeEdges
-exploreFragmentSpreads Fragment {fragmentName, fragmentSelection, fragmentPosition} =
-  (Ref fragmentName fragmentPosition, concatMap scanForSpread fragmentSelection)
-
-scanForSpreadContent :: SelectionContent RAW -> [Node]
-scanForSpreadContent SelectionField = []
-scanForSpreadContent (SelectionSet selectionSet) =
-  concatMap scanForSpread selectionSet
-
-scanForSpread :: Selection RAW -> [Node]
-scanForSpread Selection {selectionContent} =
-  scanForSpreadContent selectionContent
-scanForSpread (InlineFragment Fragment {fragmentSelection}) =
-  concatMap scanForSpread fragmentSelection
-scanForSpread (Spread _ Ref {refName, refPosition}) =
-  [Ref refName refPosition]
-
-type Node = Ref
-
-type NodeEdges = (Node, [Node])
-
-type Graph = [NodeEdges]
-
-fragmentCycleChecking :: Graph -> BaseValidator ()
-fragmentCycleChecking lib = traverse_ checkFragment lib
-  where
-    checkFragment (fragmentID, _) = checkForCycle lib fragmentID [fragmentID]
-
-checkForCycle :: Graph -> Node -> [Node] -> BaseValidator Graph
-checkForCycle lib parentNode history = case lookup parentNode lib of
-  Just node -> concat <$> traverse checkNode node
-  Nothing -> pure []
-  where
-    checkNode x = if x `elem` history then cycleError x else recurse x
-    recurse node = checkForCycle lib node $ history ++ [node]
-    cycleError n = failure $ cannotSpreadWithinItself (n : history)
+selectFragmentType :: Fragment RAW -> FragmentValidator s (TypeDefinition IMPLEMENTABLE VALID)
+selectFragmentType fr@Fragment {fragmentType, fragmentPosition} = do
+  (schema :: Schema VALID) <- askSchema
+  typeDef <- selectKnown (TypeNameRef fragmentType fragmentPosition) schema
+  constraint IMPLEMENTABLE fr typeDef
diff --git a/src/Data/Morpheus/Validation/Query/FragmentPreconditions.hs b/src/Data/Morpheus/Validation/Query/FragmentPreconditions.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Morpheus/Validation/Query/FragmentPreconditions.hs
@@ -0,0 +1,108 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE KindSignatures #-}
+{-# LANGUAGE NamedFieldPuns #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+module Data.Morpheus.Validation.Query.FragmentPreconditions
+  ( checkFragmentPreconditions,
+  )
+where
+
+import Control.Applicative ((*>))
+import Control.Monad ((>>=))
+import Data.Foldable (concatMap)
+import Data.Functor ((<$>), fmap)
+-- MORPHEUS
+import Data.Morpheus.Error.Fragment
+  ( cannotSpreadWithinItself,
+  )
+import Data.Morpheus.Internal.Graph
+  ( Edges,
+    Graph,
+    Node,
+    cycleChecking,
+  )
+import Data.Morpheus.Internal.Utils
+  ( Failure (..),
+    elems,
+    selectOr,
+  )
+import Data.Morpheus.Types.Internal.AST
+  ( Fragment (..),
+    Fragments,
+    RAW,
+    Ref (..),
+    Selection (..),
+    SelectionContent (..),
+    SelectionSet,
+  )
+import Data.Morpheus.Types.Internal.Validation
+  ( BaseValidator,
+    askFragments,
+    checkUnused,
+  )
+import Data.Semigroup ((<>))
+import Prelude
+  ( (.),
+  )
+
+checkUnusedFragments :: SelectionSet RAW -> BaseValidator ()
+checkUnusedFragments selectionSet = do
+  fragments <- askFragments
+  checkUnused
+    (usedFragments fragments (elems selectionSet))
+    (elems fragments)
+
+usedFragments :: Fragments RAW -> [Selection RAW] -> [Node]
+usedFragments fragments = concatMap findAllUses
+  where
+    findUsesSelectionContent :: SelectionContent RAW -> [Node]
+    findUsesSelectionContent (SelectionSet selectionSet) =
+      concatMap findAllUses selectionSet
+    findUsesSelectionContent SelectionField = []
+    findAllUses :: Selection RAW -> [Node]
+    findAllUses Selection {selectionContent} =
+      findUsesSelectionContent selectionContent
+    findAllUses (InlineFragment Fragment {fragmentSelection}) =
+      concatMap findAllUses fragmentSelection
+    findAllUses (Spread _ Ref {refName, refPosition}) =
+      [Ref refName refPosition] <> searchInFragment
+      where
+        searchInFragment =
+          selectOr
+            []
+            (concatMap findAllUses . fragmentSelection)
+            refName
+            fragments
+
+checkFragmentPreconditions :: SelectionSet RAW -> BaseValidator ()
+checkFragmentPreconditions selection =
+  (exploreSpreads >>= cycleChecking (failure . cannotSpreadWithinItself))
+    *> checkUnusedFragments selection
+
+exploreSpreads :: BaseValidator Graph
+exploreSpreads = fmap exploreFragmentSpreads . elems <$> askFragments
+
+exploreFragmentSpreads :: Fragment RAW -> Edges
+exploreFragmentSpreads Fragment {fragmentName, fragmentSelection, fragmentPosition} =
+  (Ref fragmentName fragmentPosition, concatMap scanSpread fragmentSelection)
+
+class ScanSpread a where
+  scanSpread :: a -> [Node]
+
+instance ScanSpread (Selection RAW) where
+  scanSpread Selection {selectionContent} =
+    scanSpread selectionContent
+  scanSpread (InlineFragment Fragment {fragmentSelection}) =
+    concatMap scanSpread fragmentSelection
+  scanSpread (Spread _ Ref {refName, refPosition}) =
+    [Ref refName refPosition]
+
+instance ScanSpread (SelectionContent RAW) where
+  scanSpread SelectionField = []
+  scanSpread (SelectionSet selectionSet) =
+    concatMap scanSpread selectionSet
diff --git a/src/Data/Morpheus/Validation/Query/Selection.hs b/src/Data/Morpheus/Validation/Query/Selection.hs
--- a/src/Data/Morpheus/Validation/Query/Selection.hs
+++ b/src/Data/Morpheus/Validation/Query/Selection.hs
@@ -6,14 +6,19 @@
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE RecordWildCards #-}
 {-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Validation.Query.Selection
   ( validateOperation,
+    vaidateFragmentSelection,
   )
 where
 
--- MORPHEUS
+import Control.Applicative ((<*>), pure)
+import Data.Foldable (null)
+import Data.Functor ((<$>), fmap)
+import Data.List (filter)
+import Data.Maybe (Maybe (..), maybe)
 import Data.Morpheus.Error.Selection
   ( hasNoSubfields,
     subfieldsNotSelected,
@@ -29,11 +34,11 @@
   ( Arguments,
     DirectiveLocation (FIELD, FRAGMENT_SPREAD, INLINE_FRAGMENT, MUTATION, QUERY, SUBSCRIPTION),
     Directives,
-    FieldDefinition,
+    FieldDefinition (fieldType),
     FieldName,
     FieldsDefinition,
     Fragment (..),
-    GQLError (..),
+    IMPLEMENTABLE,
     OUT,
     Operation (..),
     OperationType (..),
@@ -45,51 +50,55 @@
     TRUE,
     TypeContent (..),
     TypeDefinition (..),
-    TypeName,
+    UnionTag (..),
     VALID,
-    getOperationDataType,
+    ValidationError (..),
     isEntNode,
-    msg,
+    msgValidation,
+    possibleTypes,
+    toCategory,
+    typed,
+    withPosition,
   )
 import Data.Morpheus.Types.Internal.AST.MergeSet
   ( concatTraverse,
   )
 import Data.Morpheus.Types.Internal.Validation
-  ( SelectionValidator,
-    askFieldType,
+  ( FragmentValidator,
+    SelectionValidator,
     askSchema,
+    askType,
+    getOperationType,
     selectKnown,
     withScope,
   )
+import Data.Morpheus.Validation.Internal.Arguments
+  ( validateFieldArguments,
+  )
 import Data.Morpheus.Validation.Internal.Directive
   ( shouldIncludeSelection,
     validateDirectives,
   )
-import Data.Morpheus.Validation.Query.Arguments
-  ( validateFieldArguments,
-  )
 import Data.Morpheus.Validation.Query.Fragment
-  ( castFragmentType,
-    resolveSpread,
+  ( ResolveFragment (..),
+    resolveValidFragment,
+    selectFragmentType,
+    validateFragment,
   )
 import Data.Morpheus.Validation.Query.UnionSelection
-  ( validateUnionSelection,
+  ( validateInterfaceSelection,
+    validateUnionSelection,
   )
 import Data.Semigroup ((<>))
-
-type TypeDef = (TypeName, FieldsDefinition OUT)
-
-getOperationObject ::
-  Operation a -> SelectionValidator (TypeName, FieldsDefinition OUT)
-getOperationObject operation = do
-  dt <- askSchema >>= getOperationDataType operation
-  case dt of
-    TypeDefinition {typeContent = DataObject {objectFields}, typeName} -> pure (typeName, objectFields)
-    TypeDefinition {typeName} ->
-      failure $
-        "Type Mismatch: operation \""
-          <> msg typeName
-          <> "\" must be an Object"
+import Prelude
+  ( ($),
+    (&&),
+    (.),
+    Eq (..),
+    const,
+    not,
+    otherwise,
+  )
 
 selectionsWitoutTypename :: SelectionSet VALID -> [Selection VALID]
 selectionsWitoutTypename = filter (("__typename" /=) . keyOf) . elems
@@ -97,21 +106,18 @@
 singleTopLevelSelection :: Operation RAW -> SelectionSet VALID -> SelectionValidator ()
 singleTopLevelSelection Operation {operationType = Subscription, operationName} selSet =
   case selectionsWitoutTypename selSet of
-    (_ : xs) | not (null xs) -> failure $ map (singleTopLevelSelectionError operationName) xs
+    (_ : xs) | not (null xs) -> failure $ fmap (singleTopLevelSelectionError operationName) xs
     _ -> pure ()
 singleTopLevelSelection _ _ = pure ()
 
-singleTopLevelSelectionError :: Maybe FieldName -> Selection VALID -> GQLError
+singleTopLevelSelectionError :: Maybe FieldName -> Selection VALID -> ValidationError
 singleTopLevelSelectionError name Selection {selectionPosition} =
-  GQLError
-    { message =
-        subscriptionName
-          <> " must select "
-          <> "only one top level field.",
-      locations = [selectionPosition]
-    }
+  withPosition (Just selectionPosition) $
+    subscriptionName
+      <> " must select "
+      <> "only one top level field."
   where
-    subscriptionName = maybe "Anonymous Subscription" (("Subscription " <>) . msg) name
+    subscriptionName = maybe "Anonymous Subscription" (("Subscription " <>) . msgValidation) name
 
 validateOperation ::
   Operation RAW ->
@@ -125,8 +131,8 @@
       ..
     } =
     do
-      typeDef <- getOperationObject rawOperation
-      selection <- validateSelectionSet typeDef operationSelection
+      typeDef <- getOperationType rawOperation
+      selection <- validateSelectionSet (toCategory typeDef) operationSelection
       singleTopLevelSelection rawOperation selection
       directives <-
         validateDirectives
@@ -150,8 +156,8 @@
 processSelectionDirectives ::
   DirectiveLocation ->
   Directives RAW ->
-  (Directives VALID -> SelectionValidator (SelectionSet VALID)) ->
-  SelectionValidator (SelectionSet VALID)
+  (Directives VALID -> FragmentValidator s (SelectionSet VALID)) ->
+  FragmentValidator s (SelectionSet VALID)
 processSelectionDirectives location rawDirectives sel = do
   directives <- validateDirectives location rawDirectives
   include <- shouldIncludeSelection directives
@@ -161,13 +167,27 @@
       then selection
       else empty
 
+vaidateFragmentSelection :: (ResolveFragment s) => Fragment RAW -> FragmentValidator s (SelectionSet VALID)
+vaidateFragmentSelection f@Fragment {fragmentSelection} = do
+  typeDef <- selectFragmentType f
+  validateSelectionSet typeDef fragmentSelection
+
+getFields :: TypeDefinition IMPLEMENTABLE s -> FieldsDefinition OUT s
+getFields TypeDefinition {typeContent = DataObject {objectFields}} = objectFields
+getFields TypeDefinition {typeContent = DataInterface fields} = fields
+
 validateSelectionSet ::
-  TypeDef -> SelectionSet RAW -> SelectionValidator (SelectionSet VALID)
-validateSelectionSet dataType@(typeName, fieldsDef) =
+  forall s.
+  ( ResolveFragment s
+  ) =>
+  TypeDefinition IMPLEMENTABLE VALID ->
+  SelectionSet RAW ->
+  FragmentValidator s (SelectionSet VALID)
+validateSelectionSet typeDef =
   concatTraverse validateSelection
   where
     -- validate single selection: InlineFragments and Spreads will Be resolved and included in SelectionSet
-    validateSelection :: Selection RAW -> SelectionValidator (SelectionSet VALID)
+    validateSelection :: Selection RAW -> FragmentValidator s (SelectionSet VALID)
     validateSelection
       sel@Selection
         { selectionName,
@@ -177,7 +197,7 @@
           selectionDirectives
         } =
         withScope
-          typeName
+          typeDef
           currentSelectionRef
           $ processSelectionDirectives
             FIELD
@@ -185,19 +205,14 @@
             (`validateSelectionContent` selectionContent)
         where
           currentSelectionRef = Ref selectionName selectionPosition
-          commonValidation :: SelectionValidator (TypeDefinition OUT, Arguments VALID)
+          commonValidation :: FragmentValidator s (TypeDefinition OUT VALID, Arguments VALID)
           commonValidation = do
-            (fieldDef :: FieldDefinition OUT) <- selectKnown (Ref selectionName selectionPosition) fieldsDef
-            -- validate field Argument -----
-            arguments <-
-              validateFieldArguments
-                fieldDef
-                selectionArguments
-            -- check field Type existence  -----
-            (typeDef :: TypeDefinition OUT) <- askFieldType fieldDef
-            pure (typeDef, arguments)
+            fieldDef <- selectKnown (Ref selectionName selectionPosition) (getFields typeDef)
+            (,)
+              <$> askType (typed fieldType fieldDef)
+              <*> validateFieldArguments fieldDef selectionArguments
           -----------------------------------------------------------------------------------
-          validateSelectionContent :: Directives VALID -> SelectionContent RAW -> SelectionValidator (SelectionSet VALID)
+          validateSelectionContent :: Directives VALID -> SelectionContent RAW -> FragmentValidator s (SelectionSet VALID)
           validateSelectionContent directives SelectionField
             | null selectionArguments && selectionName == "__typename" =
               pure $ singleton $
@@ -208,73 +223,90 @@
                   }
             | otherwise = do
               (datatype, validArgs) <- commonValidation
-              isLeaf datatype
-              pure $ singleton $
-                sel
-                  { selectionArguments = validArgs,
-                    selectionDirectives = directives,
-                    selectionContent = SelectionField
-                  }
-            where
-              ------------------------------------------------------------
-              isLeaf :: TypeDefinition OUT -> SelectionValidator ()
-              isLeaf TypeDefinition {typeName = typename, typeContent}
-                | isEntNode typeContent = pure ()
-                | otherwise =
-                  failure $
-                    subfieldsNotSelected selectionName typename selectionPosition
+              selContent <-
+                validateContentLeaf currentSelectionRef datatype
+              pure $
+                singleton
+                  ( sel
+                      { selectionArguments = validArgs,
+                        selectionDirectives = directives,
+                        selectionContent = selContent
+                      }
+                  )
           ----- SelectionSet
           validateSelectionContent directives (SelectionSet rawSelectionSet) =
             do
-              (TypeDefinition {typeName = name, typeContent}, validArgs) <- commonValidation
-              selContent <- withScope name currentSelectionRef $ validateByTypeContent name typeContent
+              (tyDef, validArgs) <- commonValidation
+              selContent <- validateByTypeContent tyDef currentSelectionRef rawSelectionSet
               pure $ singleton $
                 sel
                   { selectionArguments = validArgs,
                     selectionDirectives = directives,
                     selectionContent = selContent
                   }
-            where
-              validateByTypeContent :: TypeName -> TypeContent TRUE OUT -> SelectionValidator (SelectionContent VALID)
-              -- Validate UnionSelection
-              validateByTypeContent _ DataUnion {unionMembers} =
-                validateUnionSelection
-                  validateSelectionSet
-                  rawSelectionSet
-                  unionMembers
-              -- Validate Regular selection set
-              validateByTypeContent typename DataObject {objectFields} =
-                SelectionSet
-                  <$> validateSelectionSet
-                    (typename, objectFields)
-                    rawSelectionSet
-              validateByTypeContent typename DataInterface {interfaceFields} =
-                SelectionSet
-                  <$> validateSelectionSet
-                    (typename, interfaceFields)
-                    rawSelectionSet
-              validateByTypeContent typename _ =
-                failure $
-                  hasNoSubfields
-                    (Ref selectionName selectionPosition)
-                    typename
-    validateSelection (Spread dirs ref) =
-      processSelectionDirectives FRAGMENT_SPREAD dirs
-        $ const
-        -- TODO: add directives to selection
-        $ resolveSpread [typeName] ref
-          >>= validateFragment
+    validateSelection (Spread dirs ref) = do
+      types <- possibleTypes typeDef <$> askSchema
+      processSelectionDirectives
+        FRAGMENT_SPREAD
+        dirs
+        (const $ unionTagSelection <$> resolveValidFragment vaidateFragmentSelection types ref)
     validateSelection
       ( InlineFragment
           fragment@Fragment
-            { fragmentDirectives,
-              fragmentPosition
+            { fragmentDirectives
             }
-        ) =
-        processSelectionDirectives INLINE_FRAGMENT fragmentDirectives
-          $ const
-          -- TODO: add directives to selection
-          $ castFragmentType Nothing fragmentPosition [typeName] fragment
-            >>= validateFragment
-    --------------------------------------------------------------------------------
-    validateFragment Fragment {fragmentSelection} = validateSelectionSet dataType fragmentSelection
+        ) = do
+        types <- possibleTypes typeDef <$> askSchema
+        processSelectionDirectives INLINE_FRAGMENT fragmentDirectives $
+          const (validate types fragment)
+    validate types = fmap fragmentSelection . validateFragment vaidateFragmentSelection types
+
+validateContentLeaf ::
+  Ref ->
+  TypeDefinition OUT VALID ->
+  FragmentValidator s' (SelectionContent s)
+validateContentLeaf
+  (Ref selectionName selectionPosition)
+  TypeDefinition {typeName, typeContent}
+    | isEntNode typeContent = pure SelectionField
+    | otherwise =
+      failure $ subfieldsNotSelected selectionName typeName selectionPosition
+
+validateByTypeContent ::
+  forall s.
+  (ResolveFragment s) =>
+  TypeDefinition OUT VALID ->
+  Ref ->
+  SelectionSet RAW ->
+  FragmentValidator s (SelectionContent VALID)
+validateByTypeContent
+  typeDef@TypeDefinition {typeContent, ..}
+  currentSelectionRef =
+    withScope typeDef currentSelectionRef
+      . __validate typeContent
+    where
+      __validate ::
+        TypeContent TRUE OUT VALID ->
+        SelectionSet RAW ->
+        FragmentValidator s (SelectionContent VALID)
+      -- Validate UnionSelection
+      __validate DataUnion {unionMembers} =
+        validateUnionSelection
+          vaidateFragmentSelection
+          validateSelectionSet
+          unionMembers
+      -- Validate Regular selection set
+      __validate DataObject {..} =
+        fmap SelectionSet . validateSelectionSet (TypeDefinition {typeContent = DataObject {..}, ..})
+      -- TODO: Union Like Validation
+      __validate DataInterface {..} =
+        validateInterfaceSelection
+          vaidateFragmentSelection
+          validateSelectionSet
+          (TypeDefinition {typeContent = DataInterface {..}, ..})
+      __validate _ =
+        const
+          $ failure
+          $ hasNoSubfields
+            currentSelectionRef
+            typeDef
diff --git a/src/Data/Morpheus/Validation/Query/UnionSelection.hs b/src/Data/Morpheus/Validation/Query/UnionSelection.hs
--- a/src/Data/Morpheus/Validation/Query/UnionSelection.hs
+++ b/src/Data/Morpheus/Validation/Query/UnionSelection.hs
@@ -3,94 +3,119 @@
 {-# LANGUAGE GADTs #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE TupleSections #-}
 
 module Data.Morpheus.Validation.Query.UnionSelection
   ( validateUnionSelection,
+    validateInterfaceSelection,
   )
 where
 
 import Control.Monad ((>=>))
+import Data.Maybe (isJust)
 -- MORPHEUS
-import Data.Morpheus.Error.Selection (unknownSelectionField)
 import Data.Morpheus.Internal.Utils
-  ( Failure (..),
-    elems,
+  ( elems,
     empty,
     fromElems,
-    selectOr,
-    singleton,
   )
 import Data.Morpheus.Types.Internal.AST
   ( DataUnion,
-    FieldsDefinition,
     Fragment (..),
-    OUT,
+    IMPLEMENTABLE,
     RAW,
-    Ref (..),
     Selection (..),
     SelectionContent (..),
     SelectionSet,
     SelectionSet,
+    TypeContent (..),
+    TypeDefinition (..),
     TypeName,
-    UnionMember (..),
     UnionTag (..),
     VALID,
+    mkType,
+    toCategory,
   )
 import qualified Data.Morpheus.Types.Internal.AST.MergeSet as MS
   ( join,
   )
 import Data.Morpheus.Types.Internal.Validation
-  ( Scope (..),
-    SelectionValidator,
+  ( FragmentValidator,
+    Scope (..),
+    askInterfaceTypes,
     askTypeMember,
-    asks,
+    asksScope,
   )
 import Data.Morpheus.Validation.Query.Fragment
-  ( castFragmentType,
-    resolveSpread,
+  ( ResolveFragment (resolveValidFragment),
+    castFragmentType,
   )
 
-type TypeDef = (TypeName, FieldsDefinition OUT)
-
--- returns all Fragments used in Union
-exploreUnionFragments ::
-  [UnionMember OUT] ->
+-- returns all Fragments used for Possible Types
+splitFragment ::
+  (ResolveFragment s) =>
+  ( Fragment RAW ->
+    FragmentValidator s (SelectionSet VALID)
+  ) ->
+  [TypeDefinition IMPLEMENTABLE VALID] ->
   Selection RAW ->
-  SelectionValidator [Fragment]
-exploreUnionFragments unionTags = splitFrag
-  where
-    packFragment fragment = [fragment]
-    splitFrag ::
-      Selection RAW -> SelectionValidator [Fragment]
-    splitFrag (Spread _ ref) = packFragment <$> resolveSpread (map memberName unionTags) ref
-    splitFrag Selection {selectionName = "__typename", selectionContent = SelectionField} = pure []
-    splitFrag Selection {selectionName, selectionPosition} = do
-      typeName <- asks typename
-      failure $ unknownSelectionField typeName (Ref selectionName selectionPosition)
-    splitFrag (InlineFragment fragment) =
-      packFragment
-        <$> castFragmentType Nothing (fragmentPosition fragment) (map memberName unionTags) fragment
+  FragmentValidator s ([UnionTag], [Selection RAW])
+splitFragment _ _ x@Selection {} = pure ([], [x])
+splitFragment f types (Spread _ ref) = pureFirst <$> resolveValidFragment f (typeName <$> types) ref
+splitFragment f types (InlineFragment fragment@Fragment {fragmentType}) =
+  pureFirst . UnionTag fragmentType
+    <$> ( castFragmentType Nothing (fragmentPosition fragment) (typeName <$> types) fragment
+            >>= f
+        )
 
+pureFirst :: a1 -> ([a1], [a2])
+pureFirst x = ([x], [])
+
+joinExploredSelection :: [([UnionTag], [Selection RAW])] -> FragmentValidator s ([UnionTag], SelectionSet RAW)
+joinExploredSelection i = do
+  let (x, y) = unzip i
+  let x' = concat x
+  let y' = concat y
+  (x',) <$> fromElems y'
+
+exploreFragments ::
+  (ResolveFragment s) =>
+  ( Fragment RAW ->
+    FragmentValidator s (SelectionSet VALID)
+  ) ->
+  [TypeDefinition IMPLEMENTABLE VALID] ->
+  SelectionSet RAW ->
+  FragmentValidator s ([UnionTag], SelectionSet RAW)
+exploreFragments validateFragment types selectionSet =
+  traverse (splitFragment validateFragment types) (elems selectionSet)
+    >>= joinExploredSelection
+
 -- sorts Fragment by contitional Types
 -- [
 --   ( Type for Tag User , [ Fragment for User] )
 --   ( Type for Tag Product , [ Fragment for Product] )
 -- ]
 tagUnionFragments ::
-  [TypeDef] -> [Fragment] -> [(TypeDef, [Fragment])]
+  [TypeDefinition IMPLEMENTABLE VALID] ->
+  [UnionTag] ->
+  [(TypeName, [SelectionSet VALID])]
 tagUnionFragments types fragments =
-  filter notEmpty $
-    map categorizeType types
+  filter notEmpty (map categorizeType types)
   where
     notEmpty = not . null . snd
-    categorizeType :: (TypeName, FieldsDefinition OUT) -> (TypeDef, [Fragment])
-    categorizeType datatype = (datatype, filter matches fragments)
+    categorizeType ::
+      TypeDefinition IMPLEMENTABLE VALID ->
+      (TypeName, [SelectionSet VALID])
+    categorizeType datatype = (typeName datatype, unionTagSelection <$> filter matches fragments)
       where
-        matches fragment = fragmentType fragment == fst datatype
+        matches = (`elem` subTypes datatype) . unionTagName
 
+subTypes :: TypeDefinition a s -> [TypeName]
+subTypes TypeDefinition {typeName, typeContent = DataObject {objectImplements}} =
+  typeName : objectImplements
+subTypes TypeDefinition {typeName} = [typeName]
+
 {-
     - all Variable and Fragment references will be: resolved and validated
     - unionTypes: will be clustered under type names
@@ -102,29 +127,58 @@
           UnionTag "T2" {<SelectionB>,<SelectionC>}
       ]
  -}
-validateCluster ::
-  (TypeDef -> SelectionSet RAW -> SelectionValidator (SelectionSet VALID)) ->
-  SelectionSet RAW ->
-  [(TypeDef, [Fragment])] ->
-  SelectionValidator (SelectionContent VALID)
-validateCluster validator __typename = traverse _validateCluster >=> fmap UnionSelection . fromElems
+joinClusters ::
+  forall s.
+  SelectionSet VALID ->
+  [(TypeName, [SelectionSet VALID])] ->
+  FragmentValidator s (SelectionContent VALID)
+joinClusters selSet =
+  traverse joinCluster
+    >=> fmap UnionSelection . fromElems
   where
-    _validateCluster :: (TypeDef, [Fragment]) -> SelectionValidator UnionTag
-    _validateCluster (unionType, fragmets) = do
-      fragmentSelections <- MS.join (__typename : map fragmentSelection fragmets)
-      UnionTag (fst unionType) <$> validator unionType fragmentSelections
+    joinCluster (typeName, fragmets) = UnionTag typeName <$> MS.join (selSet : fragmets)
 
+validateInterfaceSelection ::
+  ResolveFragment s =>
+  (Fragment RAW -> FragmentValidator s (SelectionSet VALID)) ->
+  (TypeDefinition IMPLEMENTABLE VALID -> SelectionSet RAW -> FragmentValidator s (SelectionSet VALID)) ->
+  TypeDefinition IMPLEMENTABLE VALID ->
+  SelectionSet RAW ->
+  FragmentValidator s (SelectionContent VALID)
+validateInterfaceSelection
+  validateFragment
+  validate
+  typeDef
+  inputSelectionSet = do
+    possibleTypes <- askInterfaceTypes typeDef
+    (spreads, selectionSet) <- exploreFragments validateFragment possibleTypes inputSelectionSet
+    validSelectionSet <- validate typeDef selectionSet
+    let categories = tagUnionFragments possibleTypes spreads
+    if null categories
+      then pure (SelectionSet validSelectionSet)
+      else joinClusters validSelectionSet (insertDefault (typeName typeDef) categories)
+
+insertDefault :: TypeName -> [(TypeName, [a])] -> [(TypeName, [a])]
+insertDefault interfaceName categories
+  | isJust (lookup interfaceName categories) = categories
+  | otherwise = (interfaceName, []) : categories
+
+mkUnionRootType :: FragmentValidator s (TypeDefinition IMPLEMENTABLE VALID)
+mkUnionRootType = (`mkType` DataObject [] empty) <$> asksScope currentTypeName
+
 validateUnionSelection ::
-  (TypeDef -> SelectionSet RAW -> SelectionValidator (SelectionSet VALID)) ->
+  ResolveFragment s =>
+  (Fragment RAW -> FragmentValidator s (SelectionSet VALID)) ->
+  (TypeDefinition IMPLEMENTABLE VALID -> SelectionSet RAW -> FragmentValidator s (SelectionSet VALID)) ->
+  DataUnion VALID ->
   SelectionSet RAW ->
-  DataUnion ->
-  SelectionValidator (SelectionContent VALID)
-validateUnionSelection validate selectionSet members = do
-  let (__typename :: SelectionSet RAW) = selectOr empty singleton "__typename" selectionSet
+  FragmentValidator s (SelectionContent VALID)
+validateUnionSelection validateFragment validate members selectionSet = do
   -- get union Types defined in GraphQL schema -> (union Tag, union Selection set)
   -- [("User", FieldsDefinition { ... }), ("Product", FieldsDefinition { ...
-  unionTypes <- traverse askTypeMember members
+  unionTypes <- traverse (fmap toCategory . askTypeMember) members
   -- find all Fragments used in Selection
-  spreads <- concat <$> traverse (exploreUnionFragments members) (elems selectionSet)
-  let categories = tagUnionFragments unionTypes spreads
-  validateCluster validate __typename categories
+  (spreads, selSet) <- exploreFragments validateFragment unionTypes selectionSet
+  typeDef <- mkUnionRootType
+  validSelection <- validate typeDef selSet
+  joinClusters validSelection (tagUnionFragments unionTypes spreads)
diff --git a/src/Data/Morpheus/Validation/Query/Validation.hs b/src/Data/Morpheus/Validation/Query/Validation.hs
--- a/src/Data/Morpheus/Validation/Query/Validation.hs
+++ b/src/Data/Morpheus/Validation/Query/Validation.hs
@@ -3,7 +3,6 @@
 {-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE TypeOperators #-}
 
 module Data.Morpheus.Validation.Query.Validation
   ( validateRequest,
@@ -11,13 +10,15 @@
 where
 
 import Data.HashMap.Lazy (fromList)
+import Data.Morpheus.Internal.Utils (empty)
 import Data.Morpheus.Types.Internal.AST
   ( GQLQuery (..),
     Operation (..),
     Schema (..),
+    TypeKind (..),
     VALID,
-    VALIDATION_MODE,
   )
+import Data.Morpheus.Types.Internal.Config (Config (..))
 import Data.Morpheus.Types.Internal.Resolving
   ( Eventless,
   )
@@ -31,21 +32,25 @@
 import Data.Morpheus.Validation.Query.Fragment
   ( validateFragments,
   )
+import Data.Morpheus.Validation.Query.FragmentPreconditions
+  ( checkFragmentPreconditions,
+  )
 import Data.Morpheus.Validation.Query.Selection
-  ( validateOperation,
+  ( vaidateFragmentSelection,
+    validateOperation,
   )
 import Data.Morpheus.Validation.Query.Variable
   ( resolveOperationVariables,
   )
 
 validateRequest ::
-  Schema ->
-  VALIDATION_MODE ->
+  Config ->
+  Schema VALID ->
   GQLQuery ->
   Eventless (Operation VALID)
 validateRequest
+  config
   schema
-  validationMode
   GQLQuery
     { fragments,
       inputVariables,
@@ -57,20 +62,55 @@
           }
     } =
     do
-      variables <- runValidator validateHelpers (ctx ())
-      runValidator (validateOperation operation) (ctx variables)
+      variables <-
+        runValidator
+          validateHelpers
+          config
+          schema
+          scope
+          ( OperationContext
+              { selection,
+                fragments,
+                variables = empty
+              }
+          )
+      validFragments <-
+        runValidator
+          (validateFragments vaidateFragmentSelection)
+          config
+          schema
+          scope
+          ( OperationContext
+              { selection,
+                fragments,
+                variables
+              }
+          )
+      runValidator
+        (validateOperation operation)
+        config
+        schema
+        scope
+        ( OperationContext
+            { selection,
+              fragments = validFragments,
+              variables
+            }
+        )
     where
-      ctx variables =
-        OperationContext
-          { schema,
-            fragments,
-            scope = Scope {typename = "Root", position = operationPosition, kind = SELECTION},
-            selection = CurrentSelection {operationName, selectionName = "Root"},
-            variables
+      scope =
+        Scope
+          { kind = SELECTION,
+            currentTypeName = "Root",
+            currentTypeKind = KindObject Nothing,
+            currentTypeWrappers = [],
+            fieldname = "Root",
+            position = Just operationPosition
           }
+      selection = CurrentSelection {operationName}
       validateHelpers =
-        validateFragments operationSelection
+        checkFragmentPreconditions operationSelection
           *> resolveOperationVariables
+            config
             (fromList inputVariables)
-            validationMode
             operation
diff --git a/src/Data/Morpheus/Validation/Query/Variable.hs b/src/Data/Morpheus/Validation/Query/Variable.hs
--- a/src/Data/Morpheus/Validation/Query/Variable.hs
+++ b/src/Data/Morpheus/Validation/Query/Variable.hs
@@ -2,17 +2,21 @@
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE GADTs #-}
 {-# LANGUAGE NamedFieldPuns #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Data.Morpheus.Validation.Query.Variable
   ( resolveOperationVariables,
   )
 where
 
+import Control.Applicative ((*>), pure)
+import Control.Monad (Monad ((>>=)))
+import Data.Foldable (concat, concatMap)
+import Data.Functor ((<$>), fmap)
 import qualified Data.HashMap.Lazy as M
   ( lookup,
   )
-import Data.Maybe (maybe)
---- MORPHEUS
+import Data.Maybe (Maybe (..), maybe)
 import Data.Morpheus.Error.Variable (uninitializedVariable)
 import Data.Morpheus.Internal.Utils
   ( Failure (..),
@@ -37,7 +41,6 @@
     TypeNameRef (..),
     TypeRef (..),
     VALID,
-    VALIDATION_MODE (..),
     ValidValue,
     Value (..),
     Variable (..),
@@ -46,6 +49,10 @@
     Variables,
     isNullable,
   )
+import Data.Morpheus.Types.Internal.Config
+  ( Config (..),
+    VALIDATION_MODE (..),
+  )
 import Data.Morpheus.Types.Internal.Validation
   ( BaseValidator,
     Constraint (..),
@@ -59,9 +66,21 @@
     withPosition,
   )
 import Data.Morpheus.Validation.Internal.Value
-  ( validateInput,
+  ( validateInputByType,
   )
 import Data.Semigroup ((<>))
+import Data.Traversable
+  ( traverse,
+  )
+import Prelude
+  ( ($),
+    (&&),
+    (.),
+    Bool (..),
+    Eq (..),
+    not,
+    otherwise,
+  )
 
 class ExploreRefs a where
   exploreRefs :: a -> [Ref]
@@ -105,13 +124,13 @@
             )
 
 resolveOperationVariables ::
+  Config ->
   Variables ->
-  VALIDATION_MODE ->
   Operation RAW ->
   BaseValidator (VariableDefinitions VALID)
 resolveOperationVariables
+  Config {validationMode}
   root
-  validationMode
   Operation
     { operationSelection,
       operationArguments
@@ -134,14 +153,14 @@
   validationMode
   var@Variable
     { variableName,
-      variableType,
+      variableType = variableType@TypeRef {typeWrappers, typeConName},
       variablePosition,
       variableValue = DefaultValue defaultValue
     } =
     withPosition variablePosition $
       toVariable
         <$> ( askSchema
-                >>= selectKnown (TypeNameRef (typeConName variableType) variablePosition)
+                >>= selectKnown (TypeNameRef typeConName variablePosition)
                 >>= constraint INPUT var
                 >>= checkType getVariable defaultValue
             )
@@ -154,11 +173,11 @@
       checkType ::
         Maybe ResolvedValue ->
         DefaultValue ->
-        TypeDefinition IN ->
+        TypeDefinition IN VALID ->
         BaseValidator ValidValue
       checkType (Just variable) Nothing varType = validator varType False variable
       checkType (Just variable) (Just defValue) varType =
-        validator varType True defValue >> validator varType False variable
+        validator varType True defValue *> validator varType False variable
       checkType Nothing (Just defValue) varType = validator varType True defValue
       checkType Nothing Nothing varType
         | validationMode /= WITHOUT_VARIABLES && not (isNullable variableType) =
@@ -169,10 +188,12 @@
           returnNull =
             maybe (pure Null) (validator varType False) (M.lookup variableName bodyVariables)
       -----------------------------------------------------------------------------------------------
-      validator :: TypeDefinition IN -> Bool -> ResolvedValue -> BaseValidator ValidValue
-      validator varType isDefaultValue varValue =
-        startInput (SourceVariable var isDefaultValue) $
-          validateInput
-            (typeWrappers variableType)
-            varType
-            (ObjectEntry variableName varValue)
+      validator :: TypeDefinition IN VALID -> Bool -> ResolvedValue -> BaseValidator ValidValue
+      validator varTypeDef isDefaultValue varValue =
+        startInput
+          (SourceVariable var isDefaultValue)
+          ( validateInputByType
+              typeWrappers
+              varTypeDef
+              varValue
+          )
diff --git a/test/Lib.hs b/test/Lib.hs
--- a/test/Lib.hs
+++ b/test/Lib.hs
@@ -1,9 +1,12 @@
+{-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Lib
   ( getGQLBody,
-    getResponseBody,
+    expectedResponse,
     getCases,
     maybeVariables,
     readSource,
@@ -11,30 +14,69 @@
     FileUrl (..),
     CaseTree (..),
     toString,
+    getRequest,
+    assertValidSchema,
+    getSchema,
+    getResolvers,
   )
 where
 
-import Control.Applicative ((<|>))
+import Control.Applicative ((<|>), pure)
+import Control.Monad ((>=>), Monad)
 import Data.Aeson (FromJSON, Value (..), decode)
 import qualified Data.ByteString.Lazy as L (readFile)
 import Data.ByteString.Lazy.Char8 (ByteString)
-import Data.Maybe (fromMaybe)
-import Data.Morpheus.Types.Internal.AST (FieldName (..))
+import Data.Either (Either (..))
+import Data.Foldable (foldl)
+import Data.Functor ((<$>))
+import Data.HashMap.Lazy (lookup)
+import Data.Maybe (Maybe (..), fromMaybe, maybe)
+import Data.Morpheus.Core (parseGQLDocument)
+import Data.Morpheus.Types.IO
+  ( GQLRequest (..),
+  )
+import Data.Morpheus.Types.Internal.AST (FieldName (..), Schema (..), VALID)
+import Data.Morpheus.Types.Internal.Resolving
+  ( Eventless,
+    ResModel,
+    RootResModel (..),
+    WithOperation,
+    mkNull,
+    mkValue,
+    resultOr,
+  )
 import Data.Semigroup ((<>))
 import Data.Text (Text, unpack)
+import qualified Data.Text.Lazy as LT (toStrict)
+import Data.Text.Lazy.Encoding (decodeUtf8)
+import Data.Traversable (traverse)
 import System.Directory (doesDirectoryExist, listDirectory)
+import Test.Tasty.HUnit
+  ( assertFailure,
+  )
+import Prelude
+  ( ($),
+    (.),
+    Bool,
+    FilePath,
+    IO,
+    Show,
+    and,
+    map,
+    show,
+  )
 
 readSource :: FieldName -> IO ByteString
 readSource = L.readFile . path . readName
 
-path :: Text -> String
-path name = "test/" ++ unpack name
+path :: Text -> FilePath
+path name = "test/" <> unpack name
 
-gqlLib :: Text -> String
-gqlLib x = path x ++ "/query.gql"
+gqlLib :: Text -> FilePath
+gqlLib x = path x <> "/query.gql"
 
-resLib :: Text -> String
-resLib x = path x ++ "/response.json"
+resLib :: Text -> FilePath
+resLib x = path x <> "/response.json"
 
 data FileUrl = FileUrl
   { filePath :: [FilePath],
@@ -44,7 +86,7 @@
 
 data CaseTree = CaseTree
   { caseUrl :: FileUrl,
-    children :: Either [String] [CaseTree]
+    children :: Either [FilePath] [CaseTree]
   }
   deriving (Show)
 
@@ -65,12 +107,12 @@
 deepScan = shouldScan . FileUrl []
   where
     shouldScan :: FileUrl -> IO CaseTree
-    shouldScan caseUrl@FileUrl {..} = do
+    shouldScan caseUrl = do
       children <- prefixed caseUrl
       pure CaseTree {..}
     isDirectory :: FileUrl -> IO Bool
     isDirectory = doesDirectoryExist . toString
-    prefixed :: FileUrl -> IO (Either [String] [CaseTree])
+    prefixed :: FileUrl -> IO (Either [FilePath] [CaseTree])
     prefixed p = do
       dir <- isDirectory p
       if dir
@@ -83,13 +125,53 @@
         else pure $ Left []
 
 maybeVariables :: FieldName -> IO (Maybe Value)
-maybeVariables (FieldName x) = decode <$> (L.readFile (path x ++ "/variables.json") <|> return "{}")
+maybeVariables (FieldName x) = decode <$> (L.readFile (path x <> "/variables.json") <|> pure "{}")
 
 getGQLBody :: FieldName -> IO ByteString
 getGQLBody (FieldName p) = L.readFile (gqlLib p)
 
-getCases :: FromJSON a => String -> IO [a]
-getCases dir = fromMaybe [] . decode <$> L.readFile ("test/" ++ dir ++ "/cases.json")
+getCases :: FromJSON a => FilePath -> IO [a]
+getCases dir = fromMaybe [] . decode <$> L.readFile ("test/" <> dir <> "/cases.json")
 
-getResponseBody :: FieldName -> IO Value
-getResponseBody (FieldName p) = fromMaybe Null . decode <$> L.readFile (resLib p)
+getSchema :: FieldName -> IO (Eventless (Schema VALID))
+getSchema (FieldName x) = parseGQLDocument <$> L.readFile (path x <> "/schema.gql")
+
+assertValidSchema :: FieldName -> IO (Schema VALID)
+assertValidSchema = getSchema >=> resultOr failedSchema pure
+  where
+    failedSchema err = assertFailure ("unexpected schema validation error: \n " <> show err)
+
+expectedResponse :: FieldName -> IO Value
+expectedResponse (FieldName p) = fromMaybe Null . decode <$> L.readFile (resLib p)
+
+getRequest :: FieldName -> IO GQLRequest
+getRequest p = do
+  queryBS <- LT.toStrict . decodeUtf8 <$> getGQLBody p
+  variables <- maybeVariables p
+  pure $
+    GQLRequest
+      { operationName = Nothing,
+        query = queryBS,
+        variables
+      }
+
+getResolvers :: Monad m => FieldName -> IO (RootResModel e m)
+getResolvers (FieldName p) = do
+  res <- fromMaybe Null . decode <$> L.readFile (path p <> "/resolvers.json")
+  pure
+    RootResModel
+      { query = pure (lookupRes "query" res),
+        mutation = pure (lookupRes "mutation" res),
+        subscription = pure (lookupRes "subscription" res),
+        channelMap = Nothing
+      }
+
+lookupRes ::
+  ( WithOperation o,
+    Monad m
+  ) =>
+  Text ->
+  Value ->
+  ResModel o e m
+lookupRes name (Object fields) = maybe mkNull mkValue (lookup name fields)
+lookupRes _ _ = mkNull
diff --git a/test/Schema.hs b/test/Schema.hs
deleted file mode 100644
--- a/test/Schema.hs
+++ /dev/null
@@ -1,93 +0,0 @@
-{-# LANGUAGE DeriveGeneric #-}
-{-# LANGUAGE DuplicateRecordFields #-}
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE OverloadedStrings #-}
-
-module Schema
-  ( testSchema,
-  )
-where
-
-import Control.Monad ((<=<))
-import Data.Aeson ((.:), (.=), FromJSON (..), ToJSON (..), Value (..), eitherDecode, encode, object)
-import qualified Data.ByteString.Lazy as L (readFile)
-import qualified Data.ByteString.Lazy.Char8 as LB (unpack)
-import Data.ByteString.Lazy.Char8 (ByteString)
-import Data.Either (either)
-import Data.Morpheus.Core (parseFullGQLDocument, validateSchema)
-import Data.Morpheus.Types.Internal.AST
-  ( GQLErrors,
-    Schema,
-  )
-import Data.Morpheus.Types.Internal.Resolving
-  ( Eventless,
-    Result (..),
-  )
-import Data.Semigroup ((<>))
-import Data.Text (pack)
-import GHC.Generics (Generic)
-import Lib
-  ( CaseTree (..),
-    FileUrl (..),
-    scanSchemaTests,
-    toString,
-  )
-import Test.Tasty (TestTree, testGroup)
-import Test.Tasty.HUnit (assertFailure, testCase)
-
-readSource :: String -> IO ByteString
-readSource = L.readFile
-
-readSchema :: String -> IO (Eventless Schema)
-readSchema = fmap (validateSchema <=< parseFullGQLDocument) . readSource . (<> "/schema.gql")
-
-readResponse :: String -> IO Response
-readResponse = fmap (either AesonError id . eitherDecode) . readSource . (<> "/response.json")
-
-data Response
-  = OK
-  | Errors {errors :: GQLErrors}
-  | AesonError String
-  deriving (Generic)
-
-instance FromJSON Response where
-  parseJSON (Object v) =
-    Errors <$> v .: "errors"
-  parseJSON (String "OK") = pure OK
-  parseJSON v = pure $ AesonError (show v)
-
-instance ToJSON Response where
-  toJSON OK = String "OK"
-  toJSON (Errors err) = object ["errors" .= toJSON err]
-  toJSON (AesonError err) = String (pack err)
-
-toTests :: CaseTree -> TestTree
-toTests CaseTree {caseUrl, children = Left {}} = schemaCase caseUrl
-toTests CaseTree {caseUrl = FileUrl {fileName}, children = Right children} =
-  testGroup
-    fileName
-    (map toTests children)
-
-testSchema :: IO TestTree
-testSchema = toTests <$> scanSchemaTests "test/schema"
-
-schemaCase :: FileUrl -> TestTree
-schemaCase url = testCase (fileName url) $ do
-  schema <- readSchema (toString url)
-  expected <- readResponse (toString url)
-  assertion expected schema
-
-assertion :: Response -> Eventless Schema -> IO ()
-assertion OK Success {} = return ()
-assertion Errors {errors = err} Failure {errors}
-  | err == errors =
-    pure
-      ()
-assertion expected Success {} =
-  assertFailure $
-    LB.unpack
-      ("expected: \n " <> encode expected <> " \n but got: \n OK")
-assertion expected Failure {errors} =
-  assertFailure $
-    LB.unpack
-      ("expected: \n " <> encode expected <> " \n but got: \n " <> encode (Errors errors))
diff --git a/test/Spec.hs b/test/Spec.hs
--- a/test/Spec.hs
+++ b/test/Spec.hs
@@ -1,154 +1,43 @@
-{-# LANGUAGE DuplicateRecordFields #-}
-{-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 
 module Main
   ( main,
   )
 where
 
-import qualified Data.Aeson as A
-import Data.Aeson (decode, encode)
-import Data.Functor.Identity (Identity (..))
-import Data.Morpheus.Core (runApi)
-import Data.Morpheus.Internal.Utils
-  ( fromElems,
-  )
-import Data.Morpheus.QuasiQuoter (dsl)
-import Data.Morpheus.Types.IO
-  ( GQLRequest (..),
-  )
-import Data.Morpheus.Types.Internal.AST
-  ( FieldName,
-    Schema,
-    VALID,
-    Value (..),
-    msg,
-  )
-import Data.Morpheus.Types.Internal.Resolving
-  ( ResModel,
-    Resolver,
-    ResponseStream,
-    Result (..),
-    ResultT (..),
-    RootResModel (..),
-    WithOperation,
-    mkList,
-    mkNull,
-    mkObject,
-    mkString,
+import Test.Tasty
+  ( defaultMain,
+    testGroup,
   )
-import Data.Semigroup ((<>))
-import qualified Data.Text.Lazy as LT (toStrict)
-import Data.Text.Lazy.Encoding (decodeUtf8)
-import Lib
-  ( getGQLBody,
-    getResponseBody,
-    maybeVariables,
+import Utils.Api
+  ( apiTest,
   )
-import Schema
+import Utils.Schema
   ( testSchema,
   )
-import Test.Tasty
-  ( TestTree,
-    defaultMain,
-    testGroup,
-  )
-import Test.Tasty.HUnit
-  ( assertFailure,
-    testCase,
+import Prelude
+  ( ($),
+    IO,
   )
 
-getSchema :: Monad m => ResponseStream e m Schema
-getSchema =
-  fromElems
-    [dsl|
-  
-  type Query {
-    deity(name: String): Deity!
-  }
-
-  interface Character {
-    name : String
-  }
-
-  interface Supernatural {
-    power: [String!]!
-  }
-
-  type Hero implements Character {
-    name: String
-  }
-
-  type Deity implements Character Supernatural {
-    name: String!
-    power: [String!]!
-  }
-|]
-
-resolver :: Monad m => RootResModel e m
-resolver =
-  RootResModel
-    { query =
-        pure $
-          mkObject
-            "Query"
-            [("deity", resolveDeity)],
-      mutation = pure mkNull,
-      subscription = pure mkNull
-    }
-
-resolveDeity :: (WithOperation o, Monad m) => Resolver o e m (ResModel o e m)
-resolveDeity =
-  pure $
-    mkObject
-      "Deity"
-      [ ("name", pure $ mkString "Morpheus"),
-        ("power", pure $ mkList [mkString "Shapeshifting"])
-      ]
-
 main :: IO ()
 main = do
   schema <- testSchema
-  defaultMain
-    $ testGroup
+  defaultMain $
+    testGroup
       "core tests"
-    $ map
-      (uncurry basicTest)
-      [ ("basic Test", "api/simple"),
-        ("test interface", "api/interface")
+      [ schema,
+        apiTest "api/deity" ["simple", "interface"],
+        apiTest
+          "api/validation/fragment"
+          [ "on-type",
+            "on-interface",
+            "on-interface-inline",
+            "on-union-type",
+            "fail-unknown-field-on-interface",
+            "on-interface-type-casting",
+            "on-interface-type-casting-inline",
+            "on-interface-fail-without-casting"
+          ]
       ]
-      <> [schema]
-
-basicTest :: String -> FieldName -> TestTree
-basicTest description path = testCase description $ do
-  actual <- simpleTest <$> getRequest path
-  expected <- expectedResponse path
-  assertion expected actual
-
-simpleTest :: GQLRequest -> ResponseStream e Identity (Value VALID)
-simpleTest request = do
-  schema <- getSchema
-  runApi schema resolver request
-
-expectedResponse :: FieldName -> IO A.Value
-expectedResponse = getResponseBody
-
-assertion :: A.Value -> ResponseStream e Identity (Value VALID) -> IO ()
-assertion expected (ResultT (Identity Success {result}))
-  | Just expected == decode (encode result) = return ()
-  | otherwise =
-    assertFailure $ show ("expected: \n " <> msg expected <> " \n but got: \n " <> msg result)
-assertion _ (ResultT (Identity Failure {errors})) = assertFailure (show errors)
-
-getRequest :: FieldName -> IO GQLRequest
-getRequest path = do
-  queryBS <- LT.toStrict . decodeUtf8 <$> getGQLBody path
-  variables <- maybeVariables path
-  pure $
-    GQLRequest
-      { operationName = Nothing,
-        query = queryBS,
-        variables
-      }
diff --git a/test/Utils/Api.hs b/test/Utils/Api.hs
new file mode 100644
--- /dev/null
+++ b/test/Utils/Api.hs
@@ -0,0 +1,77 @@
+{-# LANGUAGE DuplicateRecordFields #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+module Utils.Api
+  ( apiTest,
+    assertion,
+  )
+where
+
+import Control.Applicative (pure)
+import qualified Data.Aeson as A
+import Data.Aeson (decode, encode)
+import qualified Data.ByteString.Lazy.Char8 as LB (unpack)
+import Data.Functor ((<$>), fmap)
+import Data.Functor.Identity (Identity (..))
+import Data.Maybe (Maybe (..))
+import Data.Morpheus.Core (defaultConfig, runApi)
+import Data.Morpheus.Types.IO
+import Data.Morpheus.Types.Internal.AST
+  ( FieldName (..),
+    VALID,
+    Value (..),
+  )
+import Data.Morpheus.Types.Internal.Resolving
+  ( ResponseStream,
+    ResultT (..),
+  )
+import Data.Semigroup ((<>))
+import Data.Text (unpack)
+import Lib
+  ( assertValidSchema,
+    expectedResponse,
+    getRequest,
+    getResolvers,
+  )
+import Test.Tasty
+  ( TestTree,
+    testGroup,
+  )
+import Test.Tasty.HUnit
+  ( assertFailure,
+    testCase,
+  )
+import Prelude
+  ( ($),
+    (==),
+    IO,
+    otherwise,
+  )
+
+assertion :: A.Value -> ResponseStream e Identity (Value VALID) -> IO ()
+assertion expected (ResultT (Identity actual))
+  | Just expected == decode actualValue = pure ()
+  | otherwise =
+    assertFailure $
+      LB.unpack
+        ("expected: \n\n " <> encode expected <> " \n\n but got: \n\n " <> actualValue)
+  where
+    actualValue = encode (renderResponse actual)
+
+apiTest :: FieldName -> [FieldName] -> TestTree
+apiTest apiPath requestPath =
+  testGroup (unpack $ readName apiPath) $
+    fmap (testApiRequest apiPath) requestPath
+
+testApiRequest ::
+  FieldName ->
+  FieldName ->
+  TestTree
+testApiRequest apiPath path = testCase (unpack $ readName path) $ do
+  schema <- assertValidSchema apiPath
+  resolvers <- getResolvers apiPath
+  let fullPath = apiPath <> "/" <> path
+  actual <- runApi schema resolvers defaultConfig <$> getRequest fullPath
+  expected <- expectedResponse fullPath
+  assertion expected actual
diff --git a/test/Utils/Schema.hs b/test/Utils/Schema.hs
new file mode 100644
--- /dev/null
+++ b/test/Utils/Schema.hs
@@ -0,0 +1,106 @@
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE DuplicateRecordFields #-}
+{-# LANGUAGE NamedFieldPuns #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+module Utils.Schema
+  ( testSchema,
+  )
+where
+
+import Control.Applicative (pure)
+import Data.Aeson ((.:), (.=), FromJSON (..), ToJSON (..), Value (..), eitherDecode, encode, object)
+import qualified Data.ByteString.Lazy as L (readFile)
+import qualified Data.ByteString.Lazy.Char8 as LB (unpack)
+import Data.ByteString.Lazy.Char8 (ByteString)
+import Data.Either (Either (..), either)
+import Data.Functor ((<$>), fmap)
+import Data.Morpheus.Core (parseFullGQLDocument)
+import Data.Morpheus.Types.Internal.AST
+  ( GQLErrors,
+    Schema,
+    VALID,
+  )
+import Data.Morpheus.Types.Internal.Resolving
+  ( Eventless,
+    Result (..),
+  )
+import Data.Semigroup ((<>))
+import Data.Text (pack)
+import GHC.Generics (Generic)
+import Lib
+  ( CaseTree (..),
+    FileUrl (..),
+    scanSchemaTests,
+    toString,
+  )
+import Test.Tasty (TestTree, testGroup)
+import Test.Tasty.HUnit (assertFailure, testCase)
+import Prelude
+  ( ($),
+    (.),
+    Eq (..),
+    FilePath,
+    IO,
+    String,
+    id,
+    show,
+  )
+
+readSource :: FilePath -> IO ByteString
+readSource = L.readFile
+
+readSchema :: FilePath -> IO (Eventless (Schema VALID))
+readSchema = fmap parseFullGQLDocument . readSource . (<> "/schema.gql")
+
+readResponse :: FilePath -> IO Response
+readResponse = fmap (either AesonError id . eitherDecode) . readSource . (<> "/response.json")
+
+data Response
+  = OK
+  | Errors {errors :: GQLErrors}
+  | AesonError String
+  deriving (Generic)
+
+instance FromJSON Response where
+  parseJSON (Object v) =
+    Errors <$> v .: "errors"
+  parseJSON (String "OK") = pure OK
+  parseJSON v = pure $ AesonError (show v)
+
+instance ToJSON Response where
+  toJSON OK = String "OK"
+  toJSON (Errors err) = object ["errors" .= toJSON err]
+  toJSON (AesonError err) = String (pack err)
+
+toTests :: CaseTree -> TestTree
+toTests CaseTree {caseUrl, children = Left {}} = schemaCase caseUrl
+toTests CaseTree {caseUrl = FileUrl {fileName}, children = Right children} =
+  testGroup
+    fileName
+    (fmap toTests children)
+
+testSchema :: IO TestTree
+testSchema = toTests <$> scanSchemaTests "test/schema"
+
+schemaCase :: FileUrl -> TestTree
+schemaCase url = testCase (fileName url) $ do
+  schema <- readSchema (toString url)
+  expected <- readResponse (toString url)
+  assertion expected schema
+
+assertion :: Response -> Eventless (Schema VALID) -> IO ()
+assertion OK Success {} = pure ()
+assertion Errors {errors = err} Failure {errors}
+  | err == errors =
+    pure
+      ()
+assertion expected Success {} =
+  assertFailure $
+    LB.unpack
+      ("expected: \n " <> encode expected <> " \n but got: \n OK")
+assertion expected Failure {errors} =
+  assertFailure $
+    LB.unpack
+      ("expected: \n " <> encode expected <> " \n but got: \n " <> encode (Errors errors))
diff --git a/test/api/deity/interface/query.gql b/test/api/deity/interface/query.gql
new file mode 100644
--- /dev/null
+++ b/test/api/deity/interface/query.gql
@@ -0,0 +1,79 @@
+query Get__Type {
+  interface: __type(name: "Character") {
+    ...FullType
+  }
+  deity: __type(name: "Deity") {
+    ...FullType
+  }
+}
+
+fragment FullType on __Type {
+  kind
+  name
+  fields(includeDeprecated: true) {
+    name
+    args {
+      ...InputValue
+    }
+    type {
+      ...TypeRef
+    }
+    isDeprecated
+    deprecationReason
+  }
+  inputFields {
+    ...InputValue
+  }
+  interfaces {
+    ...TypeRef
+  }
+  enumValues(includeDeprecated: true) {
+    name
+    isDeprecated
+    deprecationReason
+  }
+  possibleTypes {
+    ...TypeRef
+  }
+}
+
+fragment InputValue on __InputValue {
+  name
+  type {
+    ...TypeRef
+  }
+  defaultValue
+}
+
+fragment TypeRef on __Type {
+  kind
+  name
+  ofType {
+    kind
+    name
+    ofType {
+      kind
+      name
+      ofType {
+        kind
+        name
+        ofType {
+          kind
+          name
+          ofType {
+            kind
+            name
+            ofType {
+              kind
+              name
+              ofType {
+                kind
+                name
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/test/api/deity/interface/response.json b/test/api/deity/interface/response.json
new file mode 100644
--- /dev/null
+++ b/test/api/deity/interface/response.json
@@ -0,0 +1,67 @@
+{
+  "data": {
+    "interface": {
+      "kind": "INTERFACE",
+      "name": "Character",
+      "fields": [
+        {
+          "name": "name",
+          "args": [],
+          "type": { "kind": "SCALAR", "name": "String", "ofType": null },
+          "isDeprecated": false,
+          "deprecationReason": null
+        }
+      ],
+      "inputFields": null,
+      "interfaces": null,
+      "enumValues": null,
+      "possibleTypes": [
+        { "kind": "OBJECT", "name": "Deity", "ofType": null },
+        { "kind": "OBJECT", "name": "Hero", "ofType": null }
+      ]
+    },
+    "deity": {
+      "kind": "OBJECT",
+      "name": "Deity",
+      "fields": [
+        {
+          "name": "name",
+          "args": [],
+          "type": {
+            "kind": "NON_NULL",
+            "name": null,
+            "ofType": { "kind": "SCALAR", "name": "String", "ofType": null }
+          },
+          "isDeprecated": false,
+          "deprecationReason": null
+        },
+        {
+          "name": "power",
+          "args": [],
+          "type": {
+            "kind": "NON_NULL",
+            "name": null,
+            "ofType": {
+              "kind": "LIST",
+              "name": null,
+              "ofType": {
+                "kind": "NON_NULL",
+                "name": null,
+                "ofType": { "kind": "SCALAR", "name": "String", "ofType": null }
+              }
+            }
+          },
+          "isDeprecated": false,
+          "deprecationReason": null
+        }
+      ],
+      "inputFields": null,
+      "interfaces": [
+        { "kind": "INTERFACE", "name": "Character", "ofType": null },
+        { "kind": "INTERFACE", "name": "Supernatural", "ofType": null }
+      ],
+      "enumValues": null,
+      "possibleTypes": null
+    }
+  }
+}
diff --git a/test/api/deity/resolvers.json b/test/api/deity/resolvers.json
new file mode 100644
--- /dev/null
+++ b/test/api/deity/resolvers.json
@@ -0,0 +1,8 @@
+{
+  "query": {
+    "deity": {
+      "name": "Morpheus",
+      "power": ["Shapeshifting"]
+    }
+  }
+}
diff --git a/test/api/deity/schema.gql b/test/api/deity/schema.gql
new file mode 100644
--- /dev/null
+++ b/test/api/deity/schema.gql
@@ -0,0 +1,20 @@
+type Query {
+  deity(name: String): Deity!
+}
+
+interface Character {
+  name: String
+}
+
+interface Supernatural {
+  power: [String!]!
+}
+
+type Hero implements Character {
+  name: String
+}
+
+type Deity implements Character & Supernatural {
+  name: String!
+  power: [String!]!
+}
diff --git a/test/api/deity/simple/query.gql b/test/api/deity/simple/query.gql
new file mode 100644
--- /dev/null
+++ b/test/api/deity/simple/query.gql
@@ -0,0 +1,6 @@
+{
+  deity {
+    name
+    power
+  }
+}
diff --git a/test/api/deity/simple/response.json b/test/api/deity/simple/response.json
new file mode 100644
--- /dev/null
+++ b/test/api/deity/simple/response.json
@@ -0,0 +1,8 @@
+{
+  "data": {
+    "deity": {
+      "name": "Morpheus",
+      "power": ["Shapeshifting"]
+    }
+  }
+}
diff --git a/test/api/interface/query.gql b/test/api/interface/query.gql
deleted file mode 100644
--- a/test/api/interface/query.gql
+++ /dev/null
@@ -1,79 +0,0 @@
-query Get__Type {
-  interface: __type(name: "Character") {
-    ...FullType
-  }
-  deity: __type(name: "Deity") {
-    ...FullType
-  }
-}
-
-fragment FullType on __Type {
-  kind
-  name
-  fields(includeDeprecated: true) {
-    name
-    args {
-      ...InputValue
-    }
-    type {
-      ...TypeRef
-    }
-    isDeprecated
-    deprecationReason
-  }
-  inputFields {
-    ...InputValue
-  }
-  interfaces {
-    ...TypeRef
-  }
-  enumValues(includeDeprecated: true) {
-    name
-    isDeprecated
-    deprecationReason
-  }
-  possibleTypes {
-    ...TypeRef
-  }
-}
-
-fragment InputValue on __InputValue {
-  name
-  type {
-    ...TypeRef
-  }
-  defaultValue
-}
-
-fragment TypeRef on __Type {
-  kind
-  name
-  ofType {
-    kind
-    name
-    ofType {
-      kind
-      name
-      ofType {
-        kind
-        name
-        ofType {
-          kind
-          name
-          ofType {
-            kind
-            name
-            ofType {
-              kind
-              name
-              ofType {
-                kind
-                name
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-}
diff --git a/test/api/interface/response.json b/test/api/interface/response.json
deleted file mode 100644
--- a/test/api/interface/response.json
+++ /dev/null
@@ -1,65 +0,0 @@
-{
-  "interface": {
-    "kind": "INTERFACE",
-    "name": "Character",
-    "fields": [
-      {
-        "name": "name",
-        "args": [],
-        "type": { "kind": "SCALAR", "name": "String", "ofType": null },
-        "isDeprecated": false,
-        "deprecationReason": null
-      }
-    ],
-    "inputFields": null,
-    "interfaces": null,
-    "enumValues": null,
-    "possibleTypes": [
-      { "kind": "OBJECT", "name": "Deity", "ofType": null },
-      { "kind": "OBJECT", "name": "Hero", "ofType": null }
-    ]
-  },
-  "deity": {
-    "kind": "OBJECT",
-    "name": "Deity",
-    "fields": [
-      {
-        "name": "name",
-        "args": [],
-        "type": {
-          "kind": "NON_NULL",
-          "name": null,
-          "ofType": { "kind": "SCALAR", "name": "String", "ofType": null }
-        },
-        "isDeprecated": false,
-        "deprecationReason": null
-      },
-      {
-        "name": "power",
-        "args": [],
-        "type": {
-          "kind": "NON_NULL",
-          "name": null,
-          "ofType": {
-            "kind": "LIST",
-            "name": null,
-            "ofType": {
-              "kind": "NON_NULL",
-              "name": null,
-              "ofType": { "kind": "SCALAR", "name": "String", "ofType": null }
-            }
-          }
-        },
-        "isDeprecated": false,
-        "deprecationReason": null
-      }
-    ],
-    "inputFields": null,
-    "interfaces": [
-      { "kind": "INTERFACE", "name": "Character", "ofType": null },
-      { "kind": "INTERFACE", "name": "Supernatural", "ofType": null }
-    ],
-    "enumValues": null,
-    "possibleTypes": null
-  }
-}
diff --git a/test/api/simple/query.gql b/test/api/simple/query.gql
deleted file mode 100644
--- a/test/api/simple/query.gql
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  deity {
-    name
-    power
-  }
-}
diff --git a/test/api/simple/response.json b/test/api/simple/response.json
deleted file mode 100644
--- a/test/api/simple/response.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "deity": {
-    "name": "Morpheus",
-    "power": ["Shapeshifting"]
-  }
-}
diff --git a/test/api/validation/fragment/fail-unknown-field-on-interface/query.gql b/test/api/validation/fragment/fail-unknown-field-on-interface/query.gql
new file mode 100644
--- /dev/null
+++ b/test/api/validation/fragment/fail-unknown-field-on-interface/query.gql
@@ -0,0 +1,16 @@
+{
+  deity {
+    ...onSupernatural
+  }
+  character {
+    ...OnCharacter
+  }
+}
+
+fragment OnCharacter on Character {
+  power
+}
+
+fragment onSupernatural on Supernatural {
+  name
+}
diff --git a/test/api/validation/fragment/fail-unknown-field-on-interface/response.json b/test/api/validation/fragment/fail-unknown-field-on-interface/response.json
new file mode 100644
--- /dev/null
+++ b/test/api/validation/fragment/fail-unknown-field-on-interface/response.json
@@ -0,0 +1,12 @@
+{
+  "errors": [
+    {
+      "message": "Cannot query field \"power\" on type \"Character\".",
+      "locations": [{ "line": 11, "column": 3 }]
+    },
+    {
+      "message": "Cannot query field \"name\" on type \"Supernatural\".",
+      "locations": [{ "line": 15, "column": 3 }]
+    }
+  ]
+}
diff --git a/test/api/validation/fragment/on-interface-fail-without-casting/query.gql b/test/api/validation/fragment/on-interface-fail-without-casting/query.gql
new file mode 100644
--- /dev/null
+++ b/test/api/validation/fragment/on-interface-fail-without-casting/query.gql
@@ -0,0 +1,7 @@
+{
+  character {
+    name
+    power
+    nickname
+  }
+}
diff --git a/test/api/validation/fragment/on-interface-fail-without-casting/response.json b/test/api/validation/fragment/on-interface-fail-without-casting/response.json
new file mode 100644
--- /dev/null
+++ b/test/api/validation/fragment/on-interface-fail-without-casting/response.json
@@ -0,0 +1,22 @@
+{
+  "errors": [
+    {
+      "message": "Cannot query field \"power\" on type \"Character\".",
+      "locations": [
+        {
+          "line": 4,
+          "column": 5
+        }
+      ]
+    },
+    {
+      "message": "Cannot query field \"nickname\" on type \"Character\".",
+      "locations": [
+        {
+          "line": 5,
+          "column": 5
+        }
+      ]
+    }
+  ]
+}
diff --git a/test/api/validation/fragment/on-interface-inline/query.gql b/test/api/validation/fragment/on-interface-inline/query.gql
new file mode 100644
--- /dev/null
+++ b/test/api/validation/fragment/on-interface-inline/query.gql
@@ -0,0 +1,12 @@
+{
+  deity {
+    ... on Supernatural {
+      power
+    }
+  }
+  character {
+    ... on Character {
+      name
+    }
+  }
+}
diff --git a/test/api/validation/fragment/on-interface-inline/response.json b/test/api/validation/fragment/on-interface-inline/response.json
new file mode 100644
--- /dev/null
+++ b/test/api/validation/fragment/on-interface-inline/response.json
@@ -0,0 +1,10 @@
+{
+  "data": {
+    "deity": { "power": ["Shapeshifting"] },
+    "character": [
+      { "name": "Test Deity" },
+      { "name": "Test Hero" },
+      { "name": "Test Character" }
+    ]
+  }
+}
diff --git a/test/api/validation/fragment/on-interface-type-casting-inline/query.gql b/test/api/validation/fragment/on-interface-type-casting-inline/query.gql
new file mode 100644
--- /dev/null
+++ b/test/api/validation/fragment/on-interface-type-casting-inline/query.gql
@@ -0,0 +1,13 @@
+{
+  character {
+    ... on Character {
+      name
+    }
+    ... on Deity {
+      power
+    }
+    ... on Hero {
+      nickname
+    }
+  }
+}
diff --git a/test/api/validation/fragment/on-interface-type-casting-inline/response.json b/test/api/validation/fragment/on-interface-type-casting-inline/response.json
new file mode 100644
--- /dev/null
+++ b/test/api/validation/fragment/on-interface-type-casting-inline/response.json
@@ -0,0 +1,17 @@
+{
+  "data": {
+    "character": [
+      {
+        "name": "Test Deity",
+        "power": ["Show Only on Deity"]
+      },
+      {
+        "name": "Test Hero",
+        "nickname": "tets Hero NickName"
+      },
+      {
+        "name": "Test Character"
+      }
+    ]
+  }
+}
diff --git a/test/api/validation/fragment/on-interface-type-casting/query.gql b/test/api/validation/fragment/on-interface-type-casting/query.gql
new file mode 100644
--- /dev/null
+++ b/test/api/validation/fragment/on-interface-type-casting/query.gql
@@ -0,0 +1,19 @@
+{
+  character {
+    ...OnCharacter
+    ...onDeity
+    ...onHero
+  }
+}
+
+fragment OnCharacter on Character {
+  name
+}
+
+fragment onDeity on Deity {
+  power
+}
+
+fragment onHero on Hero {
+  nickname
+}
diff --git a/test/api/validation/fragment/on-interface-type-casting/response.json b/test/api/validation/fragment/on-interface-type-casting/response.json
new file mode 100644
--- /dev/null
+++ b/test/api/validation/fragment/on-interface-type-casting/response.json
@@ -0,0 +1,17 @@
+{
+  "data": {
+    "character": [
+      {
+        "name": "Test Deity",
+        "power": ["Show Only on Deity"]
+      },
+      {
+        "name": "Test Hero",
+        "nickname": "tets Hero NickName"
+      },
+      {
+        "name": "Test Character"
+      }
+    ]
+  }
+}
diff --git a/test/api/validation/fragment/on-interface/query.gql b/test/api/validation/fragment/on-interface/query.gql
new file mode 100644
--- /dev/null
+++ b/test/api/validation/fragment/on-interface/query.gql
@@ -0,0 +1,16 @@
+{
+  deity {
+    ...OnSupernatural
+  }
+  character {
+    ...OnCharacter
+  }
+}
+
+fragment OnSupernatural on Supernatural {
+  power
+}
+
+fragment OnCharacter on Character {
+  name
+}
diff --git a/test/api/validation/fragment/on-interface/response.json b/test/api/validation/fragment/on-interface/response.json
new file mode 100644
--- /dev/null
+++ b/test/api/validation/fragment/on-interface/response.json
@@ -0,0 +1,10 @@
+{
+  "data": {
+    "deity": { "power": ["Shapeshifting"] },
+    "character": [
+      { "name": "Test Deity" },
+      { "name": "Test Hero" },
+      { "name": "Test Character" }
+    ]
+  }
+}
diff --git a/test/api/validation/fragment/on-type/query.gql b/test/api/validation/fragment/on-type/query.gql
new file mode 100644
--- /dev/null
+++ b/test/api/validation/fragment/on-type/query.gql
@@ -0,0 +1,9 @@
+{
+  deity {
+    ...OnDeity
+  }
+}
+
+fragment OnDeity on Deity {
+  name
+}
diff --git a/test/api/validation/fragment/on-type/response.json b/test/api/validation/fragment/on-type/response.json
new file mode 100644
--- /dev/null
+++ b/test/api/validation/fragment/on-type/response.json
@@ -0,0 +1,7 @@
+{
+  "data": {
+    "deity": {
+      "name": "Morpheus"
+    }
+  }
+}
diff --git a/test/api/validation/fragment/on-union-type/query.gql b/test/api/validation/fragment/on-union-type/query.gql
new file mode 100644
--- /dev/null
+++ b/test/api/validation/fragment/on-union-type/query.gql
@@ -0,0 +1,9 @@
+{
+  myUnion {
+    ...onDeity
+  }
+}
+
+fragment onDeity on Deity {
+  power
+}
diff --git a/test/api/validation/fragment/on-union-type/response.json b/test/api/validation/fragment/on-union-type/response.json
new file mode 100644
--- /dev/null
+++ b/test/api/validation/fragment/on-union-type/response.json
@@ -0,0 +1,5 @@
+{
+  "data": {
+    "myUnion": null
+  }
+}
diff --git a/test/api/validation/fragment/resolvers.json b/test/api/validation/fragment/resolvers.json
new file mode 100644
--- /dev/null
+++ b/test/api/validation/fragment/resolvers.json
@@ -0,0 +1,29 @@
+{
+  "query": {
+    "deity": {
+      "__typename": "Deity",
+      "name": "Morpheus",
+      "power": ["Shapeshifting"]
+    },
+    "character": [
+      {
+        "__typename": "Deity",
+        "name": "Test Deity",
+        "power": ["Show Only on Deity"],
+        "nickname": "this should be skipped"
+      },
+      {
+        "__typename": "Hero",
+        "name": "Test Hero",
+        "power": ["this should be skipped"],
+        "nickname": "tets Hero NickName"
+      },
+      {
+        "__typename": "Character",
+        "name": "Test Character",
+        "nickname": "this should be skipped",
+        "power": ["this should be skipped"]
+      }
+    ]
+  }
+}
diff --git a/test/api/validation/fragment/schema.gql b/test/api/validation/fragment/schema.gql
new file mode 100644
--- /dev/null
+++ b/test/api/validation/fragment/schema.gql
@@ -0,0 +1,25 @@
+interface Character {
+  name: String
+}
+
+interface Supernatural {
+  power: [String!]!
+}
+
+type Hero implements Character {
+  name: String
+  nickname: String
+}
+
+type Deity implements Character & Supernatural {
+  name: String!
+  power: [String!]!
+}
+
+union MyUnion = Hero | Deity
+
+type Query {
+  deity: Deity!
+  myUnion: MyUnion
+  character: [Character!]
+}
diff --git a/test/schema/parsing/directive/ok/simple/response.json b/test/schema/parsing/directive/ok/simple/response.json
new file mode 100644
--- /dev/null
+++ b/test/schema/parsing/directive/ok/simple/response.json
@@ -0,0 +1,1 @@
+"OK"
diff --git a/test/schema/parsing/directive/ok/simple/schema.gql b/test/schema/parsing/directive/ok/simple/schema.gql
new file mode 100644
--- /dev/null
+++ b/test/schema/parsing/directive/ok/simple/schema.gql
@@ -0,0 +1,5 @@
+directive @MyDirective on FIELD_DEFINITION | OBJECT
+
+type Query {
+  name: String
+}
diff --git a/test/schema/parsing/directive/ok/sophisticated/response.json b/test/schema/parsing/directive/ok/sophisticated/response.json
new file mode 100644
--- /dev/null
+++ b/test/schema/parsing/directive/ok/sophisticated/response.json
@@ -0,0 +1,1 @@
+"OK"
diff --git a/test/schema/parsing/directive/ok/sophisticated/schema.gql b/test/schema/parsing/directive/ok/sophisticated/schema.gql
new file mode 100644
--- /dev/null
+++ b/test/schema/parsing/directive/ok/sophisticated/schema.gql
@@ -0,0 +1,17 @@
+directive @DirectiveA on SCALAR
+
+directive @DirectiveB(arg: Int) on FIELD_DEFINITION | INPUT_OBJECT
+
+directive @DirectiveC(arg: MyInput! = {}) on FIELD_DEFINITION | FIELD_DEFINITION
+
+directive @DirectiveD(
+  arg: String = "bla"
+) on FIELD_DEFINITION | FIELD_DEFINITION
+
+input MyInput {
+  field: Int
+}
+
+type Query {
+  name: String
+}
diff --git a/test/schema/parsing/schema-definition/fail/dupplicate-field/query-mutation-subscription/response.json b/test/schema/parsing/schema-definition/fail/dupplicate-field/query-mutation-subscription/response.json
new file mode 100644
--- /dev/null
+++ b/test/schema/parsing/schema-definition/fail/dupplicate-field/query-mutation-subscription/response.json
@@ -0,0 +1,20 @@
+{
+  "errors": [
+    {
+      "message": "There can Be only One TypeDefinition for schema.\"query\"",
+      "locations": []
+    },
+    {
+      "message": "There can Be only One TypeDefinition for schema.\"mutation\"",
+      "locations": []
+    },
+    {
+      "message": "There can Be only One TypeDefinition for schema.\"subscription\"",
+      "locations": []
+    },
+    {
+      "message": "There can Be only One TypeDefinition for schema.\"subscription\"",
+      "locations": []
+    }
+  ]
+}
diff --git a/test/schema/parsing/schema-definition/fail/dupplicate-field/query-mutation-subscription/schema.gql b/test/schema/parsing/schema-definition/fail/dupplicate-field/query-mutation-subscription/schema.gql
new file mode 100644
--- /dev/null
+++ b/test/schema/parsing/schema-definition/fail/dupplicate-field/query-mutation-subscription/schema.gql
@@ -0,0 +1,21 @@
+type Query {
+  name: String
+}
+
+type Mutation {
+  name: String
+}
+
+type Subscription {
+  name: String
+}
+
+schema {
+  query: Query
+  query: Query
+  mutation: Mutation
+  mutation: Mutation
+  subscription: Subscription
+  subscription: Subscription
+  subscription: Subscription
+}
diff --git a/test/schema/parsing/schema-definition/fail/dupplicate-field/query/response.json b/test/schema/parsing/schema-definition/fail/dupplicate-field/query/response.json
new file mode 100644
--- /dev/null
+++ b/test/schema/parsing/schema-definition/fail/dupplicate-field/query/response.json
@@ -0,0 +1,12 @@
+{
+  "errors": [
+    {
+      "message": "There can Be only One TypeDefinition for schema.\"query\"",
+      "locations": []
+    },
+    {
+      "message": "There can Be only One TypeDefinition for schema.\"query\"",
+      "locations": []
+    }
+  ]
+}
diff --git a/test/schema/parsing/schema-definition/fail/dupplicate-field/query/schema.gql b/test/schema/parsing/schema-definition/fail/dupplicate-field/query/schema.gql
new file mode 100644
--- /dev/null
+++ b/test/schema/parsing/schema-definition/fail/dupplicate-field/query/schema.gql
@@ -0,0 +1,9 @@
+type Query {
+  name: String
+}
+
+schema {
+  query: Query
+  query: Query
+  query: Query
+}
diff --git a/test/schema/parsing/schema-definition/fail/dupplicate-schema-definition/response.json b/test/schema/parsing/schema-definition/fail/dupplicate-schema-definition/response.json
new file mode 100644
--- /dev/null
+++ b/test/schema/parsing/schema-definition/fail/dupplicate-schema-definition/response.json
@@ -0,0 +1,6 @@
+{
+  "errors": [
+    { "message": "There can Be only One SchemaDefinition.", "locations": [] },
+    { "message": "There can Be only One SchemaDefinition.", "locations": [] }
+  ]
+}
diff --git a/test/schema/parsing/schema-definition/fail/dupplicate-schema-definition/schema.gql b/test/schema/parsing/schema-definition/fail/dupplicate-schema-definition/schema.gql
new file mode 100644
--- /dev/null
+++ b/test/schema/parsing/schema-definition/fail/dupplicate-schema-definition/schema.gql
@@ -0,0 +1,29 @@
+type Query {
+  name: String
+}
+
+schema {
+  query: Query
+  mutation: Mutation
+  subscription: Subscription
+}
+
+schema {
+  query: Query
+  mutation: Mutation
+  subscription: Subscription
+}
+
+type Mutation {
+  name: String
+}
+
+type Subscription {
+  name: String
+}
+
+schema {
+  query: Query
+  mutation: Mutation
+  subscription: Subscription
+}
diff --git a/test/schema/parsing/schema-definition/fail/unknown-fields/bla/response.json b/test/schema/parsing/schema-definition/fail/unknown-fields/bla/response.json
new file mode 100644
--- /dev/null
+++ b/test/schema/parsing/schema-definition/fail/unknown-fields/bla/response.json
@@ -0,0 +1,8 @@
+{
+  "errors": [
+    {
+      "message": "offset=78:\nunexpected 'b'\nexpecting '}', Ignored, IgnoredTokens, OperationType, or white space\n",
+      "locations": [{ "line": 8, "column": 3 }]
+    }
+  ]
+}
diff --git a/test/schema/parsing/schema-definition/fail/unknown-fields/bla/schema.gql b/test/schema/parsing/schema-definition/fail/unknown-fields/bla/schema.gql
new file mode 100644
--- /dev/null
+++ b/test/schema/parsing/schema-definition/fail/unknown-fields/bla/schema.gql
@@ -0,0 +1,9 @@
+type MyType {
+  name: String
+}
+
+schema {
+  query: MyType
+  mutation: MyType
+  bla: MyType
+}
diff --git a/test/schema/parsing/schema-definition/fail/unknown-fields/uppercase/response.json b/test/schema/parsing/schema-definition/fail/unknown-fields/uppercase/response.json
new file mode 100644
--- /dev/null
+++ b/test/schema/parsing/schema-definition/fail/unknown-fields/uppercase/response.json
@@ -0,0 +1,8 @@
+{
+  "errors": [
+    {
+      "message": "offset=43:\nunexpected 'Q'\nexpecting '}', Ignored, OperationType, or white space\n",
+      "locations": [{ "line": 6, "column": 3 }]
+    }
+  ]
+}
diff --git a/test/schema/parsing/schema-definition/fail/unknown-fields/uppercase/schema.gql b/test/schema/parsing/schema-definition/fail/unknown-fields/uppercase/schema.gql
new file mode 100644
--- /dev/null
+++ b/test/schema/parsing/schema-definition/fail/unknown-fields/uppercase/schema.gql
@@ -0,0 +1,7 @@
+type MyType {
+  name: String
+}
+
+schema {
+  Query: MyType
+}
diff --git a/test/schema/parsing/schema-definition/ok/query-mutation-subscription/response.json b/test/schema/parsing/schema-definition/ok/query-mutation-subscription/response.json
new file mode 100644
--- /dev/null
+++ b/test/schema/parsing/schema-definition/ok/query-mutation-subscription/response.json
@@ -0,0 +1,1 @@
+"OK"
diff --git a/test/schema/parsing/schema-definition/ok/query-mutation-subscription/schema.gql b/test/schema/parsing/schema-definition/ok/query-mutation-subscription/schema.gql
new file mode 100644
--- /dev/null
+++ b/test/schema/parsing/schema-definition/ok/query-mutation-subscription/schema.gql
@@ -0,0 +1,17 @@
+type Query {
+  name: String
+}
+
+type Mutation {
+  name: String
+}
+
+type Subscription {
+  name: String
+}
+
+schema {
+  query: Query
+  mutation: Mutation
+  subscription: Subscription
+}
diff --git a/test/schema/parsing/schema-definition/ok/query-mutation/response.json b/test/schema/parsing/schema-definition/ok/query-mutation/response.json
new file mode 100644
--- /dev/null
+++ b/test/schema/parsing/schema-definition/ok/query-mutation/response.json
@@ -0,0 +1,1 @@
+"OK"
diff --git a/test/schema/parsing/schema-definition/ok/query-mutation/schema.gql b/test/schema/parsing/schema-definition/ok/query-mutation/schema.gql
new file mode 100644
--- /dev/null
+++ b/test/schema/parsing/schema-definition/ok/query-mutation/schema.gql
@@ -0,0 +1,12 @@
+type Query {
+  name: String
+}
+
+type Mutation {
+  name: String
+}
+
+schema {
+  query: Query
+  mutation: Mutation
+}
diff --git a/test/schema/parsing/schema-definition/ok/query/response.json b/test/schema/parsing/schema-definition/ok/query/response.json
new file mode 100644
--- /dev/null
+++ b/test/schema/parsing/schema-definition/ok/query/response.json
@@ -0,0 +1,1 @@
+"OK"
diff --git a/test/schema/parsing/schema-definition/ok/query/schema.gql b/test/schema/parsing/schema-definition/ok/query/schema.gql
new file mode 100644
--- /dev/null
+++ b/test/schema/parsing/schema-definition/ok/query/schema.gql
@@ -0,0 +1,12 @@
+type Query {
+  name: String
+}
+
+type Mutation {
+  name: String
+}
+
+schema {
+  query: Query
+  mutation: Mutation
+}
diff --git a/test/schema/validation/default-value/argument/missing-field/response.json b/test/schema/validation/default-value/argument/missing-field/response.json
--- a/test/schema/validation/default-value/argument/missing-field/response.json
+++ b/test/schema/validation/default-value/argument/missing-field/response.json
@@ -13,11 +13,11 @@
       "locations": []
     },
     {
-      "message": "Field Query.field(i3:) got invalid default value. in field \"field\": Undefined Field \"field2\".",
+      "message": "Field Query.field(i3:) got invalid default value. in field \"field.field\": Undefined Field \"field\".",
       "locations": []
     },
     {
-      "message": "Field Query.field(i3:) got invalid default value. in field \"field.field\": Undefined Field \"field\".",
+      "message": "Field Query.field(i3:) got invalid default value. in field \"field\": Undefined Field \"field2\".",
       "locations": []
     }
   ]
diff --git a/test/schema/validation/default-value/argument/unexpected-value/response.json b/test/schema/validation/default-value/argument/unexpected-value/response.json
--- a/test/schema/validation/default-value/argument/unexpected-value/response.json
+++ b/test/schema/validation/default-value/argument/unexpected-value/response.json
@@ -2,31 +2,31 @@
   "errors": [
     {
       "message": "Field Query.field(i1:) got invalid default value. in field \"field1.field2\": Expected type \"String\" found 1.",
-      "locations": [{ "line": 0, "column": 0 }]
+      "locations": []
     },
     {
       "message": "Field Query.field(i1:) got invalid default value. in field \"field2\": Expected type \"String\" found true.",
-      "locations": [{ "line": 0, "column": 0 }]
+      "locations": []
     },
     {
       "message": "Field Query.field(i2:) got invalid default value. in field \"field1\": Expected type \"ID\" found {field3: 2344}.",
-      "locations": [{ "line": 0, "column": 0 }]
+      "locations": []
     },
     {
       "message": "Field Query.field(i2:) got invalid default value. in field \"field2\": Expected type \"String\" found 123.",
-      "locations": [{ "line": 0, "column": 0 }]
+      "locations": []
     },
     {
       "message": "Field Query.field(i3:) got invalid default value. Expected type \"TestEnum\" found EnumBB.",
-      "locations": [{ "line": 0, "column": 0 }]
+      "locations": []
     },
     {
       "message": "Field Query.field(i4:) got invalid default value. Expected type \"ID\" found true.",
-      "locations": [{ "line": 0, "column": 0 }]
+      "locations": []
     },
     {
       "message": "Field Query.field(i5:) got invalid default value. Expected type \"Int\" found \"some text\".",
-      "locations": [{ "line": 0, "column": 0 }]
+      "locations": []
     }
   ]
 }
diff --git a/test/schema/validation/default-value/argument/unknown-field/response.json b/test/schema/validation/default-value/argument/unknown-field/response.json
--- a/test/schema/validation/default-value/argument/unknown-field/response.json
+++ b/test/schema/validation/default-value/argument/unknown-field/response.json
@@ -1,7 +1,7 @@
 {
   "errors": [
     {
-      "message": "Field Query.field(i1:) got invalid default value. in field \"field.field\": Unknown Field \"field3\".",
+      "message": "Field Query.field(i1:) got invalid default value. Unknown Field \"field2\".",
       "locations": []
     },
     {
@@ -9,7 +9,7 @@
       "locations": []
     },
     {
-      "message": "Field Query.field(i1:) got invalid default value. Unknown Field \"field2\".",
+      "message": "Field Query.field(i1:) got invalid default value. in field \"field.field\": Unknown Field \"field3\".",
       "locations": []
     }
   ]
diff --git a/test/schema/validation/default-value/field/missing-field/response.json b/test/schema/validation/default-value/field/missing-field/response.json
--- a/test/schema/validation/default-value/field/missing-field/response.json
+++ b/test/schema/validation/default-value/field/missing-field/response.json
@@ -1,11 +1,11 @@
 {
   "errors": [
     {
-      "message": "Field Input3.field1 got invalid default value. Undefined Field \"field2\".",
+      "message": "Field Input3.field1 got invalid default value. in field \"field\": Undefined Field \"field\".",
       "locations": []
     },
     {
-      "message": "Field Input3.field1 got invalid default value. in field \"field\": Undefined Field \"field\".",
+      "message": "Field Input3.field1 got invalid default value. Undefined Field \"field2\".",
       "locations": []
     }
   ]
diff --git a/test/schema/validation/default-value/field/unexpected-value/response.json b/test/schema/validation/default-value/field/unexpected-value/response.json
--- a/test/schema/validation/default-value/field/unexpected-value/response.json
+++ b/test/schema/validation/default-value/field/unexpected-value/response.json
@@ -2,35 +2,43 @@
   "errors": [
     {
       "message": "Field Input2.objectField got invalid default value. in field \"field1\": Expected type \"ID!\" found true.",
-      "locations": [{ "line": 0, "column": 0 }]
+      "locations": []
     },
     {
       "message": "Field Input2.objectField got invalid default value. in field \"field2\": Expected type \"String!\" found true.",
-      "locations": [{ "line": 0, "column": 0 }]
+      "locations": []
     },
     {
       "message": "Field Input2.objectField got invalid default value. in field \"field3\": Expected type \"TestEnum\" found true.",
-      "locations": [{ "line": 0, "column": 0 }]
+      "locations": []
     },
     {
+      "message": "Field Input2.objectField got invalid default value. in field \"field4\": Expected type \"TestEnum!\" found 1.",
+      "locations": []
+    },
+    {
+      "message": "Field Input2.objectField got invalid default value. in field \"field5\": Expected type \"TestEnum\" found \"some text\".",
+      "locations": []
+    },
+    {
       "message": "Field Input1.field1 got invalid default value. Expected type \"ID!\" found EnumA.",
-      "locations": [{ "line": 0, "column": 0 }]
+      "locations": []
     },
     {
       "message": "Field Input1.field2 got invalid default value. Expected type \"String!\" found EnumA.",
-      "locations": [{ "line": 0, "column": 0 }]
+      "locations": []
     },
     {
       "message": "Field Input1.field3 got invalid default value. Expected type \"TestEnum\" found UnknownEnum.",
-      "locations": [{ "line": 0, "column": 0 }]
+      "locations": []
     },
     {
       "message": "Field Input1.field4 got invalid default value. Expected type \"TestEnum!\" found 1.",
-      "locations": [{ "line": 0, "column": 0 }]
+      "locations": []
     },
     {
       "message": "Field Input1.field5 got invalid default value. Expected type \"TestEnum\" found \"some text\".",
-      "locations": [{ "line": 0, "column": 0 }]
+      "locations": []
     }
   ]
 }
diff --git a/test/schema/validation/default-value/field/unknown-field/response.json b/test/schema/validation/default-value/field/unknown-field/response.json
--- a/test/schema/validation/default-value/field/unknown-field/response.json
+++ b/test/schema/validation/default-value/field/unknown-field/response.json
@@ -1,15 +1,15 @@
 {
   "errors": [
     {
-      "message": "Field Input3.field got invalid default value. in field \"field\": Unknown Field \"field2\".",
+      "message": "Field Input3.field got invalid default value. Unknown Field \"field2\".",
       "locations": []
     },
     {
-      "message": "Field Input3.field got invalid default value. in field \"field\": Unknown Field \"field3\".",
+      "message": "Field Input3.field got invalid default value. in field \"field\": Unknown Field \"field2\".",
       "locations": []
     },
     {
-      "message": "Field Input3.field got invalid default value. Unknown Field \"field2\".",
+      "message": "Field Input3.field got invalid default value. in field \"field\": Unknown Field \"field3\".",
       "locations": []
     }
   ]
diff --git a/test/schema/validation/directive/fail/at-invalid-place/response.json b/test/schema/validation/directive/fail/at-invalid-place/response.json
new file mode 100644
--- /dev/null
+++ b/test/schema/validation/directive/fail/at-invalid-place/response.json
@@ -0,0 +1,36 @@
+{
+  "errors": [
+    {
+      "message": "Directive \"DirectiveA\" may not to be used on SCALAR",
+      "locations": [{ "line": 9, "column": 17 }]
+    },
+    {
+      "message": "Directive \"DirectiveB\" may not to be used on ENUM",
+      "locations": [{ "line": 11, "column": 15 }]
+    },
+    {
+      "message": "Directive \"DirectiveC\" may not to be used on ENUM_VALUE",
+      "locations": [{ "line": 12, "column": 9 }]
+    },
+    {
+      "message": "Directive \"deprecated\" may not to be used on INPUT_OBJECT",
+      "locations": [{ "line": 16, "column": 14 }]
+    },
+    {
+      "message": "Directive \"include\" may not to be used on INPUT_FIELD_DEFINITION",
+      "locations": [{ "line": 17, "column": 14 }]
+    },
+    {
+      "message": "Directive \"deprecated\" may not to be used on OBJECT",
+      "locations": [{ "line": 21, "column": 12 }]
+    },
+    {
+      "message": "Directive \"include\" may not to be used on FIELD_DEFINITION",
+      "locations": [{ "line": 22, "column": 35 }]
+    },
+    {
+      "message": "Directive \"DirectiveD\" may not to be used on ARGUMENT_DEFINITION",
+      "locations": [{ "line": 22, "column": 17 }]
+    }
+  ]
+}
diff --git a/test/schema/validation/directive/fail/at-invalid-place/schema.gql b/test/schema/validation/directive/fail/at-invalid-place/schema.gql
new file mode 100644
--- /dev/null
+++ b/test/schema/validation/directive/fail/at-invalid-place/schema.gql
@@ -0,0 +1,23 @@
+directive @DirectiveA on INPUT_OBJECT
+
+directive @DirectiveB on SCALAR
+
+directive @DirectiveC on ENUM
+
+directive @DirectiveD on INPUT_FIELD_DEFINITION
+
+scalar MyScalar @DirectiveA
+
+enum TestEnum @DirectiveB {
+  EnumA @DirectiveC
+  EnumB
+}
+
+input Input1 @deprecated {
+  field1: ID @include(if: true)
+  field2: String
+}
+
+type Query @deprecated {
+  field(a1: Int @DirectiveD): Int @include(if: true)
+}
diff --git a/test/schema/validation/directive/fail/missing-argument/response.json b/test/schema/validation/directive/fail/missing-argument/response.json
new file mode 100644
--- /dev/null
+++ b/test/schema/validation/directive/fail/missing-argument/response.json
@@ -0,0 +1,48 @@
+{
+  "errors": [
+    {
+      "message": "Directive \"@DirectiveA\" argument \"a1\" is required but not provided.",
+      "locations": [{ "line": 9, "column": 17 }]
+    },
+    {
+      "message": "Directive \"@DirectiveA\" argument \"a2\" is required but not provided.",
+      "locations": [{ "line": 9, "column": 17 }]
+    },
+    {
+      "message": "Directive \"@DirectiveC\" argument \"arg\" is required but not provided.",
+      "locations": [{ "line": 19, "column": 13 }]
+    },
+    {
+      "message": "Directive \"@DirectiveC\" argument \"arg\" is required but not provided.",
+      "locations": [{ "line": 20, "column": 38 }]
+    },
+    {
+      "message": "Directive \"@DirectiveC\" argument \"arg\" is required but not provided.",
+      "locations": [{ "line": 20, "column": 17 }]
+    },
+    {
+      "message": "Directive \"@DirectiveA\" argument \"a1\" is required but not provided.",
+      "locations": [{ "line": 11, "column": 13 }]
+    },
+    {
+      "message": "Directive \"@DirectiveA\" argument \"a2\" is required but not provided.",
+      "locations": [{ "line": 11, "column": 13 }]
+    },
+    {
+      "message": "Directive \"@DirectiveA\" argument \"a1\" is required but not provided.",
+      "locations": [{ "line": 12, "column": 9 }]
+    },
+    {
+      "message": "Directive \"@DirectiveA\" argument \"a2\" is required but not provided.",
+      "locations": [{ "line": 12, "column": 9 }]
+    },
+    {
+      "message": "Directive \"@DirectiveB\" argument \"a1\" is required but not provided.",
+      "locations": [{ "line": 15, "column": 15 }]
+    },
+    {
+      "message": "Directive \"@DirectiveB\" argument \"a1\" is required but not provided.",
+      "locations": [{ "line": 16, "column": 17 }]
+    }
+  ]
+}
diff --git a/test/schema/validation/directive/fail/missing-argument/schema.gql b/test/schema/validation/directive/fail/missing-argument/schema.gql
new file mode 100644
--- /dev/null
+++ b/test/schema/validation/directive/fail/missing-argument/schema.gql
@@ -0,0 +1,25 @@
+directive @DirectiveA(a1: String!, a2: Int!) on SCALAR | ENUM | ENUM_VALUE
+
+directive @DirectiveB(a1: Int!) on INPUT_FIELD_DEFINITION | INPUT_OBJECT
+
+directive @DirectiveC(
+  arg: MyInput!
+) on FIELD_DEFINITION | OBJECT | ARGUMENT_DEFINITION
+
+scalar MyScalar @DirectiveA
+
+enum MyEnum @DirectiveA {
+  EnumA @DirectiveA
+}
+
+input MyInput @DirectiveB {
+  field: String @DirectiveB
+}
+
+type MyType @DirectiveC {
+  field(a1: Int @DirectiveC): String @DirectiveC
+}
+
+type Query {
+  name: String
+}
diff --git a/test/schema/validation/directive/fail/sopthisticated/response.json b/test/schema/validation/directive/fail/sopthisticated/response.json
new file mode 100644
--- /dev/null
+++ b/test/schema/validation/directive/fail/sopthisticated/response.json
@@ -0,0 +1,64 @@
+{
+  "errors": [
+    {
+      "message": "Directive \"include\" may not to be used on INPUT_OBJECT",
+      "locations": [{ "line": 13, "column": 13 }]
+    },
+    {
+      "message": "Directive \"@include\" argument \"if\" is required but not provided.",
+      "locations": [{ "line": 13, "column": 13 }]
+    },
+    {
+      "message": "Directive \"skip\" may not to be used on INPUT_FIELD_DEFINITION",
+      "locations": [{ "line": 14, "column": 13 }]
+    },
+    {
+      "message": "Directive \"@skip\" argument \"if\" is required but not provided.",
+      "locations": [{ "line": 14, "column": 13 }]
+    },
+    {
+      "message": "Unknown Directive \"SomeDirective\".",
+      "locations": [{ "line": 9, "column": 13 }]
+    },
+    {
+      "message": "Directive \"DirectiveC\" may not to be used on FIELD_DEFINITION",
+      "locations": [{ "line": 10, "column": 62 }]
+    },
+    {
+      "message": "Directive \"@DirectiveC\" argument \"arg\" is required but not provided.",
+      "locations": [{ "line": 10, "column": 62 }]
+    },
+    {
+      "message": "Unknown Argument \"someargs\" on Directive \"DirectiveC\".",
+      "locations": [{ "line": 10, "column": 40 }]
+    },
+    {
+      "message": "Argument \"arg\" got invalid value. Expected type \"Int!\" found True.",
+      "locations": [{ "line": 10, "column": 29 }]
+    },
+    {
+      "message": "Directive \"DirectiveA\" may not to be used on ENUM_VALUE",
+      "locations": [{ "line": 6, "column": 9 }]
+    },
+    {
+      "message": "Directive \"@DirectiveA\" argument \"a1\" is required but not provided.",
+      "locations": [{ "line": 6, "column": 9 }]
+    },
+    {
+      "message": "Directive \"DirectiveC\" may not to be used on OBJECT",
+      "locations": [{ "line": 17, "column": 12 }]
+    },
+    {
+      "message": "Argument \"arg\" got invalid value. Expected type \"Int!\" found \"bla\".",
+      "locations": [{ "line": 17, "column": 24 }]
+    },
+    {
+      "message": "Directive \"skip\" may not to be used on FIELD_DEFINITION",
+      "locations": [{ "line": 18, "column": 23 }]
+    },
+    {
+      "message": "Directive \"@skip\" argument \"if\" is required but not provided.",
+      "locations": [{ "line": 18, "column": 23 }]
+    }
+  ]
+}
diff --git a/test/schema/validation/directive/fail/sopthisticated/schema.gql b/test/schema/validation/directive/fail/sopthisticated/schema.gql
new file mode 100644
--- /dev/null
+++ b/test/schema/validation/directive/fail/sopthisticated/schema.gql
@@ -0,0 +1,19 @@
+directive @DirectiveA(a1: String!) on SCALAR
+
+directive @DirectiveC(arg: Int!) on ARGUMENT_DEFINITION
+
+enum MyEnum {
+  EnumA @DirectiveA
+}
+
+type MyType @SomeDirective {
+  field(a1: Int @DirectiveC(arg: True, someargs: 1)): String @DirectiveC
+}
+
+input Input @include {
+  field: ID @skip
+}
+
+type Query @DirectiveC(arg: "bla") {
+  field(a1: Int): Int @skip
+}
diff --git a/test/schema/validation/directive/fail/unexpected-value/response.json b/test/schema/validation/directive/fail/unexpected-value/response.json
new file mode 100644
--- /dev/null
+++ b/test/schema/validation/directive/fail/unexpected-value/response.json
@@ -0,0 +1,36 @@
+{
+  "errors": [
+    {
+      "message": "Argument \"a1\" got invalid value. Expected type \"Int!\" found 0.1.",
+      "locations": [{ "line": 9, "column": 29 }]
+    },
+    {
+      "message": "Argument \"reason\" got invalid value. Expected type \"String\" found EnumA.",
+      "locations": [{ "line": 14, "column": 21 }]
+    },
+    {
+      "message": "Argument \"reason\" got invalid value. Expected type \"String\" found 1.",
+      "locations": [{ "line": 15, "column": 21 }]
+    },
+    {
+      "message": "Argument \"reason\" got invalid value. Expected type \"String\" found Bool.",
+      "locations": [{ "line": 16, "column": 21 }]
+    },
+    {
+      "message": "Argument \"a1\" got invalid value. in field \"field\": Expected type \"String\" found 2394.",
+      "locations": [{ "line": 20, "column": 26 }]
+    },
+    {
+      "message": "Argument \"a1\" got invalid value. Expected type \"MyInput!\" found [\"some deprication\"].",
+      "locations": [{ "line": 21, "column": 30 }]
+    },
+    {
+      "message": "Argument \"a1\" got invalid value. Expected type \"Int!\" found \"some string\".",
+      "locations": [{ "line": 10, "column": 30 }]
+    },
+    {
+      "message": "Argument \"a1\" got invalid value. Expected type \"Int!\" found True.",
+      "locations": [{ "line": 11, "column": 30 }]
+    }
+  ]
+}
diff --git a/test/schema/validation/directive/fail/unexpected-value/schema.gql b/test/schema/validation/directive/fail/unexpected-value/schema.gql
new file mode 100644
--- /dev/null
+++ b/test/schema/validation/directive/fail/unexpected-value/schema.gql
@@ -0,0 +1,26 @@
+directive @DirectiveA(a1: Int!) on SCALAR
+
+directive @DirectiveB(a1: MyInput!) on INPUT_FIELD_DEFINITION
+
+input MyInput {
+  field: String
+}
+
+scalar MyScalar @DirectiveA(a1: 0.1)
+scalar MyScalar2 @DirectiveA(a1: "some string")
+scalar MyScalar3 @DirectiveA(a1: True)
+
+enum TestEnum {
+  EnumA @deprecated(reason: EnumA)
+  EnumB @deprecated(reason: 1)
+  EnumB @deprecated(reason: Bool)
+}
+
+input Input {
+  field1: ID @DirectiveB(a1: { field: 2394 })
+  field2: String @DirectiveB(a1: ["some deprication"])
+}
+
+type Query {
+  field: Int
+}
diff --git a/test/schema/validation/directive/fail/unknown-directive/response.json b/test/schema/validation/directive/fail/unknown-directive/response.json
new file mode 100644
--- /dev/null
+++ b/test/schema/validation/directive/fail/unknown-directive/response.json
@@ -0,0 +1,56 @@
+{
+  "errors": [
+    {
+      "message": "Unknown Directive \"DirectveD\".",
+      "locations": [{ "line": 15, "column": 15 }]
+    },
+    {
+      "message": "Unknown Directive \"DirectveA\".",
+      "locations": [{ "line": 1, "column": 17 }]
+    },
+    {
+      "message": "Unknown Directive \"DirectveB\".",
+      "locations": [{ "line": 3, "column": 15 }]
+    },
+    {
+      "message": "Unknown Directive \"DirectveB\".",
+      "locations": [{ "line": 4, "column": 9 }]
+    },
+    {
+      "message": "Unknown Directive \"DirectveC\".",
+      "locations": [{ "line": 7, "column": 8 }]
+    },
+    {
+      "message": "Unknown Directive \"DirectveC\".",
+      "locations": [{ "line": 8, "column": 17 }]
+    },
+    {
+      "message": "Unknown Directive \"DirectveE\".",
+      "locations": [{ "line": 17, "column": 14 }]
+    },
+    {
+      "message": "Unknown Directive \"DirectveE\".",
+      "locations": [{ "line": 18, "column": 14 }]
+    },
+    {
+      "message": "Unknown Directive \"DirectveC\".",
+      "locations": [{ "line": 11, "column": 8 }]
+    },
+    {
+      "message": "Unknown Directive \"DirectveC\".",
+      "locations": [{ "line": 12, "column": 17 }]
+    },
+    {
+      "message": "Unknown Directive \"DirectveF\".",
+      "locations": [{ "line": 22, "column": 12 }]
+    },
+    {
+      "message": "Unknown Directive \"DirectveF\".",
+      "locations": [{ "line": 23, "column": 34 }]
+    },
+    {
+      "message": "Unknown Directive \"DirectveF\".",
+      "locations": [{ "line": 23, "column": 17 }]
+    }
+  ]
+}
diff --git a/test/schema/validation/directive/fail/unknown-directive/schema.gql b/test/schema/validation/directive/fail/unknown-directive/schema.gql
new file mode 100644
--- /dev/null
+++ b/test/schema/validation/directive/fail/unknown-directive/schema.gql
@@ -0,0 +1,24 @@
+scalar MyScalar @DirectveA
+
+enum TestEnum @DirectveB {
+  EnumA @DirectveB
+  EnumB
+}
+type A @DirectveC {
+  name: String! @DirectveC
+}
+
+type B @DirectveC {
+  name: String! @DirectveC
+}
+
+union MyUnion @DirectveD = A | B
+
+input Input1 @DirectveE {
+  field1: ID @DirectveE
+  field2: String
+}
+
+type Query @DirectveF {
+  field(a1: Int @DirectveF): Int @DirectveF
+}
diff --git a/test/schema/validation/directive/ok/deprecated/custom-directive/response.json b/test/schema/validation/directive/ok/deprecated/custom-directive/response.json
new file mode 100644
--- /dev/null
+++ b/test/schema/validation/directive/ok/deprecated/custom-directive/response.json
@@ -0,0 +1,1 @@
+"OK"
diff --git a/test/schema/validation/directive/ok/deprecated/custom-directive/schema.gql b/test/schema/validation/directive/ok/deprecated/custom-directive/schema.gql
new file mode 100644
--- /dev/null
+++ b/test/schema/validation/directive/ok/deprecated/custom-directive/schema.gql
@@ -0,0 +1,25 @@
+directive @DirectiveA on SCALAR | ENUM | ENUM_VALUE
+
+directive @DirectiveB(arg: Int) on INPUT_FIELD_DEFINITION | INPUT_OBJECT
+
+directive @DirectiveC(
+  arg: MyInput! = {}
+) on FIELD_DEFINITION | OBJECT | ARGUMENT_DEFINITION
+
+scalar MyScalar @DirectiveA
+
+enum MyEnum @DirectiveA {
+  EnumA @DirectiveA
+}
+
+input MyInput @DirectiveB {
+  field: String @DirectiveB
+}
+
+type MyType @DirectiveC {
+  field(a1: Int @DirectiveC): String @DirectiveC
+}
+
+type Query {
+  name: String
+}
diff --git a/test/schema/validation/directive/ok/deprecated/response.json b/test/schema/validation/directive/ok/deprecated/response.json
new file mode 100644
--- /dev/null
+++ b/test/schema/validation/directive/ok/deprecated/response.json
@@ -0,0 +1,1 @@
+"OK"
diff --git a/test/schema/validation/directive/ok/deprecated/schema.gql b/test/schema/validation/directive/ok/deprecated/schema.gql
new file mode 100644
--- /dev/null
+++ b/test/schema/validation/directive/ok/deprecated/schema.gql
@@ -0,0 +1,15 @@
+scalar MyScalar
+
+enum TestEnum {
+  EnumA @deprecated
+  EnumB
+}
+
+input Input1 {
+  field1: ID
+  field2: String
+}
+
+type Query {
+  field(a1: Int): Int @deprecated
+}
diff --git a/test/schema/validation/schema-definition/fail/non-object-kind/from-schema/response.json b/test/schema/validation/schema-definition/fail/non-object-kind/from-schema/response.json
new file mode 100644
--- /dev/null
+++ b/test/schema/validation/schema-definition/fail/non-object-kind/from-schema/response.json
@@ -0,0 +1,16 @@
+{
+  "errors": [
+    {
+      "message": "Query root type must be Object type if provided, it cannot be \"MyType\"",
+      "locations": []
+    },
+    {
+      "message": "Mutation root type must be Object type if provided, it cannot be \"MyUnion\"",
+      "locations": []
+    },
+    {
+      "message": "Subscription root type must be Object type if provided, it cannot be \"MyEnum\"",
+      "locations": []
+    }
+  ]
+}
diff --git a/test/schema/validation/schema-definition/fail/non-object-kind/from-schema/schema.gql b/test/schema/validation/schema-definition/fail/non-object-kind/from-schema/schema.gql
new file mode 100644
--- /dev/null
+++ b/test/schema/validation/schema-definition/fail/non-object-kind/from-schema/schema.gql
@@ -0,0 +1,19 @@
+input MyType {
+  name: String
+}
+
+type MyType1 {
+  name: String
+}
+
+enum MyEnum {
+  Enum1
+}
+
+union MyUnion = MyType1
+
+schema {
+  query: MyType
+  mutation: MyUnion
+  subscription: MyEnum
+}
diff --git a/test/schema/validation/schema-definition/fail/non-object-kind/without-schema/response.json b/test/schema/validation/schema-definition/fail/non-object-kind/without-schema/response.json
new file mode 100644
--- /dev/null
+++ b/test/schema/validation/schema-definition/fail/non-object-kind/without-schema/response.json
@@ -0,0 +1,16 @@
+{
+  "errors": [
+    {
+      "message": "Query root type must be Object type if provided, it cannot be \"Query\"",
+      "locations": []
+    },
+    {
+      "message": "Mutation root type must be Object type if provided, it cannot be \"Mutation\"",
+      "locations": []
+    },
+    {
+      "message": "Subscription root type must be Object type if provided, it cannot be \"Subscription\"",
+      "locations": []
+    }
+  ]
+}
diff --git a/test/schema/validation/schema-definition/fail/non-object-kind/without-schema/schema.gql b/test/schema/validation/schema-definition/fail/non-object-kind/without-schema/schema.gql
new file mode 100644
--- /dev/null
+++ b/test/schema/validation/schema-definition/fail/non-object-kind/without-schema/schema.gql
@@ -0,0 +1,13 @@
+type MyType1 {
+  name: String
+}
+
+input Query {
+  name: String
+}
+
+union Mutation = MyType1
+
+enum Subscription {
+  Enum1
+}
diff --git a/test/schema/validation/schema-definition/fail/required query/empty/response.json b/test/schema/validation/schema-definition/fail/required query/empty/response.json
new file mode 100644
--- /dev/null
+++ b/test/schema/validation/schema-definition/fail/required query/empty/response.json
@@ -0,0 +1,8 @@
+{
+  "errors": [
+    {
+      "message": "Query root type must be provided.",
+      "locations": []
+    }
+  ]
+}
diff --git a/test/schema/validation/schema-definition/fail/required query/empty/schema.gql b/test/schema/validation/schema-definition/fail/required query/empty/schema.gql
new file mode 100644
--- /dev/null
+++ b/test/schema/validation/schema-definition/fail/required query/empty/schema.gql
@@ -0,0 +1,5 @@
+type MyType {
+  name: String
+}
+
+schema {}
diff --git a/test/schema/validation/schema-definition/fail/required query/no-query/response.json b/test/schema/validation/schema-definition/fail/required query/no-query/response.json
new file mode 100644
--- /dev/null
+++ b/test/schema/validation/schema-definition/fail/required query/no-query/response.json
@@ -0,0 +1,8 @@
+{
+  "errors": [
+    {
+      "message": "Query root type must be provided.",
+      "locations": []
+    }
+  ]
+}
diff --git a/test/schema/validation/schema-definition/fail/required query/no-query/schema.gql b/test/schema/validation/schema-definition/fail/required query/no-query/schema.gql
new file mode 100644
--- /dev/null
+++ b/test/schema/validation/schema-definition/fail/required query/no-query/schema.gql
@@ -0,0 +1,7 @@
+type MyType {
+  name: String
+}
+
+schema {
+  mutation: MyType
+}
diff --git a/test/schema/validation/schema-definition/fail/required query/no-schema-no-query/response.json b/test/schema/validation/schema-definition/fail/required query/no-schema-no-query/response.json
new file mode 100644
--- /dev/null
+++ b/test/schema/validation/schema-definition/fail/required query/no-schema-no-query/response.json
@@ -0,0 +1,8 @@
+{
+  "errors": [
+    {
+      "message": "Query root type must be provided.",
+      "locations": []
+    }
+  ]
+}
diff --git a/test/schema/validation/schema-definition/fail/required query/no-schema-no-query/schema.gql b/test/schema/validation/schema-definition/fail/required query/no-schema-no-query/schema.gql
new file mode 100644
--- /dev/null
+++ b/test/schema/validation/schema-definition/fail/required query/no-schema-no-query/schema.gql
@@ -0,0 +1,3 @@
+type MyType {
+  name: String
+}
diff --git a/test/schema/validation/schema-definition/fail/required query/schema-with-query/response.json b/test/schema/validation/schema-definition/fail/required query/schema-with-query/response.json
new file mode 100644
--- /dev/null
+++ b/test/schema/validation/schema-definition/fail/required query/schema-with-query/response.json
@@ -0,0 +1,8 @@
+{
+  "errors": [
+    {
+      "message": "Query root type must be provided.",
+      "locations": []
+    }
+  ]
+}
diff --git a/test/schema/validation/schema-definition/fail/required query/schema-with-query/schema.gql b/test/schema/validation/schema-definition/fail/required query/schema-with-query/schema.gql
new file mode 100644
--- /dev/null
+++ b/test/schema/validation/schema-definition/fail/required query/schema-with-query/schema.gql
@@ -0,0 +1,11 @@
+type MyType {
+  name: String
+}
+
+type Query {
+  name: String
+}
+
+schema {
+  mutation: MyType
+}
diff --git a/test/schema/validation/schema-definition/fail/unknown-type/unknown/response.json b/test/schema/validation/schema-definition/fail/unknown-type/unknown/response.json
new file mode 100644
--- /dev/null
+++ b/test/schema/validation/schema-definition/fail/unknown-type/unknown/response.json
@@ -0,0 +1,16 @@
+{
+  "errors": [
+    {
+      "message": "Unknown type \"MyType1\".",
+      "locations": []
+    },
+    {
+      "message": "Unknown type \"Asfwe\".",
+      "locations": []
+    },
+    {
+      "message": "Unknown type \"GjsO\".",
+      "locations": []
+    }
+  ]
+}
diff --git a/test/schema/validation/schema-definition/fail/unknown-type/unknown/schema.gql b/test/schema/validation/schema-definition/fail/unknown-type/unknown/schema.gql
new file mode 100644
--- /dev/null
+++ b/test/schema/validation/schema-definition/fail/unknown-type/unknown/schema.gql
@@ -0,0 +1,9 @@
+type MyType {
+  name: String
+}
+
+schema {
+  query: MyType1
+  mutation: Asfwe
+  subscription: GjsO
+}
diff --git a/test/schema/validation/schema-definition/ok/full/response.json b/test/schema/validation/schema-definition/ok/full/response.json
new file mode 100644
--- /dev/null
+++ b/test/schema/validation/schema-definition/ok/full/response.json
@@ -0,0 +1,1 @@
+"OK"
diff --git a/test/schema/validation/schema-definition/ok/full/schema.gql b/test/schema/validation/schema-definition/ok/full/schema.gql
new file mode 100644
--- /dev/null
+++ b/test/schema/validation/schema-definition/ok/full/schema.gql
@@ -0,0 +1,17 @@
+type Query {
+  name: String
+}
+
+type Mutation {
+  name: String
+}
+
+type Subscription {
+  name: String
+}
+
+schema {
+  query: Query
+  mutation: Mutation
+  subscription: Subscription
+}
