diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,404 @@
+# Morpheus GraphQL [![Hackage](https://img.shields.io/hackage/v/morpheus-graphql.svg)](https://hackage.haskell.org/package/morpheus-graphql) [![Build Status](https://api.travis-ci.com/morpheusgraphql/morpheus-graphql.svg?branch=master)](https://travis-ci.com/morpheusgraphql/morpheus-graphql)
+
+Build GraphQL APIs with your favourite functional language!
+
+Morpheus GraphQL (Server & Client) helps you to build GraphQL APIs in Haskell with native haskell types.
+Morpheus will convert your haskell types to a GraphQL schema and all your resolvers are just native Haskell functions. Mopheus GraphQL can also convert your GraphQL Schema or Query to Haskell types and validate them in compile time.
+
+Morpheus is still in an early stage of development, so any feedback is more than welcome, and we appreciate any contribution!
+Just open an issue here on GitHub, or join [our Slack channel](https://morpheus-graphql-slack-invite.herokuapp.com/) to get in touch.
+
+## Getting Started
+
+### Setup
+
+To get started with Morpheus, you first need to add it to your project's dependencies, as follows (assuming you're using hpack):
+
+package.yml
+
+```yaml
+dependencies:
+  - morpheus-graphql
+```
+
+Additionally, you should tell stack which version to pick:
+
+stack.yml
+
+```yaml
+resolver: lts-12.0 # or greater
+extra-deps:
+  - megaparsec-7.0.5
+  - aeson-1.4.4.0
+  - time-compat-1.9.2.2
+  - morpheus-graphql-0.2.2
+```
+
+As Morpheus is quite new, make sure stack can find morpheus-graphql by running `stack update`
+
+### Building your first GrqphQL API
+
+### with GraphQL syntax and Haskell QuasiQuotes
+
+```haskell
+
+[gqlDocument|
+  type Query {
+    deity (uid: Text!): Deity!
+  }
+
+  type Deity {
+    name  : Text!
+    power : Text
+  }
+|]
+
+rootResolver :: GQLRootResolver IO () () Query () ()
+rootResolver =
+  GQLRootResolver {queryResolver = return Query {deity}, mutationResolver = pure (), subscriptionResolver = pure ()}
+  where
+    deity DeityArgs {uid} = pure Deity {name, power}
+      where
+        name _ = pure "Morpheus"
+        power _ = pure (Just "Shapeshifting")
+
+gqlApi :: ByteString -> IO ByteString
+gqlApi = interpreter rootResolver
+```
+
+Template Haskell Generates types: `Query` , `Deity`, `DeityArgs`, that can be used by `rootResolver`
+
+generated types are not compatible with `Mutation`, `Subscription`,
+they can be used only in `Query`, but this issue will be fixed in next release
+
+### with Native Haskell Types
+
+To define a GraphQL API with Morpheus we start by defining the API Schema as a native Haskell data type,
+which derives the `Generic` typeclass. Lazily resolvable fields on this `Query` type are defined via `a -> IORes b`, representing resolving a set of arguments `a` to a concrete value `b`.
+
+```haskell
+data Query = Query
+  { deity :: DeityArgs -> IORes Deity
+  } deriving (Generic)
+
+data Deity = Deity
+  { fullName :: Text         -- Non-Nullable Field
+  , power    :: Maybe Text   -- Nullable Field
+  } deriving (Generic)
+
+instance GQLType Deity where
+  type  KIND Deity = OBJECT
+
+data DeityArgs = DeityArgs
+  { name      :: Text        -- Required Argument
+  , mythology :: Maybe Text  -- Optional Argument
+  } deriving (Generic)
+```
+
+For each field in the `Query` type defined via `a -> IORes b` (like `deity`) we will define a resolver implementation that provides the values during runtime by referring to
+some data source, e.g. a database or another API. Fields that are defined without `a -> IORes b` you can just provide a value.
+
+In above example, the field of `DeityArgs` could also be named using reserved identities (such as: `type`, `where`, etc), in order to avoid conflict, a prime symbol (`'`) must be attached. For example, you can have:
+
+```haskell
+data DeityArgs = DeityArgs
+  { name      :: Text        -- Required Argument
+  , mythology :: Maybe Text  -- Optional Argument
+  , type'     :: Text
+  } deriving (Generic)
+```
+
+The field name in the final request will be `type` instead of `type'`. The Morpheus request parser converts each of the reserved identities in Haskell 2010 to their corresponding names internally. This also applies to selections.
+
+```haskell
+resolveDeity :: DeityArgs -> IORes Deity
+resolveDeity args = gqlResolver $ askDB (name args) (mythology args)
+
+askDB :: Text -> Maybe Text -> IO (Either String Deity)
+askDB = ...
+```
+
+Note that the type `a -> IORes b` is just Synonym for `a -> ExceptT String IO b`
+
+To make this `Query` type available as an API, we define a `GQLRootResolver` and feed it to the Morpheus `interpreter`. A `GQLRootResolver` consists of `query`, `mutation` and `subscription` definitions, while we omit the latter for this example:
+
+```haskell
+rootResolver :: GQLRootResolver IO () () Query () ()
+rootResolver =
+  GQLRootResolver
+    { queryResolver = return Query {deity = resolveDeity}
+    , mutationResolver = return ()
+    , subscriptionResolver = return ()
+    }
+
+gqlApi :: ByteString -> IO ByteString
+gqlApi = interpreter rootResolver
+```
+
+As you can see, the API is defined as `ByteString -> IO ByteString` which we can either invoke directly or use inside an arbitrary web framework
+such as `scotty` or `serverless-haskell`. We'll go for `scotty` in this example:
+
+```haskell
+main :: IO ()
+main = scotty 3000 $ post "/api" $ raw =<< (liftIO . gqlApi =<< body)
+```
+
+If we now send a POST request to `http://localhost:3000/api` with a GraphQL Query as body for example in a tool like `Insomnia`:
+
+```GraphQL
+query GetDeity {
+  deity (name: "Morpheus") {
+    fullName
+    power
+  }
+}
+```
+
+our query will be resolved!
+
+```JSON
+{
+  "data": {
+    "deity": {
+      "fullName": "Morpheus",
+      "power": "Shapeshifting"
+    }
+  }
+}
+```
+
+## Serverless Example
+
+If you are interested in creating a `Morpheus GraphQL` API with `Serverless`, you should take a look at our example in this repository:
+[_Mythology API_](https://github.com/morpheusgraphql/mythology-api) it is our example project build with `Morpheus GraphQL` and `Serverless-Haskell`,
+where you can query different mythology characters with `GraphiQL`.
+
+Mythology API is deployed on : [_api.morpheusgraphql.com_](https://api.morpheusgraphql.com) where you can test it with `GraphiQL`
+
+![Mythology Api](./assets/img/mythology-api.png "mythology-api")
+
+## Advanced topics
+
+### Enums
+
+You can use Union Types as Enums, but they're not allowed to have any parameters.
+
+```haskell
+data City
+  = Athens
+  | Sparta
+  | Corinth
+  | Delphi
+  | Argos
+  deriving (Generic)
+
+instance GQLType City where
+  type KIND City = ENUM
+```
+
+### Union types
+
+To use union type, all you have to do is derive the `GQLType` class. Using GraphQL [_fragments_](https://graphql.org/learn/queries/#fragments), the arguments of each data constructor can be accessed from the GraphQL client.
+
+```haskell
+data Character
+  = DEITY Deity
+  | HUMAN Human
+  deriving (Generic)
+
+instance GQLType Character where
+  type KIND City = UNION
+```
+
+### Scalar types
+
+To use custom scalar types, you need to provide implementations for `parseValue` and `serialize` respectively.
+
+```haskell
+data Odd = Odd Int  deriving (Generic)
+
+instance GQLScalar Odd where
+  parseValue (Int x) = pure $ Odd (...  )
+  parseValue (String x) = pure $ Odd (...  )
+  serialize  (Odd value) = Int value
+
+instance GQLType Odd where
+  type KIND Odd = SCALAR
+```
+
+### Applicative and Monad instance
+
+The `Resolver` type has `Applicative` and `Monad` instances that can be used to compose resolvers.
+
+### Introspection
+
+Morpheus converts your schema to a GraphQL introspection automatically. You can use tools like `Insomnia` to take a
+look at the introspection and validate your schema.
+If you need a description for your GQLType inside of the introspection you can define the GQLType instance manually
+and provide an implementation for the `description` function:
+
+```haskell
+data Deity = Deity
+{ ...
+} deriving (Generic)
+
+instance GQLType Deity where
+  description = const "A supernatural being considered divine and sacred"
+```
+
+screenshots from `Insomnia`
+
+![alt text](./assets/img/introspection/spelling.png "spelling")
+![alt text](./assets/img/introspection/autocomplete.png "autocomplete")
+![alt text](./assets/img/introspection/type.png "type")
+
+### Mutations
+
+In addition to queries, Morpheus also supports mutations. The behave just like regular queries and are defined similarly:
+Just exchange deriving `GQLQuery` for `GQLMutation` and declare them separately at the `GQLRootResolver` definition
+
+```haskell
+newtype Mutation = Mutation
+  { createDeity :: Form -> IOMutRes Deity
+  } deriving (Generic)
+
+createDeityMutation :: Form -> IOMutRes Deity
+createDeityMutation = ...
+
+rootResolver :: GQLRootResolver IO Query Mutation ()
+rootResolver =
+  GQLRootResolver
+    { queryResolver = return Query {...}
+    , mutationResolver = return Mutation {
+       createDeity = createDeityMutation
+    }
+    , subscriptionResolver = return ()
+    }
+
+gqlApi :: ByteString -> IO ByteString
+gqlApi = interpreter rootResolver
+```
+
+### Subscriptions
+
+im morpheus subscription and mutation communicating with Events,
+`Event` consists with user defined `Channel` and `Content`.
+
+every subscription has own Channel by which will be triggered
+
+```haskell
+
+data Channel
+  = ChannelA
+  | ChannelB
+
+data Content
+  = ContentA Int
+  | ContentB Text
+
+newtype Query = Query
+  { deity :: () -> IORes Deity
+  } deriving (Generic)
+
+newtype Mutation = Mutation
+  { createDeity :: () -> IOMutRes Channel Content Deity
+  } deriving (Generic)
+
+newtype Subscription = Subscription
+  { newDeity :: () -> IOSubRes Channel Content Deity
+  } deriving (Generic)
+
+rootResolver :: GQLRootResolver IO Channel Content Query Mutation Subscription
+rootResolver =
+  GQLRootResolver
+    { queryResolver = return Query {deity = const fetchDeity}
+    , mutationResolver = return Mutation {createDeity}
+    , subscriptionResolver = return Subscription {newDeity}
+    }
+  where
+    fetchDeity = resolver $ dbDeity "" Nothing
+    createDeity _args = toMutResolver [Event {channels = [ChannelA], content = ContentA 1}] fetchDeity
+    newDeity _args = Event {channels = [ChannelA], content}
+      where
+        content (Event [ChannelA] (ContentA _value)) = resolver $ dbDeity "" Nothing -- resolve New State
+        content (Event [ChannelA] (ContentB value))  = resolver $ dbDeity value Nothing -- resolve New State
+        content _                                    = fetchDeity -- Resolve Old State
+```
+
+## Morpheus `GraphQL Client` with Template haskell QuasiQuotes
+
+```haskell
+defineByDocumentFile
+    "./schema.gql"
+  [gql|
+    query GetHero ($byRealm: Realm)
+      {
+        deity (realm:$byRealm) {
+          power
+          fullName
+        }
+      }
+  |]
+```
+
+will validate query and Generate:
+
+- response type `GetHero`, `Deity` with `Lens` Instances
+- input types: `GetHeroArgs` , `Realm`
+- instance for `Fetch` typeClass
+
+so that
+
+```haskell
+  fetchHero :: Args GetHero -> m (Either String GetHero)
+  fetchHero = fetch jsonRes args
+      where
+        args = GetHeroArgs {byRealm = Just Realm {owner = "Zeus", surface = Just 10}}
+        jsonRes :: ByteString -> m ByteString
+        jsonRes = <GraphQL APi>
+```
+
+resolves well typed response `GetHero`.
+
+except: `defineByDocumentFile` you can use:
+
+```haskell
+defineByIntrospectionFile "./introspection.json"
+```
+
+or
+
+`defineByIntrospection` where you can directly connect it to server
+
+## Morpheus CLI for Code Generating
+
+Generating dummy Morpheus Api from `schema.gql`
+
+```
+morpheus build src/schem.gql src/GQLApi.hs
+```
+
+this command will generate Haskell API and resolvers,
+resolvers will resolve default values for every object
+
+# About
+
+## The name
+
+_Morpheus_ is the greek god of sleep and dreams whose name comes from the greek word _μορφή_ meaning form or shape.
+He is said to be able to mimic different forms and GraphQL is good at doing exactly that: Transforming data in the shape
+of many different APIs.
+
+## Team
+
+Morpheus is written and maintained by [_nalchevanidze_](https://github.com/nalchevanidze)
+
+## Roadmap
+
+- Medium future:
+  - Stabilize API
+  - Specification-isomorphic introspection
+  - Specification-isomorphic error handling
+- Long term:
+  - Support all possible GQL features
+  - Performance optimization
diff --git a/assets/simple.gql b/assets/simple.gql
--- a/assets/simple.gql
+++ b/assets/simple.gql
@@ -4,6 +4,10 @@
   hero: Human!
 }
 
+interface MyInterface {
+    name: String
+}
+
 type Mutation {
   createDeity (deityName: [[[[[String!]]!]]], deityMythology: String): Deity!
   createCharacter (charRealm: Realm! , charMutID: String! ): Character!
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,34 @@
+## [0.2.2] - 30.08.2019
+
+### Fixed
+- Parser Supports GraphQL multiline comments
+- Morpheus GraphQL Client: Support GraphQL Alias
+- Support of GraphQL Interfaces on GraphQL Document:
+    ```gql
+    # simple.gql
+    interface Node {
+      nodeId: ID!
+    }
+
+    type SimpleType implements Node {
+      nodeId: ID!
+      name: String!
+    }
+    ```
+
+    morpheus compiler will read interfaces and validate implements.
+    template haskell will generate haskell types only for types not for interfaces.
+
+    haskell type from `simple.gql`:
+    ```haskell
+     data SimpleType = SimpleType {
+        nodeId :: ID!
+        name   :: Text!
+      }  deriving (Generic)
+    ```
+
+    at the time compiler does not validates field Arguments by interface
+
 ## [0.2.1] - 23.08.2019
 
 - assets are added to cabal source files
diff --git a/examples/Main.hs b/examples/Main.hs
--- a/examples/Main.hs
+++ b/examples/Main.hs
@@ -22,12 +22,11 @@
 import           Data.Morpheus.Types            (ScalarValue (..))
 import           Deprecated.API                 (Channel, Content, gqlRoot)
 import           Mythology.API                  (mythologyApi)
-import           TH.API                         (thApi)
-
 import qualified Network.Wai                    as Wai
 import qualified Network.Wai.Handler.Warp       as Warp
 import qualified Network.Wai.Handler.WebSockets as WaiWs
 import           Network.WebSockets             (defaultConnectionOptions)
+import           TH.API                         (thApi)
 import           Web.Scotty                     (body, file, get, post, raw, scottyApp)
 
 ioRes :: ByteString -> IO ByteString
@@ -42,8 +41,8 @@
     # Query Hero with Compile time Validation
     query GetUser ($userCoordinates: Coordinates!)
       {
-        user {
-           name
+        myUser: user {
+           boo3: name
            email
            address (coordinates: $userCoordinates ){
             city
diff --git a/examples/Subscription/SimpleSubscription.hs b/examples/Subscription/SimpleSubscription.hs
new file mode 100644
--- /dev/null
+++ b/examples/Subscription/SimpleSubscription.hs
@@ -0,0 +1,47 @@
+{-# LANGUAGE DeriveGeneric     #-}
+{-# LANGUAGE NamedFieldPuns    #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+module Subscription.SimpleSubscription where
+
+import           Data.Morpheus.Types       (Event (..), GQLRootResolver (..), IOMutRes, IORes, IOSubRes, resolver,
+                                            toMutResolver)
+import           Data.Text                 (Text)
+import           GHC.Generics              (Generic)
+import           Mythology.Character.Deity (Deity (..), dbDeity)
+
+data Channel
+  = ChannelA
+  | ChannelB
+
+data Content
+  = ContentA Int
+  | ContentB Text
+
+newtype Query = Query
+  { deity :: () -> IORes Deity
+  } deriving (Generic)
+
+newtype Mutation = Mutation
+  { createDeity :: () -> IOMutRes Channel Content Deity
+  } deriving (Generic)
+
+newtype Subscription = Subscription
+  { newDeity :: () -> IOSubRes Channel Content Deity
+  } deriving (Generic)
+
+rootResolver :: GQLRootResolver IO Channel Content Query Mutation Subscription
+rootResolver =
+  GQLRootResolver
+    { queryResolver = return Query {deity = const fetchDeity}
+    , mutationResolver = return Mutation {createDeity}
+    , subscriptionResolver = return Subscription {newDeity}
+    }
+  where
+    fetchDeity = resolver $ dbDeity "" Nothing
+    createDeity _args = toMutResolver [Event {channels = [ChannelA], content = ContentA 1}] fetchDeity
+    newDeity _args = Event {channels = [ChannelA], content}
+      where
+        content (Event [ChannelA] (ContentA _value)) = resolver $ dbDeity "" Nothing -- resolve New State
+        content (Event [ChannelA] (ContentB value))  = resolver $ dbDeity value Nothing -- resolve New State
+        content _                                    = fetchDeity -- Resolve Old State
diff --git a/examples/TH/API.hs b/examples/TH/API.hs
--- a/examples/TH/API.hs
+++ b/examples/TH/API.hs
@@ -16,7 +16,7 @@
 import           Data.Morpheus              (interpreter)
 import           Data.Morpheus.Document     (gqlDocument)
 import           Data.Morpheus.Kind         (SCALAR)
-import           Data.Morpheus.Types        (GQLRootResolver (..), GQLScalar (..), GQLType (..), IORes,
+import           Data.Morpheus.Types        (GQLRootResolver (..), GQLScalar (..), GQLType (..), ID, IORes,
                                              ScalarValue (..))
 
 newtype Euro =
@@ -37,6 +37,10 @@
     user : User!
   }
 
+
+  """
+    GraphQL Multiline Comment
+  """
   type User {
     name                                      : Text!
     email                                     : Text!
@@ -62,6 +66,16 @@
   input Coordinates {
     latitude  : Euro!
     longitude : [[UID!]]!
+  }
+
+  # simple.gql
+  interface Node {
+      nodeId: ID!
+  }
+
+  type SimpleType implements Node {
+    nodeId: ID!
+    interfaceName: String!
   }
 
   input UID {
diff --git a/morpheus-graphql.cabal b/morpheus-graphql.cabal
--- a/morpheus-graphql.cabal
+++ b/morpheus-graphql.cabal
@@ -2,10 +2,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 5dffd2e1cb2921b0bc958c61fb047928492b4b4ac933979f6f3cf12e5f2d49b9
+-- hash: e5802f5202e1f3d85dbcbbfa5bbeccbe45394f9039335d2315915df0cee9d49a
 
 name:           morpheus-graphql
-version:        0.2.1
+version:        0.2.2
 synopsis:       Morpheus GraphQL
 description:    Build GraphQL APIs with your favourite functional language!
 category:       web, graphql
@@ -24,6 +24,7 @@
     assets/pubsub.gql
     assets/simple.gql
     changelog.md
+    README.md
 data-files:
     test/Feature/Holistic/API.gql
     test/Feature/Holistic/arguments/nameConflict/query.gql
@@ -97,9 +98,13 @@
     test/Feature/Holistic/parsing/invalidNotNullOperator/response.json
     test/Feature/Holistic/parsing/missingCloseBrace/query.gql
     test/Feature/Holistic/parsing/missingCloseBrace/response.json
+    test/Feature/Holistic/parsing/multilineComments/query.gql
+    test/Feature/Holistic/parsing/multilineComments/response.json
     test/Feature/Holistic/parsing/notNullSpacing/query.gql
     test/Feature/Holistic/parsing/notNullSpacing/response.json
     test/Feature/Holistic/parsing/notNullSpacing/variables.json
+    test/Feature/Holistic/parsing/singleLineComments/query.gql
+    test/Feature/Holistic/parsing/singleLineComments/response.json
     test/Feature/Holistic/selection/AliasNameConflict/query.gql
     test/Feature/Holistic/selection/AliasNameConflict/response.json
     test/Feature/Holistic/selection/AliasResolve/query.gql
@@ -223,6 +228,7 @@
   other-modules:
       Data.Morpheus.Error.Arguments
       Data.Morpheus.Error.Client.Client
+      Data.Morpheus.Error.Document.Interface
       Data.Morpheus.Error.Fragment
       Data.Morpheus.Error.Input
       Data.Morpheus.Error.Internal
@@ -254,7 +260,6 @@
       Data.Morpheus.Parsing.Client.ParseMeta
       Data.Morpheus.Parsing.Client.Parser
       Data.Morpheus.Parsing.Document.DataType
-      Data.Morpheus.Parsing.Document.Parse
       Data.Morpheus.Parsing.Document.Parser
       Data.Morpheus.Parsing.Internal.Create
       Data.Morpheus.Parsing.Internal.Internal
@@ -300,15 +305,16 @@
       Data.Morpheus.Types.IO
       Data.Morpheus.Types.Resolver
       Data.Morpheus.Types.Types
-      Data.Morpheus.Validation.Arguments
-      Data.Morpheus.Validation.Fragment
-      Data.Morpheus.Validation.Input.Enum
-      Data.Morpheus.Validation.Input.Object
-      Data.Morpheus.Validation.Selection
-      Data.Morpheus.Validation.Utils.Selection
-      Data.Morpheus.Validation.Utils.Utils
-      Data.Morpheus.Validation.Validation
-      Data.Morpheus.Validation.Variable
+      Data.Morpheus.Validation.Document.Validation
+      Data.Morpheus.Validation.Internal.Utils
+      Data.Morpheus.Validation.Query.Arguments
+      Data.Morpheus.Validation.Query.Fragment
+      Data.Morpheus.Validation.Query.Input.Enum
+      Data.Morpheus.Validation.Query.Input.Object
+      Data.Morpheus.Validation.Query.Selection
+      Data.Morpheus.Validation.Query.Utils.Selection
+      Data.Morpheus.Validation.Query.Validation
+      Data.Morpheus.Validation.Query.Variable
       Paths_morpheus_graphql
   hs-source-dirs:
       src
@@ -344,6 +350,7 @@
       Mythology.Character.Deity
       Mythology.Character.Human
       Mythology.Place.Places
+      Subscription.SimpleSubscription
       TH.API
       TH.Simple
       Paths_morpheus_graphql
diff --git a/src/Data/Morpheus/Client.hs b/src/Data/Morpheus/Client.hs
--- a/src/Data/Morpheus/Client.hs
+++ b/src/Data/Morpheus/Client.hs
@@ -17,11 +17,11 @@
 import           Language.Haskell.TH
 import           Language.Haskell.TH.Quote
 
+import           Data.Morpheus.Document                  (parseFullGQLDocument)
 -- MORPHEUS
 import           Data.Morpheus.Execution.Client.Build    (defineQuery)
 import           Data.Morpheus.Execution.Client.Compile  (compileSyntax)
 import           Data.Morpheus.Execution.Client.Fetch    (Fetch (..))
-import           Data.Morpheus.Parsing.Document.Parse    (parseFullGQLDocument)
 import           Data.Morpheus.Parsing.JSONSchema.Parse  (decodeIntrospection)
 import           Data.Morpheus.Types.Internal.Data       (DataTypeLib)
 import           Data.Morpheus.Types.Internal.Validation (Validation)
diff --git a/src/Data/Morpheus/Document.hs b/src/Data/Morpheus/Document.hs
--- a/src/Data/Morpheus/Document.hs
+++ b/src/Data/Morpheus/Document.hs
@@ -5,19 +5,39 @@
   ( toGraphQLDocument
   , toMorpheusHaskellAPi
   , gqlDocument
+  , parseFullGQLDocument
   ) where
 
-import           Data.ByteString.Lazy.Char8               (ByteString, pack)
+import           Control.Monad                                ((>=>))
+import           Data.ByteString.Lazy.Char8                   (ByteString, pack)
+import           Data.Text                                    (Text)
+import qualified Data.Text.Lazy                               as LT (toStrict)
+import           Data.Text.Lazy.Encoding                      (decodeUtf8)
 import           Language.Haskell.TH.Quote
 
 --
 -- MORPHEUS
-import           Data.Morpheus.Execution.Document.Compile (compileDec, compileExp)
-import           Data.Morpheus.Execution.Server.Resolve   (RootResCon, fullSchema)
-import           Data.Morpheus.Parsing.Document.Parse     (parseGraphQLDocument)
-import           Data.Morpheus.Rendering.GQL              (renderGraphQLDocument)
-import           Data.Morpheus.Rendering.Haskell.Render   (renderHaskellDocument)
-import           Data.Morpheus.Types                      (GQLRootResolver)
+import           Data.Morpheus.Execution.Document.Compile     (compileDec, compileExp)
+import           Data.Morpheus.Execution.Server.Resolve       (RootResCon, fullSchema)
+import           Data.Morpheus.Rendering.GQL                  (renderGraphQLDocument)
+import           Data.Morpheus.Rendering.Haskell.Render       (renderHaskellDocument)
+import           Data.Morpheus.Types                          (GQLRootResolver)
+
+import           Data.Morpheus.Parsing.Document.Parser        (parseTypes)
+import           Data.Morpheus.Parsing.Internal.Create        (createDataTypeLib)
+import           Data.Morpheus.Schema.SchemaAPI               (defaultTypes)
+import           Data.Morpheus.Types.Internal.Data            (DataTypeLib)
+import           Data.Morpheus.Types.Internal.Validation      (Validation)
+import           Data.Morpheus.Validation.Document.Validation (validatePartialDocument)
+
+parseDocument :: Text -> Validation DataTypeLib
+parseDocument doc = parseTypes doc >>= validatePartialDocument >>= createDataTypeLib
+
+parseGraphQLDocument :: ByteString -> Validation DataTypeLib
+parseGraphQLDocument x = parseDocument (LT.toStrict $ decodeUtf8 x)
+
+parseFullGQLDocument :: ByteString -> Validation DataTypeLib
+parseFullGQLDocument = parseGraphQLDocument >=> defaultTypes
 
 -- | Generates schema.gql file from 'GQLRootResolver'
 toGraphQLDocument :: RootResCon m e c query mut sub => proxy (GQLRootResolver m e c query mut sub) -> ByteString
diff --git a/src/Data/Morpheus/Error/Document/Interface.hs b/src/Data/Morpheus/Error/Document/Interface.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Morpheus/Error/Document/Interface.hs
@@ -0,0 +1,35 @@
+{-# LANGUAGE NamedFieldPuns    #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+module Data.Morpheus.Error.Document.Interface
+  ( unknownInterface
+  , partialImplements
+  , ImplementsError(..)
+  ) where
+
+import           Data.Morpheus.Error.Utils               (globalErrorMessage)
+import           Data.Morpheus.Types.Internal.Base       (Key)
+import           Data.Morpheus.Types.Internal.Validation (GQLError (..), GQLErrors)
+import           Data.Semigroup                          ((<>))
+
+unknownInterface :: Key -> GQLErrors
+unknownInterface name = globalErrorMessage message
+  where
+    message = "Unknown Interface \"" <> name <> "\"."
+
+data ImplementsError
+  = UnexpectedType { expectedType :: Key
+                   , foundType    :: Key }
+  | UndefinedField
+
+partialImplements :: Key -> [(Key, Key, ImplementsError)] -> GQLErrors
+partialImplements name = map impError
+  where
+    impError (interfaceName, key, errorType) = GQLError {desc = message, positions = []}
+      where
+        message =
+          "type \"" <> name <> "\" implements Interface \"" <> interfaceName <> "\" Partially," <>
+          detailedMessage errorType
+        detailedMessage UnexpectedType {expectedType, foundType} =
+          " on key \"" <> key <> "\" expected type \"" <> expectedType <> "\" found \"" <> foundType <> "\"."
+        detailedMessage UndefinedField = " key \"" <> key <> "\" not found ."
diff --git a/src/Data/Morpheus/Execution/Client/Compile.hs b/src/Data/Morpheus/Execution/Client/Compile.hs
--- a/src/Data/Morpheus/Execution/Client/Compile.hs
+++ b/src/Data/Morpheus/Execution/Client/Compile.hs
@@ -17,13 +17,14 @@
 import qualified Data.Morpheus.Types.Internal.AST.Operation as O (Operation (..))
 import           Data.Morpheus.Types.Internal.Data          (DataTypeLib)
 import           Data.Morpheus.Types.IO                     (GQLRequest (..))
+
 --
 --  Morpheus
 import           Data.Morpheus.Types.Internal.DataD         (QueryD (..))
 import           Data.Morpheus.Types.Internal.Validation    (Validation)
 import           Data.Morpheus.Types.Types                  (GQLQueryRoot (..))
-import           Data.Morpheus.Validation.Utils.Utils       (VALIDATION_MODE (..))
-import           Data.Morpheus.Validation.Validation        (validateRequest)
+import           Data.Morpheus.Validation.Internal.Utils    (VALIDATION_MODE (..))
+import           Data.Morpheus.Validation.Query.Validation  (validateRequest)
 
 compileSyntax :: String -> Q Exp
 compileSyntax queryText =
diff --git a/src/Data/Morpheus/Execution/Client/Selection.hs b/src/Data/Morpheus/Execution/Client/Selection.hs
--- a/src/Data/Morpheus/Execution/Client/Selection.hs
+++ b/src/Data/Morpheus/Execution/Client/Selection.hs
@@ -13,7 +13,7 @@
 
 --
 -- MORPHEUS
-import           Data.Morpheus.Error.Internal               (internalUnknownTypeMessage)
+import           Data.Morpheus.Error.Utils                  (globalErrorMessage)
 import           Data.Morpheus.Types.Internal.AST.Operation (Operation (..), ValidOperation, Variable (..),
                                                              VariableDefinitions)
 import           Data.Morpheus.Types.Internal.AST.Selection (Selection (..), SelectionRec (..))
@@ -22,10 +22,10 @@
                                                              allDataTypes)
 import           Data.Morpheus.Types.Internal.DataD         (ConsD (..), FieldD (..), TypeD (..), gqlToHSWrappers)
 import           Data.Morpheus.Types.Internal.Validation    (GQLErrors, Validation)
-import           Data.Morpheus.Validation.Utils.Utils       (lookupType)
+import           Data.Morpheus.Validation.Internal.Utils    (lookupType)
 
 compileError :: Text -> GQLErrors
-compileError x = internalUnknownTypeMessage $ " \"" <> x <> "\" ;"
+compileError x = globalErrorMessage $ "Unhandled Compile Time Error: \"" <> x <> "\" ;"
 
 operationTypes :: DataTypeLib -> VariableDefinitions -> ValidOperation -> Validation ([TypeD], [TypeD])
 operationTypes lib variables = genOperation
@@ -92,11 +92,13 @@
         genFields datatype = mapM typeNameFromField
           where
             typeNameFromField :: (Text, Selection) -> Validation FieldD
-            typeNameFromField (key, _) = FieldD (unpack key) <$> wrType
-              where
-                wrType = do
-                  (newType, wrappers) <- fieldDataType datatype key
-                  pure $ gqlToHSWrappers wrappers (unpack $ typeFrom newType)
+            typeNameFromField (key, Selection {selectionRec = SelectionAlias {aliasFieldName}}) =
+              FieldD (unpack key) <$> lookupFieldType aliasFieldName
+            typeNameFromField (key, _) = FieldD (unpack key) <$> lookupFieldType key
+            ------------------------------------------------------------
+            lookupFieldType key = do
+              (newType, wrappers) <- fieldDataType datatype key
+              pure $ gqlToHSWrappers wrappers (unpack $ typeFrom newType)
     --------------------------------------------
     genRecordType name dataType selectionSet = do
       (con, subTypes) <- getCon name dataType selectionSet
@@ -105,14 +107,16 @@
     newFieldTypes parentType = fmap concat <$> mapM validateSelection
       where
         validateSelection :: (Text, Selection) -> Validation [TypeD]
-        validateSelection (key, Selection {selectionRec = SelectionSet selectionSet}) = do
-          datatype <- key `typeByField` parentType
-          genRecordType (typeFrom datatype) datatype selectionSet
         validateSelection (key, Selection {selectionRec = SelectionField}) =
           key `typeByField` parentType >>= buildSelField
           where
             buildSelField (Leaf x) = buildLeaf x
             buildSelField _        = Left $ compileError "Invalid schema Expected scalar"
+        validateSelection (key, Selection {selectionRec = SelectionSet selectionSet}) = do
+          datatype <- key `typeByField` parentType
+          genRecordType (typeFrom datatype) datatype selectionSet
+        validateSelection (_, selection@Selection {selectionRec = SelectionAlias {aliasFieldName, aliasSelection}}) =
+          validateSelection (aliasFieldName, selection {selectionRec = aliasSelection})
         validateSelection (key, Selection {selectionRec = UnionSelection unionSelections}) = do
           unionTypeName <- typeFrom <$> key `typeByField` parentType
           (tCons, subTypes) <- unzip <$> mapM getUnionType unionSelections
@@ -121,7 +125,6 @@
             getUnionType (typeKey, selSet) = do
               conDatatype <- getType lib typeKey
               getCon typeKey conDatatype selSet
-        validateSelection _ = pure []
 
 buildLeaf :: DataLeaf -> Validation [TypeD]
 buildLeaf (LeafEnum DataType {typeName, typeData}) =
diff --git a/src/Data/Morpheus/Execution/Document/Compile.hs b/src/Data/Morpheus/Execution/Document/Compile.hs
--- a/src/Data/Morpheus/Execution/Document/Compile.hs
+++ b/src/Data/Morpheus/Execution/Document/Compile.hs
@@ -7,24 +7,25 @@
   , compileDec
   ) where
 
-import qualified Data.Text                                as T (pack)
+import qualified Data.Text                                    as T (pack)
 import           Language.Haskell.TH
 
 --
 --  Morpheus
-import           Data.Morpheus.Error.Client.Client        (renderGQLErrors)
-import           Data.Morpheus.Execution.Document.Convert (renderTHTypes)
-import           Data.Morpheus.Execution.Document.Declare (declareTypes)
-import           Data.Morpheus.Parsing.Document.Parser    (parseTypes)
+import           Data.Morpheus.Error.Client.Client            (renderGQLErrors)
+import           Data.Morpheus.Execution.Document.Convert     (renderTHTypes)
+import           Data.Morpheus.Execution.Document.Declare     (declareTypes)
+import           Data.Morpheus.Parsing.Document.Parser        (parseTypes)
+import           Data.Morpheus.Validation.Document.Validation
 
 compileExp :: String -> Q Exp
 compileExp documentTXT =
-  case parseTypes (T.pack documentTXT) >>= renderTHTypes of
+  case parseTypes (T.pack documentTXT) >>= validatePartialDocument >>= renderTHTypes of
     Left errors -> fail (renderGQLErrors errors)
     Right root  -> [|root|]
 
 compileDec :: String -> Q [Dec]
 compileDec documentTXT =
-  case parseTypes (T.pack documentTXT) >>= renderTHTypes of
+  case parseTypes (T.pack documentTXT) >>= validatePartialDocument >>= renderTHTypes of
     Left errors -> fail (renderGQLErrors errors)
     Right root  -> declareTypes root
diff --git a/src/Data/Morpheus/Execution/Server/Resolve.hs b/src/Data/Morpheus/Execution/Server/Resolve.hs
--- a/src/Data/Morpheus/Execution/Server/Resolve.hs
+++ b/src/Data/Morpheus/Execution/Server/Resolve.hs
@@ -42,8 +42,8 @@
 import           Data.Morpheus.Types.Internal.Value                  (Value (..))
 import           Data.Morpheus.Types.IO                              (GQLRequest (..), GQLResponse (..))
 import           Data.Morpheus.Types.Resolver                        (GQLRootResolver (..))
-import           Data.Morpheus.Validation.Utils.Utils                (VALIDATION_MODE (..))
-import           Data.Morpheus.Validation.Validation                 (validateRequest)
+import           Data.Morpheus.Validation.Internal.Utils             (VALIDATION_MODE (..))
+import           Data.Morpheus.Validation.Query.Validation           (validateRequest)
 
 type EventCon event = Eq event
 
diff --git a/src/Data/Morpheus/Parsing/Document/DataType.hs b/src/Data/Morpheus/Parsing/Document/DataType.hs
--- a/src/Data/Morpheus/Parsing/Document/DataType.hs
+++ b/src/Data/Morpheus/Parsing/Document/DataType.hs
@@ -11,9 +11,10 @@
 import           Data.Morpheus.Parsing.Internal.Terms    (parseAssignment, parseMaybeTuple, parseNonNull,
                                                           parseWrappedType, pipeLiteral, qualifier, setOf,
                                                           spaceAndComments, token)
-import           Data.Morpheus.Types.Internal.Data       (DataArgument, DataFullType (..), DataOutputField, Key)
+import           Data.Morpheus.Types.Internal.Data       (DataArgument, DataFullType (..), DataOutputField, Key,
+                                                          RawDataType (..))
 import           Data.Text                               (Text)
-import           Text.Megaparsec                         (label, sepBy1, (<|>))
+import           Text.Megaparsec                         (label, sepBy1, some, (<|>))
 import           Text.Megaparsec.Char                    (char, space1, string)
 
 dataArgument :: Parser (Text, DataArgument)
@@ -33,39 +34,57 @@
 dataInputObject =
   label "inputObject" $ do
     typeName <- typeDef "input"
-    typeData <- inputEntries
+    typeData <- inputObjectEntries
     pure (typeName, InputObject $ createType typeName typeData)
+
+inputObjectEntries :: Parser [(Key, DataArgument)]
+inputObjectEntries = label "inputEntries" $ setOf entry
   where
-    inputEntries :: Parser [(Key, DataArgument)]
-    inputEntries = label "inputEntries" $ setOf entry
-      where
-        entry =
-          label "entry" $ do
-            ((fieldName, _), (wrappers, fieldType)) <- parseAssignment qualifier parseWrappedType
-            nonNull <- parseNonNull
-            return (fieldName, createField () fieldName (nonNull ++ wrappers, fieldType))
+    entry =
+      label "entry" $ do
+        ((fieldName, _), (wrappers, fieldType)) <- parseAssignment qualifier parseWrappedType
+        nonNull <- parseNonNull
+        return (fieldName, createField () fieldName (nonNull ++ wrappers, fieldType))
 
-dataObject :: Parser (Text, DataFullType)
+outputObjectEntries :: Parser [(Key, DataOutputField)]
+outputObjectEntries = label "entries" $ setOf entry
+  where
+    fieldWithArgs =
+      label "fieldWithArgs" $ do
+        (name, _) <- qualifier
+        args <- parseMaybeTuple dataArgument
+        return (name, args)
+    entry =
+      label "entry" $ do
+        ((fieldName, fieldArgs), (wrappers, fieldType)) <- parseAssignment fieldWithArgs parseWrappedType
+        nonNull <- parseNonNull
+        return (fieldName, createField fieldArgs fieldName (nonNull ++ wrappers, fieldType))
+
+dataObject :: Parser (Text, RawDataType)
 dataObject =
   label "object" $ do
     typeName <- typeDef "type"
-    typeData <- entries
-    pure (typeName, OutputObject $ createType typeName typeData)
+    interfaces <- maybeImplements
+    typeData <- outputObjectEntries
+    pure (typeName, Implements interfaces $ createType typeName typeData)
+
+maybeImplements :: Parser [Text]
+maybeImplements = implements <|> pure []
   where
-    entries :: Parser [(Key, DataOutputField)]
-    entries = label "entries" $ setOf entry
-      where
-        fieldWithArgs =
-          label "fieldWithArgs" $ do
-            (name, _) <- qualifier
-            args <- parseMaybeTuple dataArgument
-            return (name, args)
-        entry =
-          label "entry" $ do
-            ((fieldName, fieldArgs), (wrappers, fieldType)) <- parseAssignment fieldWithArgs parseWrappedType
-            nonNull <- parseNonNull
-            return (fieldName, createField fieldArgs fieldName (nonNull ++ wrappers, fieldType))
+    implements =
+      label "implements" $ do
+        _ <- string "implements"
+        space1
+        spaceAndComments
+        some token
 
+dataInterface :: Parser (Text, RawDataType)
+dataInterface =
+  label "interface" $ do
+    typeName <- typeDef "interface"
+    typeData <- outputObjectEntries
+    pure (typeName, Interface $ createType typeName typeData)
+
 dataScalar :: Parser (Text, DataFullType)
 dataScalar =
   label "scalar" $ do
@@ -91,5 +110,12 @@
   where
     unionsParser = token `sepBy1` pipeLiteral
 
-parseDataType :: Parser (Text, DataFullType)
-parseDataType = label "dataType" $ dataObject <|> dataInputObject <|> dataUnion <|> dataEnum <|> dataScalar
+parseFinalDataType :: Parser (Text, DataFullType)
+parseFinalDataType = label "dataType" $ dataInputObject <|> dataUnion <|> dataEnum <|> dataScalar
+
+parseDataType :: Parser (Text, RawDataType)
+parseDataType = label "dataType" $ dataInterface <|> dataObject <|> finalDataT
+  where
+    finalDataT = do
+      (name, datatype) <- parseFinalDataType
+      pure (name, FinalDataType datatype)
diff --git a/src/Data/Morpheus/Parsing/Document/Parse.hs b/src/Data/Morpheus/Parsing/Document/Parse.hs
deleted file mode 100644
--- a/src/Data/Morpheus/Parsing/Document/Parse.hs
+++ /dev/null
@@ -1,24 +0,0 @@
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE NamedFieldPuns   #-}
-
-module Data.Morpheus.Parsing.Document.Parse
-  ( parseGraphQLDocument
-  , parseFullGQLDocument
-  ) where
-
-import           Control.Monad                           ((>=>))
-import           Data.ByteString.Lazy.Char8              (ByteString)
-import qualified Data.Text.Lazy                          as LT (toStrict)
-import           Data.Text.Lazy.Encoding                 (decodeUtf8)
-
--- MORPHEUS
-import           Data.Morpheus.Parsing.Document.Parser   (parseDocument)
-import           Data.Morpheus.Schema.SchemaAPI          (defaultTypes)
-import           Data.Morpheus.Types.Internal.Data       (DataTypeLib)
-import           Data.Morpheus.Types.Internal.Validation (Validation)
-
-parseGraphQLDocument :: ByteString -> Validation DataTypeLib
-parseGraphQLDocument x = parseDocument (LT.toStrict $ decodeUtf8 x)
-
-parseFullGQLDocument :: ByteString -> Validation DataTypeLib
-parseFullGQLDocument = parseGraphQLDocument >=> defaultTypes
diff --git a/src/Data/Morpheus/Parsing/Document/Parser.hs b/src/Data/Morpheus/Parsing/Document/Parser.hs
--- a/src/Data/Morpheus/Parsing/Document/Parser.hs
+++ b/src/Data/Morpheus/Parsing/Document/Parser.hs
@@ -2,8 +2,7 @@
 {-# LANGUAGE OverloadedStrings #-}
 
 module Data.Morpheus.Parsing.Document.Parser
-  ( parseDocument
-  , parseTypes
+  ( parseTypes
   ) where
 
 import           Data.Text                               (Text)
@@ -11,13 +10,12 @@
 
 -- MORPHEUS
 import           Data.Morpheus.Parsing.Document.DataType (parseDataType)
-import           Data.Morpheus.Parsing.Internal.Create   (createDataTypeLib)
 import           Data.Morpheus.Parsing.Internal.Internal (processErrorBundle)
 import           Data.Morpheus.Parsing.Internal.Terms    (spaceAndComments)
-import           Data.Morpheus.Types.Internal.Data       (DataFullType, DataTypeLib)
+import           Data.Morpheus.Types.Internal.Data       (RawDataType)
 import           Data.Morpheus.Types.Internal.Validation (Validation)
 
-parseTypes :: Text -> Validation [(Text, DataFullType)]
+parseTypes :: Text -> Validation [(Text, RawDataType)]
 parseTypes doc =
   case parseDoc of
     Right root      -> Right root
@@ -28,16 +26,3 @@
       label "DocumentTypes" $ do
         spaceAndComments
         manyTill parseDataType eof
-
-parseDocument :: Text -> Validation DataTypeLib
-parseDocument doc =
-  case parseDoc of
-    Right root      -> Right root
-    Left parseError -> Left $ processErrorBundle parseError
-  where
-    parseDoc = runParser request "<input>" doc
-    request =
-      label "Document" $ do
-        spaceAndComments
-        dataTypes <- manyTill parseDataType eof
-        createDataTypeLib dataTypes
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
@@ -6,6 +6,7 @@
   , qualifier
   , variable
   , spaceAndComments
+  , spaceAndComments1
   , pipeLiteral
   -------------
   , setOf
@@ -59,10 +60,17 @@
     varName' <- token
     return (varName', position')
 
+spaceAndComments1 :: Parser ()
+spaceAndComments1 = space1 *> spaceAndComments
+
 spaceAndComments :: Parser ()
-spaceAndComments = space *> skipMany inlineComment *> space
+spaceAndComments = space *> skipMany (inlineComment <|> multilineComment) *> space
   where
     inlineComment = char '#' *> skipManyTill printChar newline *> space
+    ------------------------------------------------------------------------
+    multilineComment = multilineIndicator *> skipManyTill (printChar *> space <|> space) multilineIndicator *> space
+    --------------------
+    multilineIndicator = string "\"\"\""
 
 -- COMPLEX
 -----------------------------
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
@@ -9,13 +9,13 @@
 import           Data.Functor                               (($>))
 import           Data.Text                                  (Text)
 import           Text.Megaparsec                            (label, (<?>), (<|>))
-import           Text.Megaparsec.Char                       (space1, string)
+import           Text.Megaparsec.Char                       (string)
 
 --
 -- MORPHEUS
 import           Data.Morpheus.Parsing.Internal.Internal    (Parser, getLocation)
 import           Data.Morpheus.Parsing.Internal.Terms       (parseAssignment, parseMaybeTuple, parseNonNull,
-                                                             parseWrappedType, token, variable)
+                                                             parseWrappedType, spaceAndComments1, token, variable)
 import           Data.Morpheus.Parsing.Request.Body         (entries)
 import           Data.Morpheus.Types.Internal.AST.Operation (Operation (..), OperationKind (..), RawOperation,
                                                              Variable (..))
@@ -64,5 +64,5 @@
 parseOperationKind =
   label "operatorKind" $ do
     kind <- (string "query" $> QUERY) <|> (string "mutation" $> MUTATION) <|> (string "subscription" $> SUBSCRIPTION)
-    space1
+    spaceAndComments1
     return kind
diff --git a/src/Data/Morpheus/Parsing/Request/Value.hs b/src/Data/Morpheus/Parsing/Request/Value.hs
--- a/src/Data/Morpheus/Parsing/Request/Value.hs
+++ b/src/Data/Morpheus/Parsing/Request/Value.hs
@@ -9,23 +9,20 @@
 import           Data.Functor                            (($>))
 import           Data.Text                               (pack)
 import           Text.Megaparsec                         (anySingleBut, between, choice, label, many, sepBy, (<|>))
-import           Text.Megaparsec.Char                    (char, space, string)
+import           Text.Megaparsec.Char                    (char, string)
 import           Text.Megaparsec.Char.Lexer              (scientific)
 
 --
 -- MORPHEUS
 import           Data.Morpheus.Parsing.Internal.Internal (Parser)
-import           Data.Morpheus.Parsing.Internal.Terms    (parseAssignment, setOf, token)
+import           Data.Morpheus.Parsing.Internal.Terms    (parseAssignment, setOf, spaceAndComments, token)
 import           Data.Morpheus.Types.Internal.Value      (ScalarValue (..), Value (..), decodeScientific)
 
 parseValue :: Parser Value
 parseValue =
   label "value" $ do
-    value <-
-      valueNull <|> booleanValue <|> valueNumber <|> enumValue <|> stringValue <|>
-      objectValue <|>
-      listValue
-    space
+    value <- valueNull <|> booleanValue <|> valueNumber <|> enumValue <|> stringValue <|> objectValue <|> listValue
+    spaceAndComments
     return value
 
 valueNull :: Parser Value
@@ -43,7 +40,7 @@
 enumValue :: Parser Value
 enumValue = do
   enum <- Enum <$> token
-  space
+  spaceAndComments
   return enum
 
 escaped :: Parser Char
@@ -59,18 +56,16 @@
     escapeChar code replacement = char code >> return replacement
 
 stringValue :: Parser Value
-stringValue =
-  label "stringValue" $
-  Scalar . String . pack <$> between (char '"') (char '"') (many escaped)
+stringValue = label "stringValue" $ Scalar . String . pack <$> between (char '"') (char '"') (many escaped)
 
 listValue :: Parser Value
 listValue =
   label "listValue" $
   List <$>
   between
-    (char '[' *> space)
-    (char ']' *> space)
-    (parseValue `sepBy` (char ',' *> space))
+    (char '[' *> spaceAndComments)
+    (char ']' *> spaceAndComments)
+    (parseValue `sepBy` (char ',' *> spaceAndComments))
 
 objectValue :: Parser Value
 objectValue = label "objectValue" $ Object <$> setOf entry
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
@@ -10,6 +10,7 @@
 
 import           Data.Aeson                              (FromJSON (..), ToJSON (..), pairs, withObject, (.:?), (.=))
 import qualified Data.Aeson                              as Aeson (Value (..))
+import qualified Data.HashMap.Lazy                       as LH (toList)
 import           GHC.Generics                            (Generic)
 
 -- MORPHEUS
@@ -39,6 +40,14 @@
   = Data Value
   | Errors [JSONError]
   deriving (Show, Generic)
+
+instance FromJSON GQLResponse where
+  parseJSON (Aeson.Object hm) =
+    case LH.toList hm of
+      [("data", value)]   -> Data <$> parseJSON value
+      [("errors", value)] -> Errors <$> parseJSON value
+      _                   -> fail "Invalid GraphQL Response"
+  parseJSON _ = fail "Invalid GraphQL Response"
 
 instance ToJSON GQLResponse where
   toEncoding (Data _data)     = pairs $ "data" .= _data
diff --git a/src/Data/Morpheus/Types/Internal/Data.hs b/src/Data/Morpheus/Types/Internal/Data.hs
--- a/src/Data/Morpheus/Types/Internal/Data.hs
+++ b/src/Data/Morpheus/Types/Internal/Data.hs
@@ -25,6 +25,7 @@
   , DataValidator(..)
   , DataTypeKind(..)
   , DataFingerprint(..)
+  , RawDataType(..)
   , isTypeDefined
   , initTypeLib
   , defineType
@@ -127,6 +128,13 @@
   | EnumKind DataEnum
   | ObjectKind (DataObject a)
   | UnionKind DataUnion
+  deriving (Show)
+
+data RawDataType
+  = FinalDataType DataFullType
+  | Interface DataOutputObject
+  | Implements { implementsInterfaces :: [Key]
+               , unImplements         :: DataOutputObject }
   deriving (Show)
 
 data DataFullType
diff --git a/src/Data/Morpheus/Validation/Arguments.hs b/src/Data/Morpheus/Validation/Arguments.hs
deleted file mode 100644
--- a/src/Data/Morpheus/Validation/Arguments.hs
+++ /dev/null
@@ -1,146 +0,0 @@
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE TupleSections  #-}
-
-module Data.Morpheus.Validation.Arguments
-  ( validateArguments
-  ) where
-
-import           Data.Morpheus.Error.Arguments                 (argumentGotInvalidValue, argumentNameCollision,
-                                                                undefinedArgument, unknownArguments)
-import           Data.Morpheus.Error.Input                     (InputValidation, inputErrorMessage)
-import           Data.Morpheus.Error.Internal                  (internalUnknownTypeMessage)
-import           Data.Morpheus.Error.Variable                  (incompatibleVariableType, undefinedVariable)
-import           Data.Morpheus.Types.Internal.AST.Operation    (ValidVariables, Variable (..))
-import           Data.Morpheus.Types.Internal.AST.RawSelection (RawArgument (..), RawArguments, Reference (..))
-import           Data.Morpheus.Types.Internal.AST.Selection    (Argument (..), ArgumentOrigin (..), Arguments)
-import           Data.Morpheus.Types.Internal.Base             (EnhancedKey (..), Position)
-import           Data.Morpheus.Types.Internal.Data             (DataArgument, DataField (..), DataInputField,
-                                                                DataOutputField, DataTypeLib, DataTypeWrapper (..),
-                                                                isFieldNullable, showWrappedType)
-import           Data.Morpheus.Types.Internal.Validation       (Validation)
-import           Data.Morpheus.Types.Internal.Value            (Value (Null))
-import           Data.Morpheus.Validation.Input.Object         (validateInputValue)
-import           Data.Morpheus.Validation.Utils.Utils          (checkForUnknownKeys, checkNameCollision, getInputType)
-import           Data.Text                                     (Text)
-
-resolveArgumentVariables ::
-     Text
-  -> ValidVariables
-  -> DataOutputField
-  -> RawArguments
-  -> Validation Arguments
-resolveArgumentVariables operatorName variables DataField {fieldName, fieldArgs} =
-  mapM resolveVariable
-  where
-    resolveVariable :: (Text, RawArgument) -> Validation (Text, Argument)
-    resolveVariable (key, RawArgument argument) = pure (key, argument)
-    resolveVariable (key, VariableReference Reference { referenceName
-                                                      , referencePosition
-                                                      }) =
-      (key, ) . toArgument <$> lookupVar
-      where
-        toArgument argumentValue =
-          Argument
-            { argumentValue
-            , argumentOrigin = VARIABLE
-            , argumentPosition = referencePosition
-            }
-        stricter [] []                               = True
-        stricter (NonNullType:xs1) (NonNullType:xs2) = stricter xs1 xs2
-        stricter (NonNullType:xs1) xs2               = stricter xs1 xs2
-        stricter (ListType:xs1) (ListType:xs2)       = stricter xs1 xs2
-        stricter _ _                                 = False
-        lookupVar =
-          case lookup referenceName variables of
-            Nothing ->
-              Left $
-              undefinedVariable operatorName referencePosition referenceName
-            Just Variable {variableValue, variableType, variableTypeWrappers} ->
-              case lookup key fieldArgs of
-                Nothing ->
-                  Left $
-                  unknownArguments fieldName [EnhancedKey key referencePosition]
-                Just DataField {fieldType, fieldTypeWrappers} ->
-                  if variableType == fieldType &&
-                     stricter variableTypeWrappers fieldTypeWrappers
-                    then return variableValue
-                    else Left $
-                         incompatibleVariableType
-                           referenceName
-                           varSignature
-                           fieldSignature
-                           referencePosition
-                  where varSignature =
-                          showWrappedType variableTypeWrappers variableType
-                        fieldSignature =
-                          showWrappedType fieldTypeWrappers fieldType
-
-handleInputError :: Text -> Position -> InputValidation a -> Validation ()
-handleInputError key position' (Left error') =
-  Left $ argumentGotInvalidValue key (inputErrorMessage error') position'
-handleInputError _ _ _ = pure ()
-
-validateArgumentValue ::
-     DataTypeLib
-  -> DataField a
-  -> (Text, Argument)
-  -> Validation (Text, Argument)
-validateArgumentValue lib DataField {fieldType, fieldTypeWrappers} arg@(key, Argument { argumentValue
-                                                                                      , argumentPosition
-                                                                                      }) =
-  getInputType fieldType lib (internalUnknownTypeMessage fieldType) >>=
-  checkType >>
-  pure arg
-  where
-    checkType type' =
-      handleInputError
-        key
-        argumentPosition
-        (validateInputValue lib [] fieldTypeWrappers type' (key, argumentValue))
-
-validateArgument ::
-     DataTypeLib
-  -> Position
-  -> Arguments
-  -> (Text, DataArgument)
-  -> Validation (Text, Argument)
-validateArgument types argumentPosition requestArgs (key, arg) =
-  case lookup key requestArgs of
-    Nothing                                            -> handleNullable
-    Just argument@Argument {argumentOrigin = VARIABLE} -> pure (key, argument) -- Variables are already checked in Variable Validation
-    Just Argument {argumentValue = Null}               -> handleNullable
-    Just argument                                      -> validateArgumentValue types arg (key, argument)
-  where
-    handleNullable
-      | isFieldNullable arg =
-        pure
-          ( key
-          , Argument
-              {argumentValue = Null, argumentOrigin = INLINE, argumentPosition})
-      | otherwise = Left $ undefinedArgument (EnhancedKey key argumentPosition)
-
-checkForUnknownArguments ::
-     (Text, DataOutputField) -> Arguments -> Validation [(Text, DataInputField)]
-checkForUnknownArguments (key, DataField {fieldArgs}) args =
-  checkForUnknownKeys enhancedKeys fieldKeys argError >>
-  checkNameCollision enhancedKeys argumentNameCollision >>
-  pure fieldArgs
-  where
-    argError = unknownArguments key
-    enhancedKeys = map argToKey args
-    argToKey (key', Argument {argumentPosition}) =
-      EnhancedKey key' argumentPosition
-    fieldKeys = map fst fieldArgs
-
-validateArguments ::
-     DataTypeLib
-  -> Text
-  -> ValidVariables
-  -> (Text, DataOutputField)
-  -> Position
-  -> RawArguments
-  -> Validation Arguments
-validateArguments typeLib operatorName variables inputs pos rawArgs = do
-  args <- resolveArgumentVariables operatorName variables (snd inputs) rawArgs
-  dataArgs <- checkForUnknownArguments inputs args
-  mapM (validateArgument typeLib pos args) dataArgs
diff --git a/src/Data/Morpheus/Validation/Document/Validation.hs b/src/Data/Morpheus/Validation/Document/Validation.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Morpheus/Validation/Document/Validation.hs
@@ -0,0 +1,54 @@
+{-# LANGUAGE NamedFieldPuns #-}
+
+module Data.Morpheus.Validation.Document.Validation
+  ( validatePartialDocument
+  ) where
+
+import           Data.Maybe
+
+--
+-- Morpheus
+import           Data.Morpheus.Error.Document.Interface  (ImplementsError (..), partialImplements, unknownInterface)
+import           Data.Morpheus.Types.Internal.Base       (Location (..))
+import           Data.Morpheus.Types.Internal.Data       (DataField (..), DataFullType (..), DataOutputField,
+                                                          DataOutputObject, DataType (..), Key, RawDataType (..),
+                                                          showWrappedType)
+import           Data.Morpheus.Types.Internal.Validation (Validation)
+import           Data.Morpheus.Validation.Internal.Utils (isEqOrStricter)
+
+validatePartialDocument :: [(Key, RawDataType)] -> Validation [(Key, DataFullType)]
+validatePartialDocument lib = catMaybes <$> traverse validateType lib
+  where
+    validateType :: (Key, RawDataType) -> Validation (Maybe (Key, DataFullType))
+    validateType (name, FinalDataType x)              = pure $ Just (name, x)
+    validateType (name, Implements interfaces object) = asTuple name <$> object `mustImplement` interfaces
+    validateType _                                    = pure Nothing
+    -----------------------------------
+    asTuple name x = Just (name, x)
+    -----------------------------------
+    mustImplement :: DataOutputObject -> [Key] -> Validation DataFullType
+    mustImplement object interfaceKey = do
+      interface <- traverse getInterfaceByKey interfaceKey
+      case concatMap (mustBeSubset object) interface of
+        []     -> pure $ OutputObject object
+        errors -> Left $ partialImplements (typeName object)  errors
+    -------------------------------
+    mustBeSubset :: DataOutputObject -> DataOutputObject -> [(Key, Key, ImplementsError)]
+    mustBeSubset DataType {typeData = objFields} DataType {typeName, typeData = interfaceFields} =
+      concatMap checkField interfaceFields
+      where
+        checkField :: (Key, DataOutputField) -> [(Key, Key, ImplementsError)]
+        checkField (key, DataField {fieldType = interfaceTypeName, fieldTypeWrappers = interfaceWrappers}) =
+          case lookup key objFields of
+            Just DataField {fieldType, fieldTypeWrappers}
+              | fieldType == interfaceTypeName && isEqOrStricter fieldTypeWrappers interfaceWrappers -> []
+              | otherwise -> [(typeName, key, UnexpectedType {expectedType, foundType})]
+              where expectedType = showWrappedType interfaceWrappers interfaceTypeName
+                    foundType = showWrappedType fieldTypeWrappers fieldType
+            Nothing -> [(typeName, key, UndefinedField)]
+    -------------------------------
+    getInterfaceByKey :: Key -> Validation DataOutputObject
+    getInterfaceByKey key =
+      case lookup key lib of
+        Just (Interface x) -> pure x
+        _                  -> Left $ unknownInterface key
diff --git a/src/Data/Morpheus/Validation/Fragment.hs b/src/Data/Morpheus/Validation/Fragment.hs
deleted file mode 100644
--- a/src/Data/Morpheus/Validation/Fragment.hs
+++ /dev/null
@@ -1,127 +0,0 @@
-{-# LANGUAGE NamedFieldPuns #-}
-
-module Data.Morpheus.Validation.Fragment
-  ( validateFragments
-  , castFragmentType
-  , resolveSpread
-  , getFragment
-  ) where
-
-import           Data.List                                     ((\\))
-import           Data.Semigroup                                ((<>))
-import           Data.Text                                     (Text)
-import qualified Data.Text                                     as T (concat)
-
--- MORPHEUS
-import           Data.Morpheus.Error.Fragment                  (cannotBeSpreadOnType, cannotSpreadWithinItself,
-                                                                fragmentNameCollision, unknownFragment, unusedFragment)
-import           Data.Morpheus.Types.Internal.AST.RawSelection (Fragment (..), FragmentLib, RawSelection (..),
-                                                                RawSelection' (..), Reference (..))
-import           Data.Morpheus.Types.Internal.Base             (EnhancedKey (..), Position)
-import           Data.Morpheus.Types.Internal.Data             (DataTypeLib)
-import           Data.Morpheus.Types.Internal.Validation       (Validation)
-import           Data.Morpheus.Validation.Utils.Utils          (checkNameCollision, existsObjectType)
-
-validateFragments ::
-     DataTypeLib -> FragmentLib -> [(Text, RawSelection)] -> Validation ()
-validateFragments lib fragments operatorSel =
-  validateNameCollision >> checkLoop >> checkUnusedFragments
-  where
-    validateNameCollision =
-      checkNameCollision fragmentsKeys fragmentNameCollision
-    checkUnusedFragments =
-      case fragmentsKeys \\ usedFragments fragments operatorSel of
-        []     -> return ()
-        unused -> Left $ unusedFragment unused
-    checkLoop = mapM (validateFragment lib) fragments >>= detectLoopOnFragments
-    fragmentsKeys = map toEnhancedKey fragments
-      where
-        toEnhancedKey (key, Fragment {fragmentPosition}) =
-          EnhancedKey key fragmentPosition
-
-type Node = EnhancedKey
-
-type NodeEdges = (Node, [Node])
-
-type Graph = [NodeEdges]
-
-getFragment :: Reference -> FragmentLib -> Validation Fragment
-getFragment Reference {referenceName, referencePosition} lib =
-  case lookup referenceName lib of
-    Nothing       -> Left $ unknownFragment referenceName referencePosition
-    Just fragment -> pure fragment
-
-castFragmentType ::
-     Maybe Text -> Position -> [Text] -> Fragment -> Validation Fragment
-castFragmentType key' position' targets' fragment@Fragment {fragmentType} =
-  if fragmentType `elem` targets'
-    then pure fragment
-    else Left $
-         cannotBeSpreadOnType key' fragmentType position' (T.concat targets')
-
-resolveSpread :: FragmentLib -> [Text] -> Reference -> Validation Fragment
-resolveSpread fragments allowedTargets reference@Reference { referenceName
-                                                           , referencePosition
-                                                           } =
-  getFragment reference fragments >>=
-  castFragmentType (Just referenceName) referencePosition allowedTargets
-
-usedFragments :: FragmentLib -> [(Text, RawSelection)] -> [Node]
-usedFragments fragments = concatMap findAllUses
-  where
-    findAllUses :: (Text, RawSelection) -> [Node]
-    findAllUses (_, RawSelectionSet RawSelection' {rawSelectionRec}) =
-      concatMap findAllUses rawSelectionRec
-    findAllUses (_, RawAlias {rawAliasSelection}) =
-      concatMap findAllUses [rawAliasSelection]
-    findAllUses (_, InlineFragment Fragment {fragmentSelection}) =
-      concatMap findAllUses fragmentSelection
-    findAllUses (_, RawSelectionField {}) = []
-    findAllUses (_, Spread Reference {referenceName, referencePosition}) =
-      [EnhancedKey referenceName referencePosition] <> searchInFragment
-      where
-        searchInFragment =
-          maybe
-            []
-            (concatMap findAllUses . fragmentSelection)
-            (lookup referenceName fragments)
-
-scanForSpread :: (Text, RawSelection) -> [Node]
-scanForSpread (_, RawSelectionSet RawSelection' {rawSelectionRec = selection'}) =
-  concatMap scanForSpread selection'
-scanForSpread (_, RawAlias {rawAliasSelection = selection'}) =
-  concatMap scanForSpread [selection']
-scanForSpread (_, InlineFragment Fragment {fragmentSelection = selection'}) =
-  concatMap scanForSpread selection'
-scanForSpread (_, RawSelectionField {}) = []
-scanForSpread (_, Spread Reference { referenceName = name'
-                                   , referencePosition = position'
-                                   }) = [EnhancedKey name' position']
-
-validateFragment :: DataTypeLib -> (Text, Fragment) -> Validation NodeEdges
-validateFragment lib (fName, Fragment { fragmentSelection
-                                      , fragmentType
-                                      , fragmentPosition
-                                      }) =
-  existsObjectType fragmentPosition fragmentType lib >>
-  pure
-    ( EnhancedKey fName fragmentPosition
-    , concatMap scanForSpread fragmentSelection)
-
-detectLoopOnFragments :: Graph -> Validation ()
-detectLoopOnFragments lib = mapM_ checkFragment lib
-  where
-    checkFragment (fragmentID, _) = checkForCycle lib fragmentID [fragmentID]
-
-checkForCycle :: Graph -> Node -> [Node] -> Validation Graph
-checkForCycle lib parentNode history =
-  case lookup parentNode lib of
-    Just node -> concat <$> mapM 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 = Left $ cannotSpreadWithinItself $ history ++ [n]
diff --git a/src/Data/Morpheus/Validation/Input/Enum.hs b/src/Data/Morpheus/Validation/Input/Enum.hs
deleted file mode 100644
--- a/src/Data/Morpheus/Validation/Input/Enum.hs
+++ /dev/null
@@ -1,16 +0,0 @@
-{-# LANGUAGE TypeOperators #-}
-
-module Data.Morpheus.Validation.Input.Enum
-  ( validateEnum
-  ) where
-
-import           Data.List                          (elem)
-import           Data.Morpheus.Types.Internal.Value (Value (..))
-import           Data.Text                          (Text)
-
-validateEnum :: error -> [Text] -> Value -> Either error Value
-validateEnum error' tags' (Enum enumValue) =
-  if enumValue `elem` tags'
-    then pure (Enum enumValue)
-    else Left error'
-validateEnum error' _ _ = Left error'
diff --git a/src/Data/Morpheus/Validation/Input/Object.hs b/src/Data/Morpheus/Validation/Input/Object.hs
deleted file mode 100644
--- a/src/Data/Morpheus/Validation/Input/Object.hs
+++ /dev/null
@@ -1,97 +0,0 @@
-{-# LANGUAGE NamedFieldPuns    #-}
-{-# LANGUAGE OverloadedStrings #-}
-
-module Data.Morpheus.Validation.Input.Object
-  ( validateInputValue
-  ) where
-
-import           Data.Morpheus.Error.Input            (InputError (..), InputValidation, Prop (..))
-import           Data.Morpheus.Types.Internal.Data    (DataField (..), DataInputType, DataKind (..), DataType (..),
-                                                       DataTypeLib (..), DataTypeWrapper (..), DataValidator (..),
-                                                       showFullAstType)
-import           Data.Morpheus.Types.Internal.Value   (Value (..))
-import           Data.Morpheus.Validation.Input.Enum  (validateEnum)
-import           Data.Morpheus.Validation.Utils.Utils (getInputType, lookupField)
-import           Data.Text                            (Text)
-
-typeMismatch :: Value -> Text -> [Prop] -> InputError
-typeMismatch jsType expected' path' =
-  UnexpectedType path' expected' jsType Nothing
-
--- Validate Variable Argument or all Possible input Values
-validateInputValue ::
-     DataTypeLib
-  -> [Prop]
-  -> [DataTypeWrapper]
-  -> DataInputType
-  -> (Text, Value)
-  -> InputValidation Value
-validateInputValue lib' prop' = validate
-  where
-    throwError ::
-         [DataTypeWrapper] -> DataInputType -> Value -> InputValidation Value
-    throwError wrappers' type' value' =
-      Left $
-      UnexpectedType prop' (showFullAstType wrappers' type') value' Nothing
-    {-- VALIDATION --}
-    {-- 1. VALIDATE WRAPPERS -}
-    validate ::
-         [DataTypeWrapper]
-      -> DataInputType
-      -> (Text, Value)
-      -> InputValidation Value
-    -- throw error on not nullable type if value = null
-    validate (NonNullType:wrappers') type' (_, Null) =
-      throwError wrappers' type' Null
-    -- resolves nullable value as null
-    validate _ _ (_, Null) = return Null
-    -- ignores NonNUllTypes if value /= null
-    validate (NonNullType:wrappers') type' value' =
-      validateInputValue lib' prop' wrappers' type' value'
-    {-- VALIDATE LIST -}
-    validate (ListType:wrappers') type' (key', List list') =
-      List <$> mapM validateElement list'
-      where
-        validateElement element' =
-          validateInputValue lib' prop' wrappers' type' (key', element')
-    {-- 2. VALIDATE TYPES, all wrappers are already Processed --}
-    {-- VALIDATE OBJECT--}
-    validate [] (ObjectKind DataType {typeData = parentFields'}) (_, Object fields) =
-      Object <$> mapM validateField fields
-      where
-        validateField (_name, value') = do
-          (type', currentProp') <- validationData value'
-          wrappers' <- fieldTypeWrappers <$> getField
-          value'' <-
-            validateInputValue lib' currentProp' wrappers' type' (_name, value')
-          return (_name, value'')
-          where
-            validationData x = do
-              fieldTypeName' <- fieldType <$> getField
-              let currentProp = prop' ++ [Prop _name fieldTypeName']
-              type' <-
-                getInputType
-                  fieldTypeName'
-                  lib'
-                  (typeMismatch x fieldTypeName' currentProp)
-              return (type', currentProp)
-            getField =
-              lookupField _name parentFields' (UnknownField prop' _name)
-    -- VALIDATE INPUT UNION
-    -- TODO: Validate Union
-    validate [] (UnionKind DataType {typeData}) (_, Object fields) =
-      return (Object fields)
-    {-- VALIDATE SCALAR --}
-    validate [] (EnumKind DataType {typeData = tags', typeName = name'}) (_, value') =
-      validateEnum (UnexpectedType prop' name' value' Nothing) tags' value'
-    {-- VALIDATE ENUM --}
-    validate [] (ScalarKind DataType { typeName = name'
-                                     , typeData = DataValidator {validateValue = validator'}
-                                     }) (_, value') =
-      case validator' value' of
-        Right _ -> return value'
-        Left "" -> Left $ UnexpectedType prop' name' value' Nothing
-        Left errorMessage ->
-          Left $ UnexpectedType prop' name' value' (Just errorMessage)
-    {-- 3. THROW ERROR: on invalid values --}
-    validate wrappers' type' (_, value') = throwError wrappers' type' value'
diff --git a/src/Data/Morpheus/Validation/Internal/Utils.hs b/src/Data/Morpheus/Validation/Internal/Utils.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Morpheus/Validation/Internal/Utils.hs
@@ -0,0 +1,86 @@
+module Data.Morpheus.Validation.Internal.Utils
+  ( differKeys
+  , existsObjectType
+  , lookupType
+  , getInputType
+  , lookupField
+  , checkNameCollision
+  , checkForUnknownKeys
+  , isEqOrStricter
+  , VALIDATION_MODE(..)
+  ) where
+
+import           Data.List                               ((\\))
+import           Data.Morpheus.Error.Variable            (unknownType)
+import           Data.Morpheus.Types.Internal.Base       (EnhancedKey (..), Key, Position, enhanceKeyWithNull)
+import           Data.Morpheus.Types.Internal.Data       (DataInputType, DataKind (..), DataLeaf (..), DataOutputObject,
+                                                          DataTypeLib (..), DataTypeWrapper (..))
+import           Data.Morpheus.Types.Internal.Validation (Validation)
+import qualified Data.Set                                as S
+import           Data.Text                               (Text)
+
+type GenError error a = error -> Either error a
+
+data VALIDATION_MODE
+  = WITHOUT_VARIABLES
+  | FULL_VALIDATION
+  deriving (Eq, Show)
+
+lookupType :: error -> [(Text, a)] -> Text -> Either error a
+lookupType error' lib' typeName' =
+  case lookup typeName' lib' of
+    Nothing -> Left error'
+    Just x  -> pure x
+
+lookupField :: Text -> [(Text, fType)] -> GenError error fType
+lookupField id' lib' error' =
+  case lookup id' lib' of
+    Nothing    -> Left error'
+    Just field -> pure field
+
+getInputType :: Text -> DataTypeLib -> GenError error DataInputType
+getInputType typeName' lib error' =
+  case lookup typeName' (inputObject lib) of
+    Just x -> pure (ObjectKind x)
+    Nothing ->
+      case lookup typeName' (inputUnion lib) of
+        Just x -> pure (UnionKind x)
+        Nothing ->
+          case lookup typeName' (leaf lib) of
+            Nothing               -> Left error'
+            Just (BaseScalar x)   -> pure (ScalarKind x)
+            Just (CustomScalar x) -> pure (ScalarKind x)
+            Just (LeafEnum x)     -> pure (EnumKind x)
+
+existsObjectType :: Position -> Text -> DataTypeLib -> Validation DataOutputObject
+existsObjectType position' typeName' lib = lookupType error' (object lib) typeName'
+  where
+    error' = unknownType typeName' position'
+
+differKeys :: [EnhancedKey] -> [Key] -> [EnhancedKey]
+differKeys enhanced keys = enhanced \\ map enhanceKeyWithNull keys
+
+removeDuplicates :: Ord a => [a] -> [a]
+removeDuplicates = S.toList . S.fromList
+
+elementOfKeys :: [Text] -> EnhancedKey -> Bool
+elementOfKeys keys' EnhancedKey {uid = id'} = id' `elem` keys'
+
+checkNameCollision :: [EnhancedKey] -> ([EnhancedKey] -> error) -> Either error [EnhancedKey]
+checkNameCollision enhancedKeys errorGenerator =
+  case enhancedKeys \\ removeDuplicates enhancedKeys of
+    []         -> pure enhancedKeys
+    duplicates -> Left $ errorGenerator duplicates
+
+checkForUnknownKeys :: [EnhancedKey] -> [Text] -> ([EnhancedKey] -> error) -> Either error [EnhancedKey]
+checkForUnknownKeys enhancedKeys' keys' errorGenerator' =
+  case filter (not . elementOfKeys keys') enhancedKeys' of
+    []           -> pure enhancedKeys'
+    unknownKeys' -> Left $ errorGenerator' unknownKeys'
+
+isEqOrStricter :: [DataTypeWrapper] -> [DataTypeWrapper] -> Bool
+isEqOrStricter [] []                               = True
+isEqOrStricter (NonNullType:xs1) (NonNullType:xs2) = isEqOrStricter xs1 xs2
+isEqOrStricter (NonNullType:xs1) xs2               = isEqOrStricter xs1 xs2
+isEqOrStricter (ListType:xs1) (ListType:xs2)       = isEqOrStricter xs1 xs2
+isEqOrStricter _ _                                 = False
diff --git a/src/Data/Morpheus/Validation/Query/Arguments.hs b/src/Data/Morpheus/Validation/Query/Arguments.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Morpheus/Validation/Query/Arguments.hs
@@ -0,0 +1,94 @@
+{-# LANGUAGE NamedFieldPuns #-}
+{-# LANGUAGE TupleSections  #-}
+
+module Data.Morpheus.Validation.Query.Arguments
+  ( validateArguments
+  ) where
+
+import           Data.Morpheus.Error.Arguments                 (argumentGotInvalidValue, argumentNameCollision,
+                                                                undefinedArgument, unknownArguments)
+import           Data.Morpheus.Error.Input                     (InputValidation, inputErrorMessage)
+import           Data.Morpheus.Error.Internal                  (internalUnknownTypeMessage)
+import           Data.Morpheus.Error.Variable                  (incompatibleVariableType, undefinedVariable)
+import           Data.Morpheus.Types.Internal.AST.Operation    (ValidVariables, Variable (..))
+import           Data.Morpheus.Types.Internal.AST.RawSelection (RawArgument (..), RawArguments, Reference (..))
+import           Data.Morpheus.Types.Internal.AST.Selection    (Argument (..), ArgumentOrigin (..), Arguments)
+import           Data.Morpheus.Types.Internal.Base             (EnhancedKey (..), Position)
+import           Data.Morpheus.Types.Internal.Data             (DataArgument, DataField (..), DataInputField,
+                                                                DataOutputField, DataTypeLib, isFieldNullable,
+                                                                showWrappedType)
+import           Data.Morpheus.Types.Internal.Validation       (Validation)
+import           Data.Morpheus.Types.Internal.Value            (Value (Null))
+import           Data.Morpheus.Validation.Internal.Utils       (checkForUnknownKeys, checkNameCollision, getInputType,
+                                                                isEqOrStricter)
+import           Data.Morpheus.Validation.Query.Input.Object   (validateInputValue)
+import           Data.Text                                     (Text)
+
+resolveArgumentVariables :: Text -> ValidVariables -> DataOutputField -> RawArguments -> Validation Arguments
+resolveArgumentVariables operatorName variables DataField {fieldName, fieldArgs} = mapM resolveVariable
+  where
+    resolveVariable :: (Text, RawArgument) -> Validation (Text, Argument)
+    resolveVariable (key, RawArgument argument) = pure (key, argument)
+    resolveVariable (key, VariableReference Reference {referenceName, referencePosition}) =
+      (key, ) . toArgument <$> lookupVar
+      where
+        toArgument argumentValue =
+          Argument {argumentValue, argumentOrigin = VARIABLE, argumentPosition = referencePosition}
+        lookupVar =
+          case lookup referenceName variables of
+            Nothing -> Left $ undefinedVariable operatorName referencePosition referenceName
+            Just Variable {variableValue, variableType, variableTypeWrappers} ->
+              case lookup key fieldArgs of
+                Nothing -> Left $ unknownArguments fieldName [EnhancedKey key referencePosition]
+                Just DataField {fieldType, fieldTypeWrappers} ->
+                  if variableType == fieldType && isEqOrStricter variableTypeWrappers fieldTypeWrappers
+                    then return variableValue
+                    else Left $ incompatibleVariableType referenceName varSignature fieldSignature referencePosition
+                  where varSignature = showWrappedType variableTypeWrappers variableType
+                        fieldSignature = showWrappedType fieldTypeWrappers fieldType
+
+handleInputError :: Text -> Position -> InputValidation a -> Validation ()
+handleInputError key position' (Left error') = Left $ argumentGotInvalidValue key (inputErrorMessage error') position'
+handleInputError _ _ _                       = pure ()
+
+validateArgumentValue :: DataTypeLib -> DataField a -> (Text, Argument) -> Validation (Text, Argument)
+validateArgumentValue lib DataField {fieldType, fieldTypeWrappers} arg@(key, Argument {argumentValue, argumentPosition}) =
+  getInputType fieldType lib (internalUnknownTypeMessage fieldType) >>= checkType >> pure arg
+  where
+    checkType type' =
+      handleInputError key argumentPosition (validateInputValue lib [] fieldTypeWrappers type' (key, argumentValue))
+
+validateArgument :: DataTypeLib -> Position -> Arguments -> (Text, DataArgument) -> Validation (Text, Argument)
+validateArgument types argumentPosition requestArgs (key, arg) =
+  case lookup key requestArgs of
+    Nothing                                            -> handleNullable
+    Just argument@Argument {argumentOrigin = VARIABLE} -> pure (key, argument) -- Variables are already checked in Variable Validation
+    Just Argument {argumentValue = Null}               -> handleNullable
+    Just argument                                      -> validateArgumentValue types arg (key, argument)
+  where
+    handleNullable
+      | isFieldNullable arg = pure (key, Argument {argumentValue = Null, argumentOrigin = INLINE, argumentPosition})
+      | otherwise = Left $ undefinedArgument (EnhancedKey key argumentPosition)
+
+checkForUnknownArguments :: (Text, DataOutputField) -> Arguments -> Validation [(Text, DataInputField)]
+checkForUnknownArguments (key, DataField {fieldArgs}) args =
+  checkForUnknownKeys enhancedKeys fieldKeys argError >> checkNameCollision enhancedKeys argumentNameCollision >>
+  pure fieldArgs
+  where
+    argError = unknownArguments key
+    enhancedKeys = map argToKey args
+    argToKey (key', Argument {argumentPosition}) = EnhancedKey key' argumentPosition
+    fieldKeys = map fst fieldArgs
+
+validateArguments ::
+     DataTypeLib
+  -> Text
+  -> ValidVariables
+  -> (Text, DataOutputField)
+  -> Position
+  -> RawArguments
+  -> Validation Arguments
+validateArguments typeLib operatorName variables inputs pos rawArgs = do
+  args <- resolveArgumentVariables operatorName variables (snd inputs) rawArgs
+  dataArgs <- checkForUnknownArguments inputs args
+  mapM (validateArgument typeLib pos args) dataArgs
diff --git a/src/Data/Morpheus/Validation/Query/Fragment.hs b/src/Data/Morpheus/Validation/Query/Fragment.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Morpheus/Validation/Query/Fragment.hs
@@ -0,0 +1,102 @@
+{-# LANGUAGE NamedFieldPuns #-}
+
+module Data.Morpheus.Validation.Query.Fragment
+  ( validateFragments
+  , castFragmentType
+  , resolveSpread
+  , getFragment
+  ) where
+
+import           Data.List                                     ((\\))
+import           Data.Semigroup                                ((<>))
+import           Data.Text                                     (Text)
+import qualified Data.Text                                     as T (concat)
+
+-- MORPHEUS
+import           Data.Morpheus.Error.Fragment                  (cannotBeSpreadOnType, cannotSpreadWithinItself,
+                                                                fragmentNameCollision, unknownFragment, unusedFragment)
+import           Data.Morpheus.Types.Internal.AST.RawSelection (Fragment (..), FragmentLib, RawSelection (..),
+                                                                RawSelection' (..), Reference (..))
+import           Data.Morpheus.Types.Internal.Base             (EnhancedKey (..), Position)
+import           Data.Morpheus.Types.Internal.Data             (DataTypeLib)
+import           Data.Morpheus.Types.Internal.Validation       (Validation)
+import           Data.Morpheus.Validation.Internal.Utils       (checkNameCollision, existsObjectType)
+
+validateFragments :: DataTypeLib -> FragmentLib -> [(Text, RawSelection)] -> Validation ()
+validateFragments lib fragments operatorSel = validateNameCollision >> checkLoop >> checkUnusedFragments
+  where
+    validateNameCollision = checkNameCollision fragmentsKeys fragmentNameCollision
+    checkUnusedFragments =
+      case fragmentsKeys \\ usedFragments fragments operatorSel of
+        []     -> return ()
+        unused -> Left $ unusedFragment unused
+    checkLoop = mapM (validateFragment lib) fragments >>= detectLoopOnFragments
+    fragmentsKeys = map toEnhancedKey fragments
+      where
+        toEnhancedKey (key, Fragment {fragmentPosition}) = EnhancedKey key fragmentPosition
+
+type Node = EnhancedKey
+
+type NodeEdges = (Node, [Node])
+
+type Graph = [NodeEdges]
+
+getFragment :: Reference -> FragmentLib -> Validation Fragment
+getFragment Reference {referenceName, referencePosition} lib =
+  case lookup referenceName lib of
+    Nothing       -> Left $ unknownFragment referenceName referencePosition
+    Just fragment -> pure fragment
+
+castFragmentType :: Maybe Text -> Position -> [Text] -> Fragment -> Validation Fragment
+castFragmentType key' position' targets' fragment@Fragment {fragmentType} =
+  if fragmentType `elem` targets'
+    then pure fragment
+    else Left $ cannotBeSpreadOnType key' fragmentType position' (T.concat targets')
+
+resolveSpread :: FragmentLib -> [Text] -> Reference -> Validation Fragment
+resolveSpread fragments allowedTargets reference@Reference {referenceName, referencePosition} =
+  getFragment reference fragments >>= castFragmentType (Just referenceName) referencePosition allowedTargets
+
+usedFragments :: FragmentLib -> [(Text, RawSelection)] -> [Node]
+usedFragments fragments = concatMap findAllUses
+  where
+    findAllUses :: (Text, RawSelection) -> [Node]
+    findAllUses (_, RawSelectionSet RawSelection' {rawSelectionRec}) = concatMap findAllUses rawSelectionRec
+    findAllUses (_, RawAlias {rawAliasSelection}) = concatMap findAllUses [rawAliasSelection]
+    findAllUses (_, InlineFragment Fragment {fragmentSelection}) = concatMap findAllUses fragmentSelection
+    findAllUses (_, RawSelectionField {}) = []
+    findAllUses (_, Spread Reference {referenceName, referencePosition}) =
+      [EnhancedKey referenceName referencePosition] <> searchInFragment
+      where
+        searchInFragment = maybe [] (concatMap findAllUses . fragmentSelection) (lookup referenceName fragments)
+
+scanForSpread :: (Text, RawSelection) -> [Node]
+scanForSpread (_, RawSelectionSet RawSelection' {rawSelectionRec = selection'}) = concatMap scanForSpread selection'
+scanForSpread (_, RawAlias {rawAliasSelection = selection'}) = concatMap scanForSpread [selection']
+scanForSpread (_, InlineFragment Fragment {fragmentSelection = selection'}) = concatMap scanForSpread selection'
+scanForSpread (_, RawSelectionField {}) = []
+scanForSpread (_, Spread Reference {referenceName = name', referencePosition = position'}) =
+  [EnhancedKey name' position']
+
+validateFragment :: DataTypeLib -> (Text, Fragment) -> Validation NodeEdges
+validateFragment lib (fName, Fragment {fragmentSelection, fragmentType, fragmentPosition}) =
+  existsObjectType fragmentPosition fragmentType lib >>
+  pure (EnhancedKey fName fragmentPosition, concatMap scanForSpread fragmentSelection)
+
+detectLoopOnFragments :: Graph -> Validation ()
+detectLoopOnFragments lib = mapM_ checkFragment lib
+  where
+    checkFragment (fragmentID, _) = checkForCycle lib fragmentID [fragmentID]
+
+checkForCycle :: Graph -> Node -> [Node] -> Validation Graph
+checkForCycle lib parentNode history =
+  case lookup parentNode lib of
+    Just node -> concat <$> mapM 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 = Left $ cannotSpreadWithinItself $ history ++ [n]
diff --git a/src/Data/Morpheus/Validation/Query/Input/Enum.hs b/src/Data/Morpheus/Validation/Query/Input/Enum.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Morpheus/Validation/Query/Input/Enum.hs
@@ -0,0 +1,16 @@
+{-# LANGUAGE TypeOperators #-}
+
+module Data.Morpheus.Validation.Query.Input.Enum
+  ( validateEnum
+  ) where
+
+import           Data.List                          (elem)
+import           Data.Morpheus.Types.Internal.Value (Value (..))
+import           Data.Text                          (Text)
+
+validateEnum :: error -> [Text] -> Value -> Either error Value
+validateEnum error' tags' (Enum enumValue) =
+  if enumValue `elem` tags'
+    then pure (Enum enumValue)
+    else Left error'
+validateEnum error' _ _ = Left error'
diff --git a/src/Data/Morpheus/Validation/Query/Input/Object.hs b/src/Data/Morpheus/Validation/Query/Input/Object.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Morpheus/Validation/Query/Input/Object.hs
@@ -0,0 +1,70 @@
+{-# LANGUAGE NamedFieldPuns    #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+module Data.Morpheus.Validation.Query.Input.Object
+  ( validateInputValue
+  ) where
+
+import           Data.Morpheus.Error.Input                  (InputError (..), InputValidation, Prop (..))
+import           Data.Morpheus.Types.Internal.Data          (DataField (..), DataInputType, DataKind (..),
+                                                             DataType (..), DataTypeLib (..), DataTypeWrapper (..),
+                                                             DataValidator (..), showFullAstType)
+import           Data.Morpheus.Types.Internal.Value         (Value (..))
+import           Data.Morpheus.Validation.Query.Input.Enum  (validateEnum)
+import           Data.Morpheus.Validation.Internal.Utils (getInputType, lookupField)
+import           Data.Text                                  (Text)
+
+typeMismatch :: Value -> Text -> [Prop] -> InputError
+typeMismatch jsType expected' path' = UnexpectedType path' expected' jsType Nothing
+
+-- Validate Variable Argument or all Possible input Values
+validateInputValue ::
+     DataTypeLib -> [Prop] -> [DataTypeWrapper] -> DataInputType -> (Text, Value) -> InputValidation Value
+validateInputValue lib' prop' = validate
+  where
+    throwError :: [DataTypeWrapper] -> DataInputType -> Value -> InputValidation Value
+    throwError wrappers' type' value' = Left $ UnexpectedType prop' (showFullAstType wrappers' type') value' Nothing
+    {-- VALIDATION --}
+    {-- 1. VALIDATE WRAPPERS -}
+    validate :: [DataTypeWrapper] -> DataInputType -> (Text, Value) -> InputValidation Value
+    -- throw error on not nullable type if value = null
+    validate (NonNullType:wrappers') type' (_, Null) = throwError wrappers' type' Null
+    -- resolves nullable value as null
+    validate _ _ (_, Null) = return Null
+    -- ignores NonNUllTypes if value /= null
+    validate (NonNullType:wrappers') type' value' = validateInputValue lib' prop' wrappers' type' value'
+    {-- VALIDATE LIST -}
+    validate (ListType:wrappers') type' (key', List list') = List <$> mapM validateElement list'
+      where
+        validateElement element' = validateInputValue lib' prop' wrappers' type' (key', element')
+    {-- 2. VALIDATE TYPES, all wrappers are already Processed --}
+    {-- VALIDATE OBJECT--}
+    validate [] (ObjectKind DataType {typeData = parentFields'}) (_, Object fields) =
+      Object <$> mapM validateField fields
+      where
+        validateField (_name, value') = do
+          (type', currentProp') <- validationData value'
+          wrappers' <- fieldTypeWrappers <$> getField
+          value'' <- validateInputValue lib' currentProp' wrappers' type' (_name, value')
+          return (_name, value'')
+          where
+            validationData x = do
+              fieldTypeName' <- fieldType <$> getField
+              let currentProp = prop' ++ [Prop _name fieldTypeName']
+              type' <- getInputType fieldTypeName' lib' (typeMismatch x fieldTypeName' currentProp)
+              return (type', currentProp)
+            getField = lookupField _name parentFields' (UnknownField prop' _name)
+    -- VALIDATE INPUT UNION
+    -- TODO: Validate Union
+    validate [] (UnionKind DataType {typeData}) (_, Object fields) = return (Object fields)
+    {-- VALIDATE SCALAR --}
+    validate [] (EnumKind DataType {typeData = tags', typeName = name'}) (_, value') =
+      validateEnum (UnexpectedType prop' name' value' Nothing) tags' value'
+    {-- VALIDATE ENUM --}
+    validate [] (ScalarKind DataType {typeName = name', typeData = DataValidator {validateValue = validator'}}) (_, value') =
+      case validator' value' of
+        Right _           -> return value'
+        Left ""           -> Left $ UnexpectedType prop' name' value' Nothing
+        Left errorMessage -> Left $ UnexpectedType prop' name' value' (Just errorMessage)
+    {-- 3. THROW ERROR: on invalid values --}
+    validate wrappers' type' (_, value') = throwError wrappers' type' value'
diff --git a/src/Data/Morpheus/Validation/Query/Selection.hs b/src/Data/Morpheus/Validation/Query/Selection.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Morpheus/Validation/Query/Selection.hs
@@ -0,0 +1,178 @@
+{-# LANGUAGE FlexibleInstances   #-}
+{-# LANGUAGE NamedFieldPuns      #-}
+{-# LANGUAGE OverloadedStrings   #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeOperators       #-}
+
+module Data.Morpheus.Validation.Query.Selection
+  ( validateSelectionSet
+  ) where
+
+import           Data.Morpheus.Error.Selection                  (cannotQueryField, duplicateQuerySelections,
+                                                                 hasNoSubfields, subfieldsNotSelected)
+import           Data.Morpheus.Error.Variable                   (unknownType)
+import           Data.Morpheus.Types.Internal.AST.Operation     (ValidVariables)
+import           Data.Morpheus.Types.Internal.AST.RawSelection  (Fragment (..), FragmentLib, RawSelection (..),
+                                                                 RawSelection' (..), RawSelectionSet)
+import           Data.Morpheus.Types.Internal.AST.Selection     (Selection (..), SelectionRec (..), SelectionSet)
+import           Data.Morpheus.Types.Internal.Base              (EnhancedKey (..))
+import           Data.Morpheus.Types.Internal.Data              (DataField (..), DataFullType (..), DataOutputObject,
+                                                                 DataType (..), DataTypeLib (..), allDataTypes)
+import           Data.Morpheus.Types.Internal.Validation        (Validation)
+import           Data.Morpheus.Validation.Internal.Utils        (checkNameCollision, lookupType)
+import           Data.Morpheus.Validation.Query.Arguments       (validateArguments)
+import           Data.Morpheus.Validation.Query.Fragment        (castFragmentType, resolveSpread)
+import           Data.Morpheus.Validation.Query.Utils.Selection (lookupFieldAsSelectionSet, lookupSelectionField,
+                                                                 lookupUnionTypes)
+import           Data.Text                                      (Text)
+
+checkDuplicatesOn :: DataOutputObject -> SelectionSet -> Validation SelectionSet
+checkDuplicatesOn DataType {typeName = name'} keys = checkNameCollision enhancedKeys selError >> pure keys
+  where
+    selError = duplicateQuerySelections name'
+    enhancedKeys = map selToKey keys
+    selToKey (key', Selection {selectionPosition = position'}) = EnhancedKey key' position'
+
+clusterUnionSelection ::
+     FragmentLib -> Text -> [DataOutputObject] -> (Text, RawSelection) -> Validation ([Fragment], SelectionSet)
+clusterUnionSelection fragments type' possibleTypes' = splitFrag
+  where
+    packFragment fragment = return ([fragment], [])
+    typeNames = map typeName possibleTypes'
+    splitFrag :: (Text, RawSelection) -> Validation ([Fragment], SelectionSet)
+    splitFrag (_, Spread ref) = resolveSpread fragments typeNames ref >>= packFragment
+    splitFrag ("__typename", RawSelectionField RawSelection' {rawSelectionPosition = position'}) =
+      return
+        ( []
+        , [ ( "__typename"
+            , Selection {selectionRec = SelectionField, selectionArguments = [], selectionPosition = position'})
+          ])
+    splitFrag (key, RawSelectionSet RawSelection' {rawSelectionPosition}) =
+      Left $ cannotQueryField key type' rawSelectionPosition
+    splitFrag (key, RawSelectionField RawSelection' {rawSelectionPosition}) =
+      Left $ cannotQueryField key type' rawSelectionPosition
+    splitFrag (key', RawAlias {rawAliasPosition = position'}) = Left $ cannotQueryField key' type' position'
+    splitFrag (_, InlineFragment fragment') =
+      castFragmentType Nothing (fragmentPosition fragment') typeNames fragment' >>= packFragment
+
+categorizeTypes :: [DataOutputObject] -> [Fragment] -> [(DataOutputObject, [Fragment])]
+categorizeTypes types fragments = filter notEmpty $ map categorizeType types
+  where
+    notEmpty = (0 /=) . length . snd
+    categorizeType :: DataOutputObject -> (DataOutputObject, [Fragment])
+    categorizeType datatype = (datatype, filter matches fragments)
+      where
+        matches fragment = fragmentType fragment == typeName datatype
+
+flatTuple :: [([a], [b])] -> ([a], [b])
+flatTuple list' = (concatMap fst list', concatMap snd list')
+ {-
+    - all Variable and Fragment references will be: resolved and validated
+    - unionTypes: will be clustered under type names
+      ...A on T1 {<SelectionA>}
+      ...B on T2 {<SelectionB>}
+      ...C on T2 {<SelectionC>}
+      will be become : [
+          ("T1",[<SelectionA>]),
+          ("T2",[<SelectionB>,<SelectionC>])
+      ]
+ -}
+
+validateSelectionSet ::
+     DataTypeLib
+  -> FragmentLib
+  -> Text
+  -> ValidVariables
+  -> DataOutputObject
+  -> RawSelectionSet
+  -> Validation SelectionSet
+validateSelectionSet lib fragments' operatorName variables = __validate
+  where
+    __validate dataType'@DataType {typeName = typeName'} selectionSet' =
+      concat <$> mapM validateSelection selectionSet' >>= checkDuplicatesOn dataType'
+      where
+        validateFragment Fragment {fragmentSelection = selection'} = __validate dataType' selection'
+        {-
+            get dataField and validated arguments for RawSelection
+        -}
+        getValidationData key RawSelection' {rawSelectionArguments, rawSelectionPosition} = do
+          selectionField <- lookupSelectionField rawSelectionPosition key dataType'
+          -- validate field Argument -----
+          arguments <-
+            validateArguments
+              lib
+              operatorName
+              variables
+              (key, selectionField)
+              rawSelectionPosition
+              rawSelectionArguments
+          -- check field Type existence  -----
+          fieldDataType <-
+            lookupType
+              (unknownType (fieldType selectionField) rawSelectionPosition)
+              (allDataTypes lib)
+              (fieldType selectionField)
+          return (selectionField, fieldDataType, arguments)
+        -- validate single selection: InlineFragments and Spreads will Be resolved and included in SelectionSet
+        --
+        validateSelection :: (Text, RawSelection) -> Validation SelectionSet
+        validateSelection (key', RawAlias {rawAliasSelection = rawSelection', rawAliasPosition = position'}) =
+          fmap processSingleSelection <$> validateSelection rawSelection'
+          where
+            processSingleSelection (selKey', selection') =
+              ( key'
+              , selection'
+                  { selectionRec = SelectionAlias {aliasFieldName = selKey', aliasSelection = selectionRec selection'}
+                  , selectionPosition = position'
+                  })
+        validateSelection (key', RawSelectionSet fullRawSelection'@RawSelection' { rawSelectionRec = rawSelectors
+                                                                                 , rawSelectionPosition = position'
+                                                                                 }) = do
+          (dataField', dataType, arguments) <- getValidationData key' fullRawSelection'
+          case dataType of
+            Union _ -> do
+              (categories, __typename) <- clusterTypes
+              mapM (validateCluster __typename) categories >>= returnSelection arguments . UnionSelection
+              where clusterTypes = do
+                      unionTypes <- lookupUnionTypes position' key' lib dataField'
+                      (spreads, __typename) <-
+                        flatTuple <$> mapM (clusterUnionSelection fragments' typeName' unionTypes) rawSelectors
+                      return (categorizeTypes unionTypes spreads, __typename)
+                    --
+                    --    second arguments will be added to every selection cluster
+                    validateCluster :: SelectionSet -> (DataOutputObject, [Fragment]) -> Validation (Text, SelectionSet)
+                    validateCluster sysSelection' (type', frags') = do
+                      selection' <- __validate type' (concatMap fragmentSelection frags')
+                      return (typeName type', sysSelection' ++ selection')
+            OutputObject _ -> do
+              fieldType' <- lookupFieldAsSelectionSet position' key' lib dataField'
+              __validate fieldType' rawSelectors >>= returnSelection arguments . SelectionSet
+                 -- DataFullType
+                       --   = Leaf DataLeaf
+                       --   | InputObject DataInputObject
+                       --   | InputUnion DataUnion
+            _ -> Left $ hasNoSubfields key' (fieldType dataField') position'
+          where
+            returnSelection arguments' selection' =
+              pure
+                [ ( key'
+                  , Selection
+                      {selectionArguments = arguments', selectionRec = selection', selectionPosition = position'})
+                ]
+        validateSelection (key', RawSelectionField fullRawSelection'@RawSelection' {rawSelectionPosition}) = do
+          (dataField, datatype, arguments') <- getValidationData key' fullRawSelection'
+          isLeaf datatype dataField
+          pure
+            [ ( key'
+              , Selection
+                  { selectionArguments = arguments'
+                  , selectionRec = SelectionField
+                  , selectionPosition = rawSelectionPosition
+                  })
+            ]
+          where
+            isLeaf (Leaf _) _              = Right ()
+            isLeaf _ DataField {fieldType} = Left $ subfieldsNotSelected key' fieldType rawSelectionPosition
+        validateSelection (_, Spread reference') = resolveSpread fragments' [typeName'] reference' >>= validateFragment
+        validateSelection (_, InlineFragment fragment') =
+          castFragmentType Nothing (fragmentPosition fragment') [typeName'] fragment' >>= validateFragment
diff --git a/src/Data/Morpheus/Validation/Query/Utils/Selection.hs b/src/Data/Morpheus/Validation/Query/Utils/Selection.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Morpheus/Validation/Query/Utils/Selection.hs
@@ -0,0 +1,29 @@
+module Data.Morpheus.Validation.Query.Utils.Selection
+  ( lookupFieldAsSelectionSet
+  , lookupSelectionField
+  , lookupUnionTypes
+  ) where
+
+import           Data.Morpheus.Error.Selection           (cannotQueryField, hasNoSubfields)
+import           Data.Morpheus.Types.Internal.Base       (Position)
+import           Data.Morpheus.Types.Internal.Data       (DataField (..), DataOutputField, DataOutputObject,
+                                                          DataType (..), DataTypeLib (..))
+import           Data.Morpheus.Types.Internal.Validation (Validation)
+import           Data.Morpheus.Validation.Internal.Utils (lookupField, lookupType)
+import           Data.Text                               (Text)
+
+lookupUnionTypes :: Position -> Text -> DataTypeLib -> DataOutputField -> Validation [DataOutputObject]
+lookupUnionTypes position' key' lib' DataField {fieldType = type'} =
+  lookupType error' (union lib') type' >>= mapM (lookupType error' (object lib') . fieldType) . typeData
+  where
+    error' = hasNoSubfields key' type' position'
+
+lookupFieldAsSelectionSet :: Position -> Text -> DataTypeLib -> DataOutputField -> Validation DataOutputObject
+lookupFieldAsSelectionSet position' key' lib' DataField {fieldType = type'} = lookupType error' (object lib') type'
+  where
+    error' = hasNoSubfields key' type' position'
+
+lookupSelectionField :: Position -> Text -> DataOutputObject -> Validation DataOutputField
+lookupSelectionField position' key' DataType {typeData = fields', typeName = name'} = lookupField key' fields' error'
+  where
+    error' = cannotQueryField key' name' position'
diff --git a/src/Data/Morpheus/Validation/Query/Validation.hs b/src/Data/Morpheus/Validation/Query/Validation.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Morpheus/Validation/Query/Validation.hs
@@ -0,0 +1,47 @@
+{-# LANGUAGE FlexibleInstances   #-}
+{-# LANGUAGE NamedFieldPuns      #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeOperators       #-}
+
+module Data.Morpheus.Validation.Query.Validation
+  ( validateRequest
+  ) where
+
+import           Data.Map                                   (fromList)
+import           Data.Morpheus.Error.Mutation               (mutationIsNotDefined)
+import           Data.Morpheus.Error.Subscription           (subscriptionIsNotDefined)
+import           Data.Morpheus.Types.Internal.AST.Operation (Operation (..), OperationKind (..), RawOperation,
+                                                             ValidOperation)
+import           Data.Morpheus.Types.Internal.Data          (DataOutputObject, DataTypeLib (..))
+import           Data.Morpheus.Types.Internal.Validation    (Validation)
+import           Data.Morpheus.Types.Types                  (GQLQueryRoot (..))
+import           Data.Morpheus.Validation.Internal.Utils    (VALIDATION_MODE)
+import           Data.Morpheus.Validation.Query.Fragment    (validateFragments)
+import           Data.Morpheus.Validation.Query.Selection   (validateSelectionSet)
+import           Data.Morpheus.Validation.Query.Variable    (resolveOperationVariables)
+
+getOperationDataType :: RawOperation -> DataTypeLib -> Validation DataOutputObject
+getOperationDataType Operation {operationKind = QUERY} lib = pure $ snd $ query lib
+getOperationDataType Operation {operationKind = MUTATION, operationPosition} lib =
+  case mutation lib of
+    Just (_, mutation') -> pure mutation'
+    Nothing             -> Left $ mutationIsNotDefined operationPosition
+getOperationDataType Operation {operationKind = SUBSCRIPTION, operationPosition} lib =
+  case subscription lib of
+    Just (_, subscription') -> pure subscription'
+    Nothing                 -> Left $ subscriptionIsNotDefined operationPosition
+
+validateRequest :: DataTypeLib -> VALIDATION_MODE -> GQLQueryRoot -> Validation ValidOperation
+validateRequest lib validationMode GQLQueryRoot { fragments
+                                                , inputVariables
+                                                , operation = rawOperation@Operation { operationName
+                                                                                     , operationKind
+                                                                                     , operationSelection
+                                                                                     , operationPosition
+                                                                                     }
+                                                } = do
+  operationDataType <- getOperationDataType rawOperation lib
+  variables <- resolveOperationVariables lib fragments (fromList inputVariables) validationMode rawOperation
+  validateFragments lib fragments operationSelection
+  selection <- validateSelectionSet lib fragments operationName variables operationDataType operationSelection
+  pure $ Operation {operationName, operationKind, operationArgs = [], operationSelection = selection, operationPosition}
diff --git a/src/Data/Morpheus/Validation/Query/Variable.hs b/src/Data/Morpheus/Validation/Query/Variable.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Morpheus/Validation/Query/Variable.hs
@@ -0,0 +1,101 @@
+{-# LANGUAGE NamedFieldPuns #-}
+
+module Data.Morpheus.Validation.Query.Variable
+  ( resolveOperationVariables
+  ) where
+
+import           Data.List                                     ((\\))
+import qualified Data.Map                                      as M (lookup)
+import           Data.Maybe                                    (maybe)
+import           Data.Morpheus.Error.Input                     (InputValidation, inputErrorMessage)
+import           Data.Morpheus.Error.Variable                  (uninitializedVariable, unknownType, unusedVariables,
+                                                                variableGotInvalidValue)
+import           Data.Morpheus.Types.Internal.AST.Operation    (Operation (..), RawOperation, ValidVariables,
+                                                                Variable (..))
+import           Data.Morpheus.Types.Internal.AST.RawSelection (Fragment (..), FragmentLib, RawArgument (..),
+                                                                RawSelection (..), RawSelection' (..), RawSelectionSet,
+                                                                Reference (..))
+import           Data.Morpheus.Types.Internal.Base             (EnhancedKey (..), Position)
+import           Data.Morpheus.Types.Internal.Data             (DataInputType, DataTypeLib)
+import           Data.Morpheus.Types.Internal.Validation       (Validation)
+import           Data.Morpheus.Types.Internal.Value            (Value (..))
+import           Data.Morpheus.Types.Types                     (Variables)
+import           Data.Morpheus.Validation.Internal.Utils       (VALIDATION_MODE (..), getInputType)
+import           Data.Morpheus.Validation.Query.Fragment       (getFragment)
+import           Data.Morpheus.Validation.Query.Input.Object   (validateInputValue)
+import           Data.Semigroup                                ((<>))
+import           Data.Text                                     (Text)
+
+getVariableType :: Text -> Position -> DataTypeLib -> Validation DataInputType
+getVariableType type' position' lib' = getInputType type' lib' error'
+  where
+    error' = unknownType type' position'
+
+lookupVariable :: Variables -> Text -> (Text -> error) -> Either error Value
+lookupVariable variables' key' error' =
+  case M.lookup key' variables' of
+    Nothing    -> Left $ error' key'
+    Just value -> pure value
+
+handleInputError :: Text -> Position -> InputValidation Value -> Validation (Text, Value)
+handleInputError key' position' (Left error') = Left $ variableGotInvalidValue key' (inputErrorMessage error') position'
+handleInputError key' _ (Right value') = pure (key', value')
+
+concatMapM :: Monad m => (a -> m [b]) -> [a] -> m [b]
+concatMapM f = fmap concat . mapM f
+
+allVariableReferences :: FragmentLib -> [RawSelectionSet] -> Validation [EnhancedKey]
+allVariableReferences fragmentLib = concatMapM (concatMapM searchReferences)
+  where
+    referencesFromArgument :: (Text, RawArgument) -> [EnhancedKey]
+    referencesFromArgument (_, RawArgument {}) = []
+    referencesFromArgument (_, VariableReference Reference {referenceName, referencePosition}) =
+      [EnhancedKey referenceName referencePosition]
+    -- | search used variables in every arguments
+    searchReferences :: (Text, RawSelection) -> Validation [EnhancedKey]
+    searchReferences (_, RawSelectionSet RawSelection' {rawSelectionArguments, rawSelectionRec}) =
+      getArgs <$> concatMapM searchReferences rawSelectionRec
+      where
+        getArgs :: [EnhancedKey] -> [EnhancedKey]
+        getArgs x = concatMap referencesFromArgument rawSelectionArguments <> x
+    searchReferences (_, InlineFragment Fragment {fragmentSelection}) = concatMapM searchReferences fragmentSelection
+    searchReferences (_, RawAlias {rawAliasSelection}) = searchReferences rawAliasSelection
+    searchReferences (_, RawSelectionField RawSelection' {rawSelectionArguments}) =
+      return $ concatMap referencesFromArgument rawSelectionArguments
+    searchReferences (_, Spread reference) =
+      getFragment reference fragmentLib >>= concatMapM searchReferences . fragmentSelection
+
+resolveOperationVariables ::
+     DataTypeLib -> FragmentLib -> Variables -> VALIDATION_MODE -> RawOperation -> Validation ValidVariables
+resolveOperationVariables typeLib lib root validationMode Operation {operationName, operationSelection, operationArgs} = do
+  allVariableReferences lib [operationSelection] >>= checkUnusedVariables
+  mapM (lookupAndValidateValueOnBody typeLib root validationMode) operationArgs
+  where
+    varToKey :: (Text, Variable ()) -> EnhancedKey
+    varToKey (key', Variable {variablePosition}) = EnhancedKey key' variablePosition
+    --
+    checkUnusedVariables :: [EnhancedKey] -> Validation ()
+    checkUnusedVariables refs =
+      case map varToKey operationArgs \\ refs of
+        []      -> pure ()
+        unused' -> Left $ unusedVariables operationName unused'
+
+lookupAndValidateValueOnBody ::
+     DataTypeLib -> Variables -> VALIDATION_MODE -> (Text, Variable ()) -> Validation (Text, Variable Value)
+lookupAndValidateValueOnBody typeLib bodyVariables validationMode (key, var@Variable { variableType
+                                                                                     , variablePosition
+                                                                                     , isVariableRequired
+                                                                                     , variableTypeWrappers
+                                                                                     }) =
+  toVariable <$>
+  (getVariableType variableType variablePosition typeLib >>=
+   checkType (validationMode /= WITHOUT_VARIABLES && isVariableRequired))
+  where
+    toVariable (varKey, variableValue) = (varKey, var {variableValue})
+    ------------------------------------------------------------------
+    checkType True varType =
+      lookupVariable bodyVariables key (uninitializedVariable variablePosition variableType) >>= validator varType
+    checkType False varType = maybe (pure (key, Null)) (validator varType) (M.lookup key bodyVariables)
+    -----------------------------------------------------------------------------------------------
+    validator varType varValue =
+      handleInputError key variablePosition $ validateInputValue typeLib [] variableTypeWrappers varType (key, varValue)
diff --git a/src/Data/Morpheus/Validation/Selection.hs b/src/Data/Morpheus/Validation/Selection.hs
deleted file mode 100644
--- a/src/Data/Morpheus/Validation/Selection.hs
+++ /dev/null
@@ -1,226 +0,0 @@
-{-# LANGUAGE FlexibleInstances   #-}
-{-# LANGUAGE NamedFieldPuns      #-}
-{-# LANGUAGE OverloadedStrings   #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE TypeOperators       #-}
-
-module Data.Morpheus.Validation.Selection
-  ( validateSelectionSet
-  ) where
-
-import           Data.Morpheus.Error.Selection                 (cannotQueryField, duplicateQuerySelections,
-                                                                hasNoSubfields, subfieldsNotSelected)
-import           Data.Morpheus.Error.Variable                  (unknownType)
-import           Data.Morpheus.Types.Internal.AST.Operation    (ValidVariables)
-import           Data.Morpheus.Types.Internal.AST.RawSelection (Fragment (..), FragmentLib, RawSelection (..),
-                                                                RawSelection' (..), RawSelectionSet)
-import           Data.Morpheus.Types.Internal.AST.Selection    (Selection (..), SelectionRec (..), SelectionSet)
-import           Data.Morpheus.Types.Internal.Base             (EnhancedKey (..))
-import           Data.Morpheus.Types.Internal.Data             (DataField (..), DataFullType (..), DataOutputObject,
-                                                                DataType (..), DataTypeLib (..), allDataTypes)
-import           Data.Morpheus.Types.Internal.Validation       (Validation)
-import           Data.Morpheus.Validation.Arguments            (validateArguments)
-import           Data.Morpheus.Validation.Fragment             (castFragmentType, resolveSpread)
-import           Data.Morpheus.Validation.Utils.Selection      (lookupFieldAsSelectionSet, lookupSelectionField,
-                                                                lookupUnionTypes)
-import           Data.Morpheus.Validation.Utils.Utils          (checkNameCollision, lookupType)
-import           Data.Text                                     (Text)
-
-checkDuplicatesOn :: DataOutputObject -> SelectionSet -> Validation SelectionSet
-checkDuplicatesOn DataType {typeName = name'} keys =
-  checkNameCollision enhancedKeys selError >> pure keys
-  where
-    selError = duplicateQuerySelections name'
-    enhancedKeys = map selToKey keys
-    selToKey (key', Selection {selectionPosition = position'}) =
-      EnhancedKey key' position'
-
-clusterUnionSelection ::
-     FragmentLib
-  -> Text
-  -> [DataOutputObject]
-  -> (Text, RawSelection)
-  -> Validation ([Fragment], SelectionSet)
-clusterUnionSelection fragments type' possibleTypes' = splitFrag
-  where
-    packFragment fragment = return ([fragment], [])
-    typeNames = map typeName possibleTypes'
-    splitFrag :: (Text, RawSelection) -> Validation ([Fragment], SelectionSet)
-    splitFrag (_, Spread ref) =
-      resolveSpread fragments typeNames ref >>= packFragment
-    splitFrag ("__typename", RawSelectionField RawSelection' {rawSelectionPosition = position'}) =
-      return
-        ( []
-        , [ ( "__typename"
-            , Selection
-                { selectionRec = SelectionField
-                , selectionArguments = []
-                , selectionPosition = position'
-                })
-          ])
-    splitFrag (key, RawSelectionSet RawSelection' {rawSelectionPosition}) =
-      Left $ cannotQueryField key type' rawSelectionPosition
-    splitFrag (key, RawSelectionField RawSelection' {rawSelectionPosition}) =
-      Left $ cannotQueryField key type' rawSelectionPosition
-    splitFrag (key', RawAlias {rawAliasPosition = position'}) =
-      Left $ cannotQueryField key' type' position'
-    splitFrag (_, InlineFragment fragment') =
-      castFragmentType Nothing (fragmentPosition fragment') typeNames fragment' >>=
-      packFragment
-
-categorizeTypes ::
-     [DataOutputObject] -> [Fragment] -> [(DataOutputObject, [Fragment])]
-categorizeTypes types fragments = filter notEmpty $ map categorizeType types
-  where
-    notEmpty = (0 /=) . length . snd
-    categorizeType :: DataOutputObject -> (DataOutputObject, [Fragment])
-    categorizeType datatype = (datatype, filter matches fragments)
-      where
-        matches fragment = fragmentType fragment == typeName datatype
-
-flatTuple :: [([a], [b])] -> ([a], [b])
-flatTuple list' = (concatMap fst list', concatMap snd list')
- {-
-    - all Variable and Fragment references will be: resolved and validated
-    - unionTypes: will be clustered under type names
-      ...A on T1 {<SelectionA>}
-      ...B on T2 {<SelectionB>}
-      ...C on T2 {<SelectionC>}
-      will be become : [
-          ("T1",[<SelectionA>]),
-          ("T2",[<SelectionB>,<SelectionC>])
-      ]
- -}
-
-validateSelectionSet ::
-     DataTypeLib
-  -> FragmentLib
-  -> Text
-  -> ValidVariables
-  -> DataOutputObject
-  -> RawSelectionSet
-  -> Validation SelectionSet
-validateSelectionSet lib fragments' operatorName variables = __validate
-  where
-    __validate dataType'@DataType {typeName = typeName'} selectionSet' =
-      concat <$> mapM validateSelection selectionSet' >>=
-      checkDuplicatesOn dataType'
-      where
-        validateFragment Fragment {fragmentSelection = selection'} =
-          __validate dataType' selection'
-        {-
-            get dataField and validated arguments for RawSelection
-        -}
-        getValidationData key RawSelection' { rawSelectionArguments
-                                            , rawSelectionPosition
-                                            } = do
-          selectionField <-
-            lookupSelectionField rawSelectionPosition key dataType'
-          -- validate field Argument -----
-          arguments <-
-            validateArguments
-              lib
-              operatorName
-              variables
-              (key, selectionField)
-              rawSelectionPosition
-              rawSelectionArguments
-          -- check field Type existence  -----
-          fieldDataType <-
-            lookupType
-              (unknownType (fieldType selectionField) rawSelectionPosition)
-              (allDataTypes lib)
-              (fieldType selectionField)
-          return (selectionField, fieldDataType, arguments)
-        -- validate single selection: InlineFragments and Spreads will Be resolved and included in SelectionSet
-        --
-        validateSelection :: (Text, RawSelection) -> Validation SelectionSet
-        validateSelection (key', RawAlias { rawAliasSelection = rawSelection'
-                                          , rawAliasPosition = position'
-                                          }) =
-          fmap processSingleSelection <$> validateSelection rawSelection'
-          where
-            processSingleSelection (selKey', selection') =
-              ( key'
-              , selection'
-                  { selectionRec =
-                      SelectionAlias
-                        { aliasFieldName = selKey'
-                        , aliasSelection = selectionRec selection'
-                        }
-                  , selectionPosition = position'
-                  })
-        validateSelection (key', RawSelectionSet fullRawSelection'@RawSelection' { rawSelectionRec = rawSelectors
-                                                                                 , rawSelectionPosition = position'
-                                                                                 }) = do
-          (dataField', dataType, arguments) <-
-            getValidationData key' fullRawSelection'
-          case dataType of
-            Union _ -> do
-              (categories, __typename) <- clusterTypes
-              mapM (validateCluster __typename) categories >>=
-                returnSelection arguments . UnionSelection
-              where clusterTypes = do
-                      unionTypes <-
-                        lookupUnionTypes position' key' lib dataField'
-                      (spreads, __typename) <-
-                        flatTuple <$>
-                        mapM
-                          (clusterUnionSelection fragments' typeName' unionTypes)
-                          rawSelectors
-                      return (categorizeTypes unionTypes spreads, __typename)
-                    --
-                    --    second arguments will be added to every selection cluster
-                    validateCluster ::
-                         SelectionSet
-                      -> (DataOutputObject, [Fragment])
-                      -> Validation (Text, SelectionSet)
-                    validateCluster sysSelection' (type', frags') = do
-                      selection' <-
-                        __validate type' (concatMap fragmentSelection frags')
-                      return (typeName type', sysSelection' ++ selection')
-            OutputObject _ -> do
-              fieldType' <-
-                lookupFieldAsSelectionSet position' key' lib dataField'
-              __validate fieldType' rawSelectors >>=
-                returnSelection arguments . SelectionSet
-                 -- DataFullType
-                       --   = Leaf DataLeaf
-                       --   | InputObject DataInputObject
-                       --   | InputUnion DataUnion
-            _ -> Left $ hasNoSubfields key' (fieldType dataField') position'
-          where
-            returnSelection arguments' selection' =
-              pure
-                [ ( key'
-                  , Selection
-                      { selectionArguments = arguments'
-                      , selectionRec = selection'
-                      , selectionPosition = position'
-                      })
-                ]
-        validateSelection (key', RawSelectionField fullRawSelection'@RawSelection' {rawSelectionPosition}) = do
-          (dataField, datatype, arguments') <-
-            getValidationData key' fullRawSelection'
-          isLeaf datatype dataField
-          pure
-            [ ( key'
-              , Selection
-                  { selectionArguments = arguments'
-                  , selectionRec = SelectionField
-                  , selectionPosition = rawSelectionPosition
-                  })
-            ]
-          where
-            isLeaf (Leaf _) _ = Right ()
-            isLeaf _ DataField {fieldType} =
-              Left $ subfieldsNotSelected key' fieldType rawSelectionPosition
-        validateSelection (_, Spread reference') =
-          resolveSpread fragments' [typeName'] reference' >>= validateFragment
-        validateSelection (_, InlineFragment fragment') =
-          castFragmentType
-            Nothing
-            (fragmentPosition fragment')
-            [typeName']
-            fragment' >>=
-          validateFragment
diff --git a/src/Data/Morpheus/Validation/Utils/Selection.hs b/src/Data/Morpheus/Validation/Utils/Selection.hs
deleted file mode 100644
--- a/src/Data/Morpheus/Validation/Utils/Selection.hs
+++ /dev/null
@@ -1,44 +0,0 @@
-module Data.Morpheus.Validation.Utils.Selection
-  ( lookupFieldAsSelectionSet
-  , lookupSelectionField
-  , lookupUnionTypes
-  ) where
-
-import           Data.Morpheus.Error.Selection           (cannotQueryField, hasNoSubfields)
-import           Data.Morpheus.Types.Internal.Base       (Position)
-import           Data.Morpheus.Types.Internal.Data       (DataField (..), DataOutputField, DataOutputObject,
-                                                          DataType (..), DataTypeLib (..))
-import           Data.Morpheus.Types.Internal.Validation (Validation)
-import           Data.Morpheus.Validation.Utils.Utils    (lookupField, lookupType)
-import           Data.Text                               (Text)
-
-lookupUnionTypes ::
-     Position
-  -> Text
-  -> DataTypeLib
-  -> DataOutputField
-  -> Validation [DataOutputObject]
-lookupUnionTypes position' key' lib' DataField {fieldType = type'} =
-  lookupType error' (union lib') type' >>=
-  mapM (lookupType error' (object lib') . fieldType) . typeData
-  where
-    error' = hasNoSubfields key' type' position'
-
-lookupFieldAsSelectionSet ::
-     Position
-  -> Text
-  -> DataTypeLib
-  -> DataOutputField
-  -> Validation DataOutputObject
-lookupFieldAsSelectionSet position' key' lib' DataField {fieldType = type'} =
-  lookupType error' (object lib') type'
-  where
-    error' = hasNoSubfields key' type' position'
-
-lookupSelectionField ::
-     Position -> Text -> DataOutputObject -> Validation DataOutputField
-lookupSelectionField position' key' DataType { typeData = fields'
-                                             , typeName = name'
-                                             } = lookupField key' fields' error'
-  where
-    error' = cannotQueryField key' name' position'
diff --git a/src/Data/Morpheus/Validation/Utils/Utils.hs b/src/Data/Morpheus/Validation/Utils/Utils.hs
deleted file mode 100644
--- a/src/Data/Morpheus/Validation/Utils/Utils.hs
+++ /dev/null
@@ -1,85 +0,0 @@
-module Data.Morpheus.Validation.Utils.Utils
-  ( differKeys
-  , existsObjectType
-  , lookupType
-  , getInputType
-  , lookupField
-  , checkNameCollision
-  , checkForUnknownKeys
-  , VALIDATION_MODE(..)
-  ) where
-
-import           Data.List                               ((\\))
-import           Data.Morpheus.Error.Variable            (unknownType)
-import           Data.Morpheus.Types.Internal.Base       (EnhancedKey (..), Key, Position, enhanceKeyWithNull)
-import           Data.Morpheus.Types.Internal.Data       (DataInputType, DataKind (..), DataLeaf (..), DataOutputObject,
-                                                          DataTypeLib (..))
-import           Data.Morpheus.Types.Internal.Validation (Validation)
-import qualified Data.Set                                as S
-import           Data.Text                               (Text)
-
-type GenError error a = error -> Either error a
-
-data VALIDATION_MODE
-  = WITHOUT_VARIABLES
-  | FULL_VALIDATION
-  deriving (Eq, Show)
-
-lookupType :: error -> [(Text, a)] -> Text -> Either error a
-lookupType error' lib' typeName' =
-  case lookup typeName' lib' of
-    Nothing -> Left error'
-    Just x  -> pure x
-
-lookupField :: Text -> [(Text, fType)] -> GenError error fType
-lookupField id' lib' error' =
-  case lookup id' lib' of
-    Nothing    -> Left error'
-    Just field -> pure field
-
-getInputType :: Text -> DataTypeLib -> GenError error DataInputType
-getInputType typeName' lib error' =
-  case lookup typeName' (inputObject lib) of
-    Just x -> pure (ObjectKind x)
-    Nothing ->
-      case lookup typeName' (inputUnion lib) of
-        Just x -> pure (UnionKind x)
-        Nothing ->
-          case lookup typeName' (leaf lib) of
-            Nothing               -> Left error'
-            Just (BaseScalar x)   -> pure (ScalarKind x)
-            Just (CustomScalar x) -> pure (ScalarKind x)
-            Just (LeafEnum x)     -> pure (EnumKind x)
-
-existsObjectType ::
-     Position -> Text -> DataTypeLib -> Validation DataOutputObject
-existsObjectType position' typeName' lib =
-  lookupType error' (object lib) typeName'
-  where
-    error' = unknownType typeName' position'
-
-differKeys :: [EnhancedKey] -> [Key] -> [EnhancedKey]
-differKeys enhanced keys = enhanced \\ map enhanceKeyWithNull keys
-
-removeDuplicates :: Ord a => [a] -> [a]
-removeDuplicates = S.toList . S.fromList
-
-elementOfKeys :: [Text] -> EnhancedKey -> Bool
-elementOfKeys keys' EnhancedKey {uid = id'} = id' `elem` keys'
-
-checkNameCollision ::
-     [EnhancedKey] -> ([EnhancedKey] -> error) -> Either error [EnhancedKey]
-checkNameCollision enhancedKeys errorGenerator =
-  case enhancedKeys \\ removeDuplicates enhancedKeys of
-    []         -> pure enhancedKeys
-    duplicates -> Left $ errorGenerator duplicates
-
-checkForUnknownKeys ::
-     [EnhancedKey]
-  -> [Text]
-  -> ([EnhancedKey] -> error)
-  -> Either error [EnhancedKey]
-checkForUnknownKeys enhancedKeys' keys' errorGenerator' =
-  case filter (not . elementOfKeys keys') enhancedKeys' of
-    []           -> pure enhancedKeys'
-    unknownKeys' -> Left $ errorGenerator' unknownKeys'
diff --git a/src/Data/Morpheus/Validation/Validation.hs b/src/Data/Morpheus/Validation/Validation.hs
deleted file mode 100644
--- a/src/Data/Morpheus/Validation/Validation.hs
+++ /dev/null
@@ -1,70 +0,0 @@
-{-# LANGUAGE FlexibleInstances   #-}
-{-# LANGUAGE NamedFieldPuns      #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE TypeOperators       #-}
-
-module Data.Morpheus.Validation.Validation
-  ( validateRequest
-  ) where
-
-import           Data.Map                                   (fromList)
-import           Data.Morpheus.Error.Mutation               (mutationIsNotDefined)
-import           Data.Morpheus.Error.Subscription           (subscriptionIsNotDefined)
-import           Data.Morpheus.Types.Internal.AST.Operation (Operation (..), OperationKind (..), RawOperation,
-                                                             ValidOperation)
-import           Data.Morpheus.Types.Internal.Data          (DataOutputObject, DataTypeLib (..))
-import           Data.Morpheus.Types.Internal.Validation    (Validation)
-import           Data.Morpheus.Types.Types                  (GQLQueryRoot (..))
-import           Data.Morpheus.Validation.Fragment          (validateFragments)
-import           Data.Morpheus.Validation.Selection         (validateSelectionSet)
-import           Data.Morpheus.Validation.Utils.Utils       (VALIDATION_MODE)
-import           Data.Morpheus.Validation.Variable          (resolveOperationVariables)
-
-getOperationDataType ::
-     RawOperation -> DataTypeLib -> Validation DataOutputObject
-getOperationDataType Operation {operationKind = QUERY} lib =
-  pure $ snd $ query lib
-getOperationDataType Operation {operationKind = MUTATION, operationPosition} lib =
-  case mutation lib of
-    Just (_, mutation') -> pure mutation'
-    Nothing             -> Left $ mutationIsNotDefined operationPosition
-getOperationDataType Operation {operationKind = SUBSCRIPTION, operationPosition} lib =
-  case subscription lib of
-    Just (_, subscription') -> pure subscription'
-    Nothing                 -> Left $ subscriptionIsNotDefined operationPosition
-
-validateRequest ::
-     DataTypeLib -> VALIDATION_MODE -> GQLQueryRoot -> Validation ValidOperation
-validateRequest lib validationMode GQLQueryRoot { fragments
-                                                , inputVariables
-                                                , operation = rawOperation@Operation { operationName
-                                                                                     , operationKind
-                                                                                     , operationSelection
-                                                                                     , operationPosition
-                                                                                     }
-                                                } = do
-  operationDataType <- getOperationDataType rawOperation lib
-  variables <-
-    resolveOperationVariables
-      lib
-      fragments
-      (fromList inputVariables)
-      validationMode
-      rawOperation
-  validateFragments lib fragments operationSelection
-  selection <-
-    validateSelectionSet
-      lib
-      fragments
-      operationName
-      variables
-      operationDataType
-      operationSelection
-  pure $
-    Operation
-      { operationName
-      , operationKind
-      , operationArgs = []
-      , operationSelection = selection
-      , operationPosition
-      }
diff --git a/src/Data/Morpheus/Validation/Variable.hs b/src/Data/Morpheus/Validation/Variable.hs
deleted file mode 100644
--- a/src/Data/Morpheus/Validation/Variable.hs
+++ /dev/null
@@ -1,130 +0,0 @@
-{-# LANGUAGE NamedFieldPuns #-}
-
-module Data.Morpheus.Validation.Variable
-  ( resolveOperationVariables
-  ) where
-
-import           Data.List                                     ((\\))
-import qualified Data.Map                                      as M (lookup)
-import           Data.Maybe                                    (maybe)
-import           Data.Morpheus.Error.Input                     (InputValidation, inputErrorMessage)
-import           Data.Morpheus.Error.Variable                  (uninitializedVariable, unknownType, unusedVariables,
-                                                                variableGotInvalidValue)
-import           Data.Morpheus.Types.Internal.AST.Operation    (Operation (..), RawOperation, ValidVariables,
-                                                                Variable (..))
-import           Data.Morpheus.Types.Internal.AST.RawSelection (Fragment (..), FragmentLib, RawArgument (..),
-                                                                RawSelection (..), RawSelection' (..), RawSelectionSet,
-                                                                Reference (..))
-import           Data.Morpheus.Types.Internal.Base             (EnhancedKey (..), Position)
-import           Data.Morpheus.Types.Internal.Data             (DataInputType, DataTypeLib)
-import           Data.Morpheus.Types.Internal.Validation       (Validation)
-import           Data.Morpheus.Types.Internal.Value            (Value (..))
-import           Data.Morpheus.Types.Types                     (Variables)
-import           Data.Morpheus.Validation.Fragment             (getFragment)
-import           Data.Morpheus.Validation.Input.Object         (validateInputValue)
-import           Data.Morpheus.Validation.Utils.Utils          (VALIDATION_MODE (..), getInputType)
-import           Data.Semigroup                                ((<>))
-import           Data.Text                                     (Text)
-
-getVariableType :: Text -> Position -> DataTypeLib -> Validation DataInputType
-getVariableType type' position' lib' = getInputType type' lib' error'
-  where
-    error' = unknownType type' position'
-
-lookupVariable :: Variables -> Text -> (Text -> error) -> Either error Value
-lookupVariable variables' key' error' =
-  case M.lookup key' variables' of
-    Nothing    -> Left $ error' key'
-    Just value -> pure value
-
-handleInputError ::
-     Text -> Position -> InputValidation Value -> Validation (Text, Value)
-handleInputError key' position' (Left error') =
-  Left $ variableGotInvalidValue key' (inputErrorMessage error') position'
-handleInputError key' _ (Right value') = pure (key', value')
-
-concatMapM :: Monad m => (a -> m [b]) -> [a] -> m [b]
-concatMapM f = fmap concat . mapM f
-
-allVariableReferences ::
-     FragmentLib -> [RawSelectionSet] -> Validation [EnhancedKey]
-allVariableReferences fragmentLib = concatMapM (concatMapM searchReferences)
-  where
-    referencesFromArgument :: (Text, RawArgument) -> [EnhancedKey]
-    referencesFromArgument (_, RawArgument {}) = []
-    referencesFromArgument (_, VariableReference Reference { referenceName
-                                                           , referencePosition
-                                                           }) =
-      [EnhancedKey referenceName referencePosition]
-    -- | search used variables in every arguments
-    searchReferences :: (Text, RawSelection) -> Validation [EnhancedKey]
-    searchReferences (_, RawSelectionSet RawSelection' { rawSelectionArguments
-                                                       , rawSelectionRec
-                                                       }) =
-      getArgs <$> concatMapM searchReferences rawSelectionRec
-      where
-        getArgs :: [EnhancedKey] -> [EnhancedKey]
-        getArgs x = concatMap referencesFromArgument rawSelectionArguments <> x
-    searchReferences (_, InlineFragment Fragment {fragmentSelection}) =
-      concatMapM searchReferences fragmentSelection
-    searchReferences (_, RawAlias {rawAliasSelection}) =
-      searchReferences rawAliasSelection
-    searchReferences (_, RawSelectionField RawSelection' {rawSelectionArguments}) =
-      return $ concatMap referencesFromArgument rawSelectionArguments
-    searchReferences (_, Spread reference) =
-      getFragment reference fragmentLib >>=
-      concatMapM searchReferences . fragmentSelection
-
-resolveOperationVariables ::
-     DataTypeLib
-  -> FragmentLib
-  -> Variables
-  -> VALIDATION_MODE
-  -> RawOperation
-  -> Validation ValidVariables
-resolveOperationVariables typeLib lib root validationMode Operation { operationName
-                                                                    , operationSelection
-                                                                    , operationArgs
-                                                                    } = do
-  allVariableReferences lib [operationSelection] >>= checkUnusedVariables
-  mapM (lookupAndValidateValueOnBody typeLib root validationMode) operationArgs
-  where
-    varToKey :: (Text, Variable ()) -> EnhancedKey
-    varToKey (key', Variable {variablePosition}) =
-      EnhancedKey key' variablePosition
-    --
-    checkUnusedVariables :: [EnhancedKey] -> Validation ()
-    checkUnusedVariables refs =
-      case map varToKey operationArgs \\ refs of
-        []      -> pure ()
-        unused' -> Left $ unusedVariables operationName unused'
-
-lookupAndValidateValueOnBody ::
-     DataTypeLib
-  -> Variables
-  -> VALIDATION_MODE
-  -> (Text, Variable ())
-  -> Validation (Text, Variable Value)
-lookupAndValidateValueOnBody typeLib bodyVariables validationMode (key, var@Variable { variableType
-                                                                                     , variablePosition
-                                                                                     , isVariableRequired
-                                                                                     , variableTypeWrappers
-                                                                                     }) =
-  toVariable <$>
-  (getVariableType variableType variablePosition typeLib >>=
-   checkType (validationMode /= WITHOUT_VARIABLES && isVariableRequired))
-  where
-    toVariable (varKey, variableValue) = (varKey, var {variableValue})
-    ------------------------------------------------------------------
-    checkType True varType =
-      lookupVariable
-        bodyVariables
-        key
-        (uninitializedVariable variablePosition variableType) >>=
-      validator varType
-    checkType False varType =
-      maybe (pure (key, Null)) (validator varType) (M.lookup key bodyVariables)
-    -----------------------------------------------------------------------------------------------
-    validator varType varValue =
-      handleInputError key variablePosition $
-      validateInputValue typeLib [] variableTypeWrappers varType (key, varValue)
diff --git a/test/Feature/Holistic/API.hs b/test/Feature/Holistic/API.hs
--- a/test/Feature/Holistic/API.hs
+++ b/test/Feature/Holistic/API.hs
@@ -7,13 +7,12 @@
   ( api
   ) where
 
-import           Data.ByteString.Lazy.Char8 (ByteString)
-import           Data.Morpheus              (interpreter)
-import           Data.Morpheus.Kind         (ENUM, INPUT_OBJECT, OBJECT, SCALAR, UNION)
-import           Data.Morpheus.Types        (Event (..), GQLRootResolver (..), GQLScalar (..), GQLType (..), ID (..),
-                                             IORes, IOSubRes, ScalarValue (..))
-import           Data.Text                  (Text)
-import           GHC.Generics               (Generic)
+import           Data.Morpheus       (interpreter)
+import           Data.Morpheus.Kind  (ENUM, INPUT_OBJECT, OBJECT, SCALAR, UNION)
+import           Data.Morpheus.Types (Event (..), GQLRequest, GQLResponse, GQLRootResolver (..), GQLScalar (..),
+                                      GQLType (..), ID (..), IORes, IOSubRes, ScalarValue (..))
+import           Data.Text           (Text)
+import           GHC.Generics        (Generic)
 
 data TestEnum
   = EnumA
@@ -121,7 +120,7 @@
   } deriving (Generic)
 
 resolveAddress :: a -> IORes Address
-resolveAddress _ = return Address {city = "", houseNumber = 1, street = const $ return Nothing}
+resolveAddress _ = return Address {city = "", houseNumber = 0, street = const $ return Nothing}
 
 resolveUser :: a -> IORes User
 resolveUser _ =
@@ -137,5 +136,5 @@
     , subscriptionResolver = return Subscription {newUser = const $ Event [EVENT] resolveUser}
     }
 
-api :: ByteString -> IO ByteString
+api :: GQLRequest -> IO GQLResponse
 api = interpreter rootResolver
diff --git a/test/Feature/Holistic/cases.json b/test/Feature/Holistic/cases.json
--- a/test/Feature/Holistic/cases.json
+++ b/test/Feature/Holistic/cases.json
@@ -166,5 +166,13 @@
   {
     "path": "introspection/kinds/UNION",
     "description": "test introspection of UNION kind"
+  },
+  {
+    "path": "parsing/singleLineComments",
+    "description": "parses single line comments"
+  },
+  {
+    "path": "parsing/multilineComments",
+    "description": "parses multiline comments"
   }
 ]
diff --git a/test/Feature/Holistic/parsing/invalidFields/response.json b/test/Feature/Holistic/parsing/invalidFields/response.json
--- a/test/Feature/Holistic/parsing/invalidFields/response.json
+++ b/test/Feature/Holistic/parsing/invalidFields/response.json
@@ -1,7 +1,7 @@
 {
   "errors": [
     {
-      "message": "offset=26:\nunexpected '<'\nexpecting '#', ',', '_', '}', body, digit, entry, letter, maybeArguments, or white space\n",
+      "message": "offset=26:\nunexpected '<'\nexpecting \"\"\"\"\", '#', ',', '_', '}', body, digit, entry, letter, maybeArguments, or white space\n",
       "locations": [
         {
           "line": 1,
diff --git a/test/Feature/Holistic/parsing/invalidNotNullOperator/response.json b/test/Feature/Holistic/parsing/invalidNotNullOperator/response.json
--- a/test/Feature/Holistic/parsing/invalidNotNullOperator/response.json
+++ b/test/Feature/Holistic/parsing/invalidNotNullOperator/response.json
@@ -1,7 +1,7 @@
 {
   "errors": [
     {
-      "message": "offset=20:\nunexpected '@'\nexpecting '!', '#', ']', '_', digit, letter, or white space\n",
+      "message": "offset=20:\nunexpected '@'\nexpecting \"\"\"\"\", '!', '#', ']', '_', digit, letter, or white space\n",
       "locations": [
         {
           "line": 1,
diff --git a/test/Feature/Holistic/parsing/missingCloseBrace/response.json b/test/Feature/Holistic/parsing/missingCloseBrace/response.json
--- a/test/Feature/Holistic/parsing/missingCloseBrace/response.json
+++ b/test/Feature/Holistic/parsing/missingCloseBrace/response.json
@@ -1,7 +1,7 @@
 {
   "errors": [
     {
-      "message": "offset=66:\nunexpected end of input\nexpecting '#', ',', '}', entry, or white space\n",
+      "message": "offset=66:\nunexpected end of input\nexpecting \"\"\"\"\", '#', ',', '}', entry, or white space\n",
       "locations": [
         {
           "line": 5,
diff --git a/test/Feature/Holistic/parsing/multilineComments/query.gql b/test/Feature/Holistic/parsing/multilineComments/query.gql
new file mode 100644
--- /dev/null
+++ b/test/Feature/Holistic/parsing/multilineComments/query.gql
@@ -0,0 +1,131 @@
+""" %&
+%(//
+     %& %(//
+%&%&  # startin""g ''Comme"""
+
+"""
+"""
+
+"""
+
+
+"""
+
+
+"""
+   comment with tabs
+
+"""
+
+
+query
+""" 
+%&
+%wer""g ''Comme
+"""
+GetUsers """ %&
+%(//
+     %& %(//
+%&%&  # startin""g ''Comme""" ( """ %&
+%(//
+     %& %(//
+%&%&  # startin""g ''Comme""" $v: """ %&
+%(//
+     %& %(//
+%&%&  # startin""g ''Comme"""
+ [ """ somejhgja """ Int """ 343 """ ! """ 343 """  ] # starting Comment'' # starting Comment''
+) {
+  user {
+    """ %&
+%(//
+     %& ''Comme"""
+
+    email2: """ %&
+%(//
+     %& %(//
+%&%&  # startin""g ''Comme""" email """ %&
+%(//
+     %& %(//
+%&%&  # startin""g ''Comme"""
+    name """ %&
+%(//
+     %& %(//
+%&%&  # startin""g ''Comme"""
+
+    address( """ %&
+%(//
+     %& %(//
+%&%&  # startin""g ''Comme"""
+      coordinates: {
+""" %&
+%(//
+     %& %(//
+%&%&  # startin""g ''Comme"""        longitude:  0 # starting Comment''
+        latitude: "" # starting Comment'' # starting Comment'' # starting Comment''
+      }
+    ) """ %&
+%(//
+     %& %(//
+%&%&  # startin""g ''Comme""" {
+      """ %&
+%(//
+     %& %(//
+%&%&  # startin""g ''Comme"""
+      # starting Comment''
+      ...City
+    }
+    office """ %&
+%(//
+     %& %(//
+%&%&  # startin""g ''Comme""" (
+      zipCode: $v # starting Comment''
+      cityID: EnumA 
+    ) """ %&
+%(//
+     %& %(//
+%&%&  # startin""g ''Comme""" {
+      houseNumber """ %&
+%(//
+     %& %(//
+%&%&  # startin""g ''Comme"""
+
+      ... on Address {
+""" %&
+%(//
+     %& %(//
+%&%&  # startin""g ''Comme"""
+        city """ %&
+%(//
+     %& %(//
+%&%&  # startin""g ''Comme"""
+      }
+    }
+    """ %&
+%(//
+     %& %(//
+%&%&  # startin""g ''Comme"""
+  }
+""" %&
+%(//
+     %& %(//
+%&%&  # startin""g ''Comme"""}
+# starting Comment''
+# starting Comment''
+
+fragment City  on  Address """ %&
+%(//
+     %& %(//
+%&%&  # startin""g ''Comme""" {
+""" %&
+%(//
+     %& %(//
+%&%&  # startin""g ''Comme"""
+  city""" %&
+%(//
+     %& %(//
+%&%&  # startin""g ''Comme"""
+}
+""" %&
+%(//
+     %& %(//
+%&%&  # startin""g ''Comme"""
diff --git a/test/Feature/Holistic/parsing/multilineComments/response.json b/test/Feature/Holistic/parsing/multilineComments/response.json
new file mode 100644
--- /dev/null
+++ b/test/Feature/Holistic/parsing/multilineComments/response.json
@@ -0,0 +1,15 @@
+{
+  "data": {
+    "user": {
+      "email2": "",
+      "name": "testName",
+      "address": {
+        "city": ""
+      },
+      "office": {
+        "houseNumber": 0,
+        "city": ""
+      }
+    }
+  }
+}
diff --git a/test/Feature/Holistic/parsing/singleLineComments/query.gql b/test/Feature/Holistic/parsing/singleLineComments/query.gql
new file mode 100644
--- /dev/null
+++ b/test/Feature/Holistic/parsing/singleLineComments/query.gql
@@ -0,0 +1,57 @@
+# starting Comment''
+# starting Comment''
+query # starting Comment''
+# starting Comment''
+GetUsers( # starting Comment'' # starting Comment''
+  $v: [# starting Comment'' # starting Comment''
+  Int!] # starting Comment'' # starting Comment''
+) {
+  user {
+    # starting Comment''
+    # %&%(//
+    # %&%(//
+    email2: email # starting Comment'' # %&%(// # starting Comment''
+    name # starting Comment''
+    # starting Comment''
+    # starting Comment''
+    # starting Comment''
+
+    address( # starting Comment'' # %&%(//
+      coordinates: {
+        # %&%(//
+        longitude: 0 # starting Comment''
+        latitude: "" # starting Comment'' # starting Comment'' # starting Comment''
+      }
+    ) {
+      # starting Comment''
+      ...City
+    }
+    office(
+      zipCode: $v # starting Comment''
+      cityID: EnumA # starting Comment'' # starting Comment''
+    ) {
+      houseNumber # starting Comment''
+      # starting Comment''
+
+      ... on Address {
+        # starting Comment''
+
+        city # starting Comment''
+        # starting Comment''
+        # starting Comment''
+      }
+    }
+    # starting Comment''
+  }
+  # starting Comment''
+}
+# starting Comment''
+# starting Comment''
+
+fragment City on Address {
+  # starting Comment''
+  # starting Comment''
+  city # starting Comment''
+}
+# starting Comment''
+# starting Comment''
diff --git a/test/Feature/Holistic/parsing/singleLineComments/response.json b/test/Feature/Holistic/parsing/singleLineComments/response.json
new file mode 100644
--- /dev/null
+++ b/test/Feature/Holistic/parsing/singleLineComments/response.json
@@ -0,0 +1,15 @@
+{
+  "data": {
+    "user": {
+      "email2": "",
+      "name": "testName",
+      "address": {
+        "city": ""
+      },
+      "office": {
+        "houseNumber": 0,
+        "city": ""
+      }
+    }
+  }
+}
diff --git a/test/Feature/Input/Enum/API.hs b/test/Feature/Input/Enum/API.hs
--- a/test/Feature/Input/Enum/API.hs
+++ b/test/Feature/Input/Enum/API.hs
@@ -7,11 +7,10 @@
   ( api
   ) where
 
-import           Data.ByteString.Lazy.Char8 (ByteString)
-import           Data.Morpheus              (interpreter)
-import           Data.Morpheus.Kind         (ENUM)
-import           Data.Morpheus.Types        (GQLRootResolver (..), GQLType (..), IORes)
-import           GHC.Generics               (Generic)
+import           Data.Morpheus       (interpreter)
+import           Data.Morpheus.Kind  (ENUM)
+import           Data.Morpheus.Types (GQLRequest, GQLResponse, GQLRootResolver (..), GQLType (..), IORes)
+import           GHC.Generics        (Generic)
 
 data TwoCon
   = LA
@@ -67,5 +66,5 @@
     , subscriptionResolver = return ()
     }
 
-api :: ByteString -> IO ByteString
+api :: GQLRequest -> IO GQLResponse
 api = interpreter rootResolver
diff --git a/test/Feature/InputType/API.hs b/test/Feature/InputType/API.hs
--- a/test/Feature/InputType/API.hs
+++ b/test/Feature/InputType/API.hs
@@ -7,12 +7,11 @@
   ( api
   ) where
 
-import           Data.ByteString.Lazy.Char8 (ByteString)
-import           Data.Morpheus              (interpreter)
-import           Data.Morpheus.Kind         (OBJECT)
-import           Data.Morpheus.Types        (GQLRootResolver (..), GQLType (..), IORes)
-import           Data.Text                  (Text)
-import           GHC.Generics               (Generic)
+import           Data.Morpheus       (interpreter)
+import           Data.Morpheus.Kind  (OBJECT)
+import           Data.Morpheus.Types (GQLRequest, GQLResponse, GQLRootResolver (..), GQLType (..), IORes)
+import           Data.Text           (Text)
+import           GHC.Generics        (Generic)
 
 data F1Args = F1Args
   { arg1 :: Text
@@ -44,5 +43,5 @@
     , subscriptionResolver = return ()
     }
 
-api :: ByteString -> IO ByteString
+api :: GQLRequest -> IO GQLResponse
 api = interpreter rootResolver
diff --git a/test/Feature/Schema/API.hs b/test/Feature/Schema/API.hs
--- a/test/Feature/Schema/API.hs
+++ b/test/Feature/Schema/API.hs
@@ -7,13 +7,12 @@
   ( api
   ) where
 
-import           Data.ByteString.Lazy.Char8 (ByteString)
-import           Data.Morpheus              (interpreter)
-import           Data.Morpheus.Kind         (OBJECT)
-import           Data.Morpheus.Types        (GQLRootResolver (..), GQLType (..))
-import           Data.Text                  (Text)
-import qualified Feature.Schema.A2          as A2 (A (..))
-import           GHC.Generics               (Generic)
+import           Data.Morpheus       (interpreter)
+import           Data.Morpheus.Kind  (OBJECT)
+import           Data.Morpheus.Types (GQLRequest, GQLResponse, GQLRootResolver (..), GQLType (..))
+import           Data.Text           (Text)
+import qualified Feature.Schema.A2   as A2 (A (..))
+import           GHC.Generics        (Generic)
 
 data A = A
   { aText :: Text
@@ -36,5 +35,5 @@
     , subscriptionResolver = return ()
     }
 
-api :: ByteString -> IO ByteString
+api :: GQLRequest -> IO GQLResponse
 api = interpreter rootResolver
diff --git a/test/Feature/UnionType/API.hs b/test/Feature/UnionType/API.hs
--- a/test/Feature/UnionType/API.hs
+++ b/test/Feature/UnionType/API.hs
@@ -1,4 +1,3 @@
-{-# LANGUAGE DeriveAnyClass    #-}
 {-# LANGUAGE DeriveGeneric     #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE TypeFamilies      #-}
@@ -8,12 +7,11 @@
   ( api
   ) where
 
-import           Data.ByteString.Lazy.Char8 (ByteString)
-import           Data.Morpheus              (interpreter)
-import           Data.Morpheus.Kind         (OBJECT, UNION)
-import           Data.Morpheus.Types        (GQLRootResolver (..), GQLType (..), IORes)
-import           Data.Text                  (Text)
-import           GHC.Generics               (Generic)
+import           Data.Morpheus       (interpreter)
+import           Data.Morpheus.Kind  (OBJECT, UNION)
+import           Data.Morpheus.Types (GQLRequest, GQLResponse, GQLRootResolver (..), GQLType (..), IORes)
+import           Data.Text           (Text)
+import           GHC.Generics        (Generic)
 
 instance GQLType A where
   type KIND A = OBJECT
@@ -63,5 +61,5 @@
     , subscriptionResolver = return ()
     }
 
-api :: ByteString -> IO ByteString
+api :: GQLRequest -> IO GQLResponse
 api = interpreter rootResolver
diff --git a/test/Feature/WrappedTypeName/API.hs b/test/Feature/WrappedTypeName/API.hs
--- a/test/Feature/WrappedTypeName/API.hs
+++ b/test/Feature/WrappedTypeName/API.hs
@@ -7,13 +7,13 @@
   ( api
   ) where
 
-import           Data.ByteString.Lazy.Char8 (ByteString)
-import           Data.Morpheus              (interpreter)
-import           Data.Morpheus.Kind         (OBJECT)
-import           Data.Morpheus.Types        (Event (..), GQLRootResolver (..), GQLType (..), IOMutRes, IORes, IOSubRes)
-import           Data.Text                  (Text)
-import           Data.Typeable              (Typeable)
-import           GHC.Generics               (Generic)
+import           Data.Morpheus       (interpreter)
+import           Data.Morpheus.Kind  (OBJECT)
+import           Data.Morpheus.Types (Event (..), GQLRequest, GQLResponse, GQLRootResolver (..), GQLType (..), IOMutRes,
+                                      IORes, IOSubRes)
+import           Data.Text           (Text)
+import           Data.Typeable       (Typeable)
+import           GHC.Generics        (Generic)
 
 instance Typeable a => GQLType (WA a) where
   type KIND (WA a) = OBJECT
@@ -67,5 +67,5 @@
             }
     }
 
-api :: ByteString -> IO ByteString
+api :: GQLRequest -> IO GQLResponse
 api = interpreter rootResolver
diff --git a/test/Lib.hs b/test/Lib.hs
--- a/test/Lib.hs
+++ b/test/Lib.hs
@@ -12,6 +12,7 @@
 import qualified Data.ByteString.Lazy       as L (readFile)
 import           Data.ByteString.Lazy.Char8 (ByteString)
 import           Data.Maybe                 (fromMaybe)
+import           Data.Morpheus.Types        (GQLResponse (..))
 import           Data.Text                  (Text, unpack)
 
 path :: Text -> String
@@ -23,8 +24,8 @@
 resLib :: Text -> String
 resLib x = path x ++ "/response.json"
 
-maybeVariables :: Text -> IO ByteString
-maybeVariables x = L.readFile (path x ++ "/variables.json") <|> return "{}"
+maybeVariables :: Text -> IO (Maybe Value)
+maybeVariables x = decode <$> (L.readFile (path x ++ "/variables.json") <|> return "{}")
 
 getGQLBody :: Text -> IO ByteString
 getGQLBody p = L.readFile (gqlLib p)
diff --git a/test/TestFeature.hs b/test/TestFeature.hs
--- a/test/TestFeature.hs
+++ b/test/TestFeature.hs
@@ -1,14 +1,19 @@
 {-# LANGUAGE DeriveAnyClass    #-}
 {-# LANGUAGE DeriveGeneric     #-}
+{-# LANGUAGE NamedFieldPuns    #-}
 {-# LANGUAGE OverloadedStrings #-}
 
 module TestFeature
   ( testFeature
   ) where
 
-import           Data.Aeson                 (FromJSON, decode, encode)
+import qualified Data.Text.Lazy             as LT (toStrict)
+import           Data.Text.Lazy.Encoding    (decodeUtf8)
+
+import           Data.Aeson                 (FromJSON, Value, decode, encode)
 import           Data.ByteString.Lazy.Char8 (ByteString)
-import qualified Data.ByteString.Lazy.Char8 as LB (concat, pack, unpack)
+import qualified Data.ByteString.Lazy.Char8 as LB (unpack)
+import           Data.Morpheus.Types        (GQLRequest (..), GQLResponse (..))
 import           Data.Semigroup             ((<>))
 import           Data.Text                  (Text, unpack)
 import qualified Data.Text                  as T (concat)
@@ -17,33 +22,31 @@
 import           Test.Tasty                 (TestTree, testGroup)
 import           Test.Tasty.HUnit           (assertFailure, testCase)
 
-packGQLRequest :: ByteString -> ByteString -> ByteString
-packGQLRequest x variables' = LB.concat ["{\"query\":", LB.pack $ show x, ",\"variables\":", variables', "}"]
+packGQLRequest :: ByteString -> Maybe Value -> GQLRequest
+packGQLRequest queryBS variables =
+  GQLRequest {operationName = Nothing, query = LT.toStrict $ decodeUtf8 queryBS, variables}
 
 data Case = Case
   { path        :: Text
   , description :: String
   } deriving (Generic, FromJSON)
 
-testFeature :: (ByteString -> IO ByteString) -> Text -> IO TestTree
-testFeature api' dir' = do
-  cases' <- getCases (unpack dir')
-  test' <- sequence $ testByFiles api' <$> map (\x -> x {path = T.concat [dir', "/", path x]}) cases'
-  return $ testGroup (unpack dir') test'
+testFeature :: (GQLRequest -> IO GQLResponse) -> Text -> IO TestTree
+testFeature api dir = do
+  cases' <- getCases (unpack dir)
+  test' <- sequence $ testByFiles api <$> map (\x -> x {path = T.concat [dir, "/", path x]}) cases'
+  return $ testGroup (unpack dir) test'
 
-testByFiles :: (ByteString -> IO ByteString) -> Case -> IO TestTree
-testByFiles testApi (Case path' description') = do
-  testCaseQuery <- getGQLBody path'
-  testCaseVariables <- maybeVariables path'
-  expectedValue <- getResponseBody path'
-  gqlResponse <- testApi $ packGQLRequest testCaseQuery testCaseVariables
- 
-  case decode gqlResponse of
+testByFiles :: (GQLRequest -> IO GQLResponse) -> Case -> IO TestTree
+testByFiles testApi Case {path, description} = do
+  testCaseQuery <- getGQLBody path
+  testCaseVariables <- maybeVariables path
+  expectedResponse <- getResponseBody path
+  actualResponse <- encode <$> testApi (packGQLRequest testCaseQuery testCaseVariables)
+  case decode actualResponse of
     Nothing -> assertFailure "Bad Response"
-    Just response -> return $ testCase (unpack path' ++ " | " ++ description') $ customTest expectedValue response
-      where customTest expected value =
-              if expected == value
-                then return ()
-                else assertFailure generateError
-              where
-                generateError = LB.unpack $ "expected: \n " <> encode expected <> " \n but got: \n " <> gqlResponse
+    Just response -> return $ testCase (unpack path ++ " | " ++ description) $ customTest expectedResponse response
+      where customTest expected value
+              | expected == value = return ()
+              | otherwise =
+                assertFailure $ LB.unpack $ "expected: \n " <> encode expected <> " \n but got: \n " <> actualResponse
