diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -29,7 +29,7 @@
 resolver: lts-14.8
 
 extra-deps:
-  - morpheus-graphql-0.9.1
+  - morpheus-graphql-0.10.0
 ```
 
 As Morpheus is quite new, make sure stack can find morpheus-graphql by running `stack upgrade` and `stack update`
@@ -425,17 +425,17 @@
  where
   -- Mutation Without Event Triggering
   createDeity :: ResolveM EVENT IO Address
-  createDeity = MutResolver \$ do
-      value <- lift dbCreateDeity
-      pure (
-        [Event { channels = [ChannelA], content = ContentA 1 }],
-        value
-      )
-  newDeity = SubResolver [ChannelA] subResolver
+  createDeity = do
+      requireAuthorized
+      publish [Event { channels = [ChannelA], content = ContentA 1 }]
+      lift dbCreateDeity
+  newDeity = subscribe [ChannelA] $ do
+      requireAuthorized
+      lift deityByEvent
    where
-    subResolver (Event [ChannelA] (ContentA _value)) = fetchDeity  -- resolve New State
-    subResolver (Event [ChannelA] (ContentB _value)) = fetchDeity   -- resolve New State
-    subResolver _ = fetchDeity -- Resolve Old State
+    deityByEvent (Event [ChannelA] (ContentA _value)) = fetchDeity  -- resolve New State
+    deityByEvent (Event [ChannelA] (ContentB _value)) = fetchDeity   -- resolve New State
+    deityByEvent _ = fetchDeity -- Resolve Old State
 ```
 
 ## Morpheus `GraphQL Client` with Template haskell QuasiQuotes
@@ -541,6 +541,18 @@
 ## Morpheus CLI for Code Generating
 
 you should use [morpheus-graphql-cli](https://github.com/morpheusgraphql/morpheus-graphql-cli)
+
+## Showcase
+
+Below are the list of projects using Morpheus GraphQL. If you want to start using Morpheus GraphQL, they are
+good templates to begin with.
+
+- https://github.com/morpheusgraphql/mythology-api
+  - Serverless Mythology API
+- https://github.com/dandoh/web-haskell
+  - Modern webserver boilerplate in Haskell: Morpheus Graphql + Postgresql + Authentication + DB migration + Dotenv and more
+
+*Edit this section and send PR if you want to share your project*.
 
 # About
 
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,79 @@
 # Changelog
 
+## 0.10.0 - 07.01.2020
+
+### Breaking Changes
+
+- all constructors of `Resolver`: `QueryResolver`,`MutResolver`,`SubResolver` are unexposed. use `lift` , `publish` or `subscribe`.
+  e.g
+
+  ```hs
+  -- Query Resolver
+  resolveUser :: ResolveQ EVENT IO User
+  resolveUser = lift getDBUser
+
+  -- Mutation Resolver
+  resolveCreateUser :: ResolveM EVENT IO User
+  resolveCreateUser = do
+    publish [userUpdate] -- publishes event inside mutation
+    lift setDBUser
+
+  -- Subscription Resolver
+  resolveNewUser :: ResolveS EVENT IO User
+  resolveNewUser = subscribe [USER] $ do
+    pure $ \(Event _ content) -> lift (getDBUserByContent content)
+  ```
+  
+### New features
+
+- exposed `publish` for mutation resolvers, now you can write
+
+  ```hs
+  resolveCreateUser :: ResolveM EVENT IO User
+  resolveCreateUser = do
+      requireAuthorized
+      publish [userUpdate]
+      liftEither setDBUser
+  ```
+
+- exposed `subscribe` for subscription resolvers, now you can write
+
+  ```hs
+  resolveNewUser :: ResolveS EVENT IO User
+  resolveNewUser = subscribe [USER] $ do
+      requireAuthorized
+      pure userByEvent
+    where userByEvent (Event _ content) = liftEither (getDBUser content)
+  ```
+
+- `type SubField` will convert your subscription monad to query monad.
+  `SubField (Resolver Subscription Event IO) User` will generate same as
+  `Resolver Subscription Event IO (User ((Resolver QUERY Event IO)))`
+  
+  now if you want define subscription as follows
+  
+  ```hs
+  data Subscription m = Subscription {
+    newUser :: SubField m User
+  }
+  ```
+
+- `unsafeInternalContext` to get resolver context, use only if it really necessary.
+  the code depending on it may break even on minor version changes.
+  
+  ```hs
+  resolveUser :: ResolveQ EVENT IO User
+  resolveUser = do
+    Context { currentSelection, schema, operation } <- unsafeInternalContext
+    lift (getDBUser currentSelection)
+  ```
+
+### Minor
+
+- MonadIO instance for resolvers. Thanks @dandoh
+- Example using STM, authentication, monad transformers. Thanks @dandoh
+- added dependency `mtl`
+
 ## [0.9.1] - 02.01.2020
 
 - removed dependency `mtl`
diff --git a/morpheus-graphql.cabal b/morpheus-graphql.cabal
--- a/morpheus-graphql.cabal
+++ b/morpheus-graphql.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 0d4240eb95d5effb0f31f87c698a24d51c363a7197319f37b50f29999209a999
+-- hash: acb4d101970b68e1e9b3790252120726595167c2154a4861772462f29501c7bb
 
 name:           morpheus-graphql
-version:        0.9.1
+version:        0.10.0
 synopsis:       Morpheus GraphQL
 description:    Build GraphQL APIs with your favourite functional language!
 category:       web, graphql
@@ -341,8 +341,7 @@
       Data.Morpheus.Execution.Server.Interpreter
       Data.Morpheus.Execution.Server.Introspect
       Data.Morpheus.Execution.Server.Resolve
-      Data.Morpheus.Execution.Subscription.Apollo
-      Data.Morpheus.Execution.Subscription.ClientRegister
+      Data.Morpheus.Execution.Server.Subscription
       Data.Morpheus.Parsing.Document.Parser
       Data.Morpheus.Parsing.Document.TypeSystem
       Data.Morpheus.Parsing.Internal.Internal
@@ -363,6 +362,7 @@
       Data.Morpheus.Types.GQLScalar
       Data.Morpheus.Types.GQLType
       Data.Morpheus.Types.ID
+      Data.Morpheus.Types.Internal.Apollo
       Data.Morpheus.Types.Internal.AST.Base
       Data.Morpheus.Types.Internal.AST.Data
       Data.Morpheus.Types.Internal.AST.Selection
@@ -391,6 +391,7 @@
     , bytestring >=0.10.4 && <0.11
     , containers >=0.4.2.1 && <0.7
     , megaparsec >=7.0.0 && <9.0.0
+    , mtl >=2.0 && <=2.3
     , scientific >=0.3.6.2 && <0.4
     , template-haskell >=2.0 && <=2.16
     , text >=1.2.3.0 && <1.3
@@ -431,6 +432,7 @@
     , containers >=0.4.2.1 && <0.7
     , megaparsec >=7.0.0 && <9.0.0
     , morpheus-graphql
+    , mtl >=2.0 && <=2.3
     , scientific >=0.3.6.2 && <0.4
     , tasty
     , tasty-hunit
diff --git a/src/Data/Morpheus/Error/Selection.hs b/src/Data/Morpheus/Error/Selection.hs
--- a/src/Data/Morpheus/Error/Selection.hs
+++ b/src/Data/Morpheus/Error/Selection.hs
@@ -5,7 +5,6 @@
   , subfieldsNotSelected
   , duplicateQuerySelections
   , hasNoSubfields
-  , resolvingFailedError
   )
 where
 
@@ -22,13 +21,6 @@
 import           Data.Text                      ( Text )
 import qualified Data.Text                     as T
                                                 ( concat )
-
-
-resolvingFailedError :: Position -> Text -> Text -> GQLError
-resolvingFailedError position name reason = GQLError
-  { message   = "Failure on Resolving Field \"" <> name <> "\": " <> reason
-  , locations = [position]
-  }
 
 
 -- GQL: "Field \"default\" must not have a selection since type \"String!\" has no subfields."
diff --git a/src/Data/Morpheus/Execution/Document/Encode.hs b/src/Data/Morpheus/Execution/Document/Encode.hs
--- a/src/Data/Morpheus/Execution/Document/Encode.hs
+++ b/src/Data/Morpheus/Execution/Document/Encode.hs
@@ -34,7 +34,6 @@
                                                 ( Resolver
                                                 , MapStrategy(..)
                                                 , LiftOperation
-                                                , ResolvingStrategy
                                                 , DataResolver(..)
                                                 )
 import           Data.Morpheus.Types.Internal.TH
@@ -80,15 +79,13 @@
     | isSubscription typeKindD
     = [applyT ''MapStrategy $ map conT [''QUERY, ''SUBSCRIPTION]]
     | otherwise
-    = [ iLiftOp fo_ ''ResolvingStrategy
-      , iLiftOp fo_ ''Resolver
+    = [ iLiftOp fo_
       , typeT ''MapStrategy [fo_, po_]
       , iTypeable fo_
       , iTypeable po_
       ]
   -------------------------
-  iLiftOp op name =
-    applyT ''LiftOperation [varT $ mkName $ unpack op, conT name]
+  iLiftOp op = applyT ''LiftOperation [varT $ mkName $ unpack op]
   -------------------------
   iTypeable name = typeT ''Typeable [name]
   -------------------------------------------
diff --git a/src/Data/Morpheus/Execution/Server/Encode.hs b/src/Data/Morpheus/Execution/Server/Encode.hs
--- a/src/Data/Morpheus/Execution/Server/Encode.hs
+++ b/src/Data/Morpheus/Execution/Server/Encode.hs
@@ -34,7 +34,6 @@
 import           GHC.Generics
 
 -- MORPHEUS
-import           Data.Morpheus.Error.Internal   ( internalResolvingError )
 import           Data.Morpheus.Execution.Server.Decode
                                                 ( DecodeType
                                                 , decodeArguments
@@ -57,46 +56,43 @@
 import           Data.Morpheus.Types.Internal.AST
                                                 ( Name
                                                 , Operation(..)
-                                                , ValidOperation
-                                                , Key
                                                 , MUTATION
                                                 , OperationType
                                                 , QUERY
                                                 , SUBSCRIPTION
-                                                , Selection(..)
-                                                , SelectionContent(..)
-                                                , ValidSelection
                                                 , GQLValue(..)
                                                 , ValidValue
-                                                , ValidSelectionSet
                                                 )
 import           Data.Morpheus.Types.Internal.Resolving
                                                 ( MapStrategy(..)
                                                 , LiftOperation
-                                                , Resolver(..)
-                                                , resolving
+                                                , Resolver
+                                                , unsafeBind
                                                 , toResolver
-                                                , ResolvingStrategy(..)
-                                                , withObject
-                                                , Validation
-                                                , failure
                                                 , DataResolver(..)
                                                 , resolveObject
                                                 , resolve__typename
-                                                , resolveEnum
                                                 , FieldRes
+                                                , ResponseStream
+                                                , runResolver
+                                                , runDataResolver
+                                                , Context(..)
                                                 )
 
 class Encode resolver o e (m :: * -> *) where
-  encode :: resolver -> (Key, ValidSelection) -> ResolvingStrategy o e m ValidValue
+  encode :: resolver -> Resolver o e m ValidValue
 
-instance {-# OVERLAPPABLE #-} (EncodeKind (KIND a) a o e m , LiftOperation o ResolvingStrategy) => Encode a o e m where
+instance {-# OVERLAPPABLE #-} (EncodeKind (KIND a) a o e m , LiftOperation o) => Encode a o e m where
   encode resolver = encodeKind (VContext resolver :: VContext (KIND a) a)
 
 -- MAYBE
-instance (Monad m , LiftOperation o ResolvingStrategy,Encode a o e m) => Encode (Maybe a) o e m where
-  encode = maybe (const $ pure gqlNull) encode
+instance (Monad m , LiftOperation o,Encode a o e m) => Encode (Maybe a) o e m where
+  encode = maybe (pure gqlNull) encode
 
+-- LIST []
+instance (Monad m, Encode a o e m, LiftOperation o) => Encode [a] o e m where
+  encode = fmap gqlList . (traverse encode)
+
 --  Tuple  (a,b)
 instance Encode (Pair k v) o e m => Encode (k, v) o e m where
   encode (key, value) = encode (Pair key value)
@@ -106,68 +102,35 @@
   encode = encode . S.toList
 
 --  Map
-instance (Eq k, Monad m,LiftOperation o Resolver, Encode (MapKind k v (Resolver o e m)) o e m) => Encode (Map k v)  o e m where
+instance (Eq k, Monad m,LiftOperation o, Encode (MapKind k v (Resolver o e m)) o e m) => Encode (Map k v)  o e m where
   encode value =
     encode ((mapKindFromList $ M.toList value) :: MapKind k v (Resolver o e m))
 
--- LIST []
-instance (Monad m, Encode a o e m, LiftOperation o ResolvingStrategy) => Encode [a] o e m where
-  encode list query = gqlList <$> traverse (`encode` query) list
-
 --  GQL a -> Resolver b, MUTATION, SUBSCRIPTION, QUERY
-instance (DecodeType a,Generic a, Monad m,LiftOperation fo Resolver, MapStrategy fo o, Encode b fo e m) => Encode (a -> Resolver fo e m b) o e m where
-  encode resolver selection@(_, Selection { selectionArguments }) =
-    mapStrategy $ resolving encode (toResolver args resolver) selection
-   where
-    args :: Validation a
-    args = decodeArguments selectionArguments
+instance (DecodeType a,Generic a, Monad m,LiftOperation fo, MapStrategy fo o, Encode b fo e m) => Encode (a -> Resolver fo e m b) o e m where
+ encode resolver = mapStrategy $ (toResolver decodeArguments resolver) `unsafeBind` encode 
 
 --  GQL a -> Resolver b, MUTATION, SUBSCRIPTION, QUERY
-instance (Monad m,LiftOperation fo Resolver, MapStrategy fo o, Encode b fo e m) => Encode (Resolver fo e m b) o e m where
-  encode resolver = mapStrategy . resolving encode resolver
+instance (Monad m,LiftOperation fo, MapStrategy fo o, Encode b fo e m) => Encode (Resolver fo e m b) o e m where
+  encode = mapStrategy . (`unsafeBind` encode)
 
 -- ENCODE GQL KIND
 class EncodeKind (kind :: GQL_KIND) a o e (m :: * -> *) where
-  encodeKind :: LiftOperation o ResolvingStrategy =>  VContext kind a -> (Key, ValidSelection) -> ResolvingStrategy o e m ValidValue
+  encodeKind :: LiftOperation o =>  VContext kind a -> Resolver o e m ValidValue
 
 -- SCALAR
 instance (GQLScalar a, Monad m) => EncodeKind SCALAR a o e m where
-  encodeKind = pure . pure . gqlScalar . serialize . unVContext
+  encodeKind = pure . gqlScalar . serialize . unVContext
 
 -- ENUM
 instance (Generic a, EnumRep (Rep a), Monad m) => EncodeKind ENUM a o e m where
-  encodeKind = pure . pure . gqlString . encodeRep . from . unVContext
+  encodeKind = pure . gqlString . encodeRep . from . unVContext
 
 instance (Monad m,Generic a, GQLType a,ExploreResolvers (CUSTOM a) a o e m) => EncodeKind OUTPUT a o e m where
-  encodeKind (VContext value) (key, sel@Selection { selectionContent }) =
-    encodeNode (exploreResolvers (Proxy @(CUSTOM a)) value) selectionContent
-   where
-    encodeNode (ObjectRes fields) _ = withObject encodeObject (key, sel)
-     where
-      encodeObject selection =
-        resolveObject selection
-          $ ObjectRes
-          $ resolve__typename (__typeName (Proxy @a))
-          : fields
-    encodeNode (EnumRes enum) _ =
-      resolveEnum (__typeName (Proxy @a)) enum selectionContent
-    -- Type References --------------------------------------------------------------
-    encodeNode (UnionRef (fieldTypeName, fieldResolver)) (UnionSelection selections)
-      = fieldResolver
-        (key, sel { selectionContent = SelectionSet currentSelection })
-      where currentSelection = pickSelection fieldTypeName selections
-    -- RECORDS ----------------------------------------------------------------------------
-    encodeNode (UnionRes (name, fields)) (UnionSelection selections) =
-      resolveObject selection resolvers
-     where
-      selection = pickSelection name selections
-      resolvers = ObjectRes (resolve__typename name : fields)
-    encodeNode _ _ = failure $ internalResolvingError
-      "union Resolver should only recieve UnionSelection"
-
+  encodeKind (VContext value) = runDataResolver (__typeName (Proxy @a)) (exploreResolvers (Proxy @(CUSTOM a)) value)
 
 convertNode
-  :: (Monad m, LiftOperation o ResolvingStrategy)
+  :: (Monad m, LiftOperation o)
   => ResNode o e m
   -> DataResolver o e m
 convertNode ResNode { resKind = REP_OBJECT, resFields } =
@@ -191,8 +154,7 @@
 -- Types & Constrains -------------------------------------------------------
 type GQL_RES a = (Generic a, GQLType a)
 
-type EncodeOperator o e m a
-  = a -> ValidOperation -> ResolvingStrategy o e m ValidValue
+type EncodeOperation e m a = a -> Context -> ResponseStream e m ValidValue
 
 type EncodeCon o e m a = (GQL_RES a, ExploreResolvers (CUSTOM a) a o e m)
 
@@ -212,7 +174,7 @@
 class ExploreResolvers (custom :: Bool) a (o :: OperationType) e (m :: * -> *) where
   exploreResolvers :: Proxy custom -> a -> DataResolver o e m
 
-instance (Generic a,Monad m,LiftOperation o ResolvingStrategy,TypeRep (Rep a) o e m ) => ExploreResolvers 'False a o e m where
+instance (Generic a,Monad m,LiftOperation o,TypeRep (Rep a) o e m ) => ExploreResolvers 'False a o e m where
   exploreResolvers _ value = convertNode
     $ typeResolvers (ResContext :: ResContext OUTPUT o e m value) (from value)
 
@@ -224,8 +186,9 @@
      , EncodeCon QUERY event m query
      )
   => schema (Resolver QUERY event m)
-  -> EncodeOperator QUERY event m query
+  -> EncodeOperation event m query
 encodeQuery schema = encodeOperationWith
+  (Proxy @QUERY)
   (Just $ objectResolvers
     (Proxy :: Proxy (CUSTOM (schema (Resolver QUERY event m))))
     schema
@@ -234,22 +197,23 @@
 encodeMutation
   :: forall event m mut
    . (Monad m, EncodeCon MUTATION event m mut)
-  => EncodeOperator MUTATION event m mut
-encodeMutation = encodeOperationWith Nothing
+  => EncodeOperation event m mut
+encodeMutation = encodeOperationWith (Proxy @MUTATION) Nothing
 
 encodeSubscription
   :: forall m event mut
    . (Monad m, EncodeCon SUBSCRIPTION event m mut)
-  => EncodeOperator SUBSCRIPTION event m mut
-encodeSubscription = encodeOperationWith Nothing
+  => EncodeOperation event m mut
+encodeSubscription = encodeOperationWith (Proxy @SUBSCRIPTION) Nothing
 
 encodeOperationWith
-  :: forall o e m a
-   . (Monad m, EncodeCon o e m a, LiftOperation o ResolvingStrategy)
-  => Maybe (DataResolver o e m)
-  -> EncodeOperator o e m a
-encodeOperationWith externalRes rootResolver Operation { operationSelection } =
-  resolveObject operationSelection (rootDataRes <> extDataRes)
+  :: forall (o :: OperationType) e m a
+   . (Monad m, EncodeCon o e m a, LiftOperation o)
+  => Proxy o
+  -> Maybe (DataResolver o e m)
+  -> EncodeOperation e m a
+encodeOperationWith _ externalRes rootResolver ctx@Context { operation = Operation { operationSelection } } =
+  runResolver (resolveObject operationSelection (rootDataRes <> extDataRes)) ctx
  where
   rootDataRes = objectResolvers (Proxy :: Proxy (CUSTOM a)) rootResolver
   extDataRes  = fromMaybe (ObjectRes []) externalRes
@@ -260,10 +224,6 @@
 
 
 -- NEW AUTOMATIC DERIVATION SYSTEM
-
-pickSelection :: Name -> [(Name, ValidSelectionSet)] -> ValidSelectionSet
-pickSelection name = fromMaybe [] . lookup name
-
 data REP_KIND = REP_UNION | REP_OBJECT
 
 data ResNode o e m = ResNode {
@@ -277,7 +237,7 @@
 data FieldNode o e m = FieldNode {
     fieldTypeName :: Name,
     fieldSelName :: Name,
-    fieldResolver  :: (Key, ValidSelection) -> ResolvingStrategy o e m ValidValue,
+    fieldResolver  :: Resolver o e m ValidValue,
     isFieldObject  :: Bool
   }
 
@@ -329,4 +289,3 @@
 
 instance FieldRep U1 o e m where
   fieldRep _ _ = []
-
diff --git a/src/Data/Morpheus/Execution/Server/Interpreter.hs b/src/Data/Morpheus/Execution/Server/Interpreter.hs
--- a/src/Data/Morpheus/Execution/Server/Interpreter.hs
+++ b/src/Data/Morpheus/Execution/Server/Interpreter.hs
@@ -35,7 +35,7 @@
                                                 , streamResolver
                                                 , coreResolver
                                                 )
-import           Data.Morpheus.Execution.Subscription.ClientRegister
+import           Data.Morpheus.Execution.Server.Subscription
                                                 ( GQLState )
 import           Data.Morpheus.Types.Internal.Resolving
                                                 ( GQLRootResolver(..)
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,9 +42,9 @@
                                                 , introspectObjectFields
                                                 , TypeScope(..)
                                                 )
-import           Data.Morpheus.Execution.Subscription.ClientRegister
+import           Data.Morpheus.Execution.Server.Subscription
                                                 ( GQLState
-                                                , publishUpdates
+                                                , publishEvent
                                                 )
 import           Data.Morpheus.Parsing.Request.Parser
                                                 ( parseGQL )
@@ -56,7 +56,6 @@
 import           Data.Morpheus.Types.GQLType    ( GQLType(CUSTOM) )
 import           Data.Morpheus.Types.Internal.AST
                                                 ( Operation(..)
-                                                , ValidOperation
                                                 , DataFingerprint(..)
                                                 , DataTypeContent(..)
                                                 , Schema(..)
@@ -70,11 +69,12 @@
                                                 , Name
                                                 , DataField
                                                 , VALIDATION_MODE(..)
+                                                , Selection(..)
+                                                , SelectionContent(..)
                                                 )
 import           Data.Morpheus.Types.Internal.Resolving
                                                 ( GQLRootResolver(..)
-                                                , Resolver(..)
-                                                , toResponseRes
+                                                , Resolver
                                                 , GQLChannel(..)
                                                 , ResponseEvent(..)
                                                 , ResponseStream
@@ -84,6 +84,7 @@
                                                 , unpackEvents
                                                 , Failure(..)
                                                 , resolveUpdates
+                                                , Context(..)
                                                 )
 import           Data.Morpheus.Types.IO         ( GQLRequest(..)
                                                 , GQLResponse(..)
@@ -145,6 +146,7 @@
 streamResolver root req =
   ResultT $ pure . renderResponse <$> runResultT (coreResolver root req)
 
+
 coreResolver
   :: forall event m query mut sub
    . (Monad m, RootResCon m event query mut sub)
@@ -155,22 +157,30 @@
   = validRequest >>= execOperator
  where
   validRequest
-    :: Monad m => ResponseStream event m (Schema, ValidOperation)
+    :: Monad m => ResponseStream event m Context
   validRequest = cleanEvents $ ResultT $ pure $ do
-    schema <- fullSchema $ Identity root
-    query  <- parseGQL request >>= validateRequest schema FULL_VALIDATION
-    pure (schema, query)
+    schema     <- fullSchema $ Identity root
+    operation  <- parseGQL request >>= validateRequest schema FULL_VALIDATION
+    pure $ Context {
+        schema
+      , operation
+      , currentSelection = (
+        "Root"
+        , Selection {
+          selectionArguments = []
+          , selectionPosition = (operationPosition operation)
+          , selectionAlias = Nothing
+          , selectionContent = SelectionSet (operationSelection operation)
+        } 
+    )
+  }
   ----------------------------------------------------------
-  execOperator (schema, operation@Operation { operationType = Query }) =
-    toResponseRes (encodeQuery (schemaAPI schema) queryResolver operation)
-  execOperator (_, operation@Operation { operationType = Mutation }) =
-    toResponseRes (encodeMutation mutationResolver operation)
-  execOperator (_, operation@Operation { operationType = Subscription }) =
-    response
-   where
-    response =
-      toResponseRes (encodeSubscription subscriptionResolver operation)
-
+  execOperator ctx@Context {schema ,operation = Operation{ operationType} } = execOperationBy operationType ctx
+    where
+      execOperationBy Query = encodeQuery (schemaAPI schema) queryResolver
+      execOperationBy Mutation = encodeMutation mutationResolver
+      execOperationBy Subscription = encodeSubscription subscriptionResolver
+    
 statefulResolver
   :: (EventCon event, MonadIO m)
   => GQLState m event
@@ -182,7 +192,7 @@
   mapM_ execute (unpackEvents res)
   pure $ encode $ renderResponse res
  where
-  execute (Publish updates) = publishUpdates state updates
+  execute (Publish events) = publishEvent state events
   execute Subscribe{}       = pure ()
 
 fullSchema
diff --git a/src/Data/Morpheus/Execution/Server/Subscription.hs b/src/Data/Morpheus/Execution/Server/Subscription.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Morpheus/Execution/Server/Subscription.hs
@@ -0,0 +1,105 @@
+{-# LANGUAGE NamedFieldPuns , FlexibleContexts #-}
+
+module Data.Morpheus.Execution.Server.Subscription
+  ( ClientDB
+  , GQLState
+  , initGQLState
+  , connectClient
+  , disconnectClient
+  , startSubscription
+  , endSubscription
+  , publishEvent
+  )
+where
+
+import           Control.Monad.IO.Class         ( MonadIO(liftIO) )
+import           Control.Concurrent             ( MVar
+                                                , modifyMVar
+                                                , modifyMVar_
+                                                , newMVar
+                                                , readMVar
+                                                )
+import           Data.Foldable                  ( traverse_ )
+import           Data.List                      ( intersect )
+import           Data.UUID.V4                   ( nextRandom )
+import           Network.WebSockets             ( Connection
+                                                , sendTextData
+                                                )
+import           Data.HashMap.Lazy              ( empty
+                                                , insert
+                                                , delete
+                                                , adjust
+                                                , toList
+                                                )
+
+-- MORPHEUS
+import           Data.Morpheus.Types.Internal.Apollo
+                                                ( toApolloResponse )
+import           Data.Morpheus.Types.Internal.Resolving
+                                                ( Event(..)
+                                                , GQLChannel(..)
+                                                , SubEvent
+                                                )
+import           Data.Morpheus.Types.Internal.WebSocket
+                                                ( ClientID
+                                                , GQLClient(..)
+                                                , ClientDB
+                                                , GQLState
+                                                , SesionID
+                                                )
+
+-- | initializes empty GraphQL state
+initGQLState :: IO (GQLState m e)
+initGQLState = newMVar empty
+ 
+connectClient :: MonadIO m => Connection -> GQLState m e -> IO (GQLClient m e)
+connectClient clientConnection gqlState = do
+  clientID <- nextRandom
+  let client = GQLClient { clientID , clientConnection, clientSessions = empty }
+  modifyMVar_ gqlState (pure . insert clientID client)
+  return client
+
+disconnectClient :: GQLClient m e -> GQLState m e -> IO (ClientDB m e)
+disconnectClient GQLClient { clientID } state = modifyMVar state removeUser
+ where
+  removeUser db = let s' = delete clientID db in return (s', s')
+
+updateClientByID
+  :: MonadIO m =>
+     ClientID
+  -> (GQLClient m e -> GQLClient m e)
+  -> MVar (ClientDB m e)
+  -> m ()
+updateClientByID key f state = liftIO $ modifyMVar_ state (return . adjust f key)
+
+publishEvent
+  :: (Eq (StreamChannel e), GQLChannel e, MonadIO m) => GQLState m e -> e -> m ()
+publishEvent gqlState event = liftIO (readMVar gqlState) >>= traverse_ sendMessage 
+ where
+  sendMessage GQLClient { clientSessions, clientConnection } 
+    | null clientSessions  = return ()
+    | otherwise = mapM_ send (filterByChannels clientSessions)
+   where
+    send (sid, Event { content = subscriptionRes }) = do
+      res <- subscriptionRes event
+      let apolloRes = toApolloResponse sid res
+      liftIO $ sendTextData clientConnection apolloRes
+    ---------------------------
+    filterByChannels = filter
+      ( not
+      . null
+      . intersect (streamChannels event)
+      . channels
+      . snd
+      ) . toList
+
+endSubscription :: MonadIO m => ClientID -> SesionID -> GQLState m e -> m ()
+endSubscription cid sid = updateClientByID cid stopSubscription
+ where
+  stopSubscription client = client { clientSessions = delete sid (clientSessions client) }
+
+startSubscription :: MonadIO m => ClientID -> SubEvent m e -> SesionID -> GQLState m e -> m ()
+startSubscription cid subscriptions sid = updateClientByID cid startSubscription
+ where
+  startSubscription client = client
+    { clientSessions = insert sid subscriptions (clientSessions client) }
diff --git a/src/Data/Morpheus/Execution/Subscription/Apollo.hs b/src/Data/Morpheus/Execution/Subscription/Apollo.hs
deleted file mode 100644
--- a/src/Data/Morpheus/Execution/Subscription/Apollo.hs
+++ /dev/null
@@ -1,92 +0,0 @@
-{-# LANGUAGE DeriveGeneric     #-}
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE NamedFieldPuns    #-}
-{-# LANGUAGE OverloadedStrings #-}
-
-module Data.Morpheus.Execution.Subscription.Apollo
-  ( SubAction(..)
-  , apolloFormat
-  , acceptApolloSubProtocol
-  , toApolloResponse
-  ) where
-
-import           Data.Aeson                 (FromJSON (..), ToJSON (..), Value (..), eitherDecode, encode, pairs,
-                                             withObject, (.:), (.:?), (.=))
-import           Data.ByteString.Lazy.Char8 (ByteString)
-import           Data.Morpheus.Types        (GQLRequest (..))
-import           Data.Morpheus.Types.IO     (GQLResponse)
-import           Data.Semigroup             ((<>))
-import           Data.Text                  (Text)
-import           GHC.Generics               (Generic)
-import           Network.WebSockets         (AcceptRequest (..), RequestHead, getRequestSubprotocols)
-
-type ApolloID = Text
-
-data ApolloSubscription payload =
-  ApolloSubscription
-    { apolloId      :: Maybe ApolloID
-    , apolloType    :: Text
-    , apolloPayload :: Maybe payload
-    }
-  deriving (Show, Generic)
-
-instance FromJSON a => FromJSON (ApolloSubscription a) where
-  parseJSON = withObject "ApolloSubscription" objectParser
-    where
-      objectParser o =
-        ApolloSubscription <$> o .:? "id" <*> o .: "type" <*> o .:? "payload"
-
-data RequestPayload =
-  RequestPayload
-    { payloadOperationName :: Maybe Text
-    , payloadQuery         :: Maybe Text
-    , payloadVariables     :: Maybe Value
-    }
-  deriving (Show, Generic)
-
-instance FromJSON RequestPayload where
-  parseJSON = withObject "ApolloPayload" objectParser
-    where
-      objectParser o =
-        RequestPayload <$> o .:? "operationName" <*> o .:? "query" <*>
-        o .:? "variables"
-
-instance ToJSON a => ToJSON (ApolloSubscription a) where
-  toEncoding (ApolloSubscription id' type' payload') =
-    pairs $ "id" .= id' <> "type" .= type' <> "payload" .= payload'
-
-acceptApolloSubProtocol :: RequestHead -> AcceptRequest
-acceptApolloSubProtocol reqHead =
-  apolloProtocol (getRequestSubprotocols reqHead)
-  where
-    apolloProtocol ["graphql-subscriptions"] =
-      AcceptRequest (Just "graphql-subscriptions") []
-    apolloProtocol ["graphql-ws"] = AcceptRequest (Just "graphql-ws") []
-    apolloProtocol _ = AcceptRequest Nothing []
-
-toApolloResponse :: ApolloID -> GQLResponse -> ByteString
-toApolloResponse sid val =
-  encode $ ApolloSubscription (Just sid) "data" (Just val)
-
-data SubAction
-  = RemoveSub ApolloID
-  | AddSub ApolloID GQLRequest
-  | SubError String
-
-apolloFormat :: ByteString -> SubAction
-apolloFormat = toWsAPI . eitherDecode
-  where
-    toWsAPI :: Either String (ApolloSubscription RequestPayload) -> SubAction
-    toWsAPI (Right ApolloSubscription { apolloType = "start"
-                                      , apolloId = Just sessionId
-                                      , apolloPayload = Just RequestPayload { payloadQuery = Just query
-                                                                            , payloadOperationName = operationName
-                                                                            , payloadVariables = variables
-                                                                            }
-                                      }) =
-      AddSub sessionId (GQLRequest {query, operationName, variables})
-    toWsAPI (Right ApolloSubscription { apolloType = "stop"
-                                      , apolloId = Just sessionId
-                                      }) = RemoveSub sessionId
-    toWsAPI (Right x) = SubError (show x)
-    toWsAPI (Left x) = SubError x
diff --git a/src/Data/Morpheus/Execution/Subscription/ClientRegister.hs b/src/Data/Morpheus/Execution/Subscription/ClientRegister.hs
deleted file mode 100644
--- a/src/Data/Morpheus/Execution/Subscription/ClientRegister.hs
+++ /dev/null
@@ -1,126 +0,0 @@
-{-# LANGUAGE NamedFieldPuns , FlexibleContexts #-}
-
-module Data.Morpheus.Execution.Subscription.ClientRegister
-  ( ClientRegister
-  , GQLState
-  , initGQLState
-  , connectClient
-  , disconnectClient
-  , updateClientByID
-  , publishUpdates
-  , addClientSubscription
-  , removeClientSubscription
-  )
-where
-
-import           Control.Monad.IO.Class         ( MonadIO(liftIO) )
-import           Control.Concurrent             ( MVar
-                                                , modifyMVar
-                                                , modifyMVar_
-                                                , newMVar
-                                                , readMVar
-                                                )
-import           Data.Foldable                  ( traverse_ )
-import           Data.List                      ( intersect )
-import           Data.Text                      ( Text )
-import           Data.UUID.V4                   ( nextRandom )
-import           Network.WebSockets             ( Connection
-                                                , sendTextData
-                                                )
--- MORPHEUS
-import           Data.Morpheus.Execution.Subscription.Apollo
-                                                ( toApolloResponse )
-import           Data.Morpheus.Types.Internal.Resolving
-                                                ( Event(..)
-                                                , GQLChannel(..)
-                                                , SubEvent
-                                                )
-import           Data.Morpheus.Types.Internal.WebSocket
-                                                ( ClientID
-                                                , ClientSession(..)
-                                                , GQLClient(..)
-                                                )
-
-type ClientRegister m e = [(ClientID, GQLClient m e)]
-
--- | shared GraphQL state between __websocket__ and __http__ server,
--- stores information about subscriptions
-type GQLState m e = MVar (ClientRegister m e) -- SharedState
-
--- | initializes empty GraphQL state
-initGQLState :: IO (GQLState m e)
-initGQLState = newMVar []
-
-connectClient :: MonadIO m => Connection -> GQLState m e -> IO (GQLClient m e)
-connectClient clientConnection varState' = do
-  client' <- newClient
-  modifyMVar_ varState' (addClient client')
-  return (snd client')
- where
-  newClient = do
-    clientID <- nextRandom
-    return
-      (clientID, GQLClient { clientID, clientConnection, clientSessions = [] })
-  addClient client' state' = return (client' : state')
-
-disconnectClient :: GQLClient m e -> GQLState m e -> IO (ClientRegister m e)
-disconnectClient client state = modifyMVar state removeUser
- where
-  removeUser state' = let s' = removeClient state' in return (s', s')
-  removeClient :: ClientRegister m e -> ClientRegister m e
-  removeClient = filter ((/= clientID client) . fst)
-
-updateClientByID
-  :: MonadIO m =>
-     ClientID
-  -> (GQLClient m e -> GQLClient m e)
-  -> MVar (ClientRegister m e)
-  -> m ()
-updateClientByID id' updateFunc state = liftIO $ modifyMVar_
-  state
-  (return . map updateClient)
- where
-  updateClient (key, client') | key == id' = (key, updateFunc client')
-  updateClient state'                      = state'
-
-publishUpdates
-  :: (Eq (StreamChannel e), GQLChannel e, MonadIO m) => GQLState m e -> e -> m ()
-publishUpdates state event = do
-  state' <- liftIO $ readMVar state
-  traverse_ sendMessage state'
- where
-  sendMessage (_, GQLClient { clientSessions = [] }             ) = return ()
-  sendMessage (_, GQLClient { clientSessions, clientConnection }) = mapM_
-    __send
-    (filterByChannels clientSessions)
-   where
-    __send ClientSession { sessionId, sessionSubscription = Event { content = subscriptionRes } } = do
-      res <- subscriptionRes event
-      let apolloRes = toApolloResponse sessionId res
-      liftIO $ sendTextData clientConnection apolloRes
-    ---------------------------
-    filterByChannels = filter
-      ( not
-      . null
-      . intersect (streamChannels event)
-      . channels
-      . sessionSubscription
-      )
-
-removeClientSubscription :: MonadIO m => ClientID -> Text -> GQLState m e -> m ()
-removeClientSubscription id' sid' = updateClientByID id' stopSubscription
- where
-  stopSubscription client' = client'
-    { clientSessions = filter ((sid' /=) . sessionId) (clientSessions client')
-    }
-
-addClientSubscription
-  :: MonadIO m => ClientID -> SubEvent m e -> Text -> GQLState m e -> m ()
-addClientSubscription id' sessionSubscription sessionId = updateClientByID
-  id'
-  startSubscription
- where
-  startSubscription client' = client'
-    { clientSessions = ClientSession { sessionId, sessionSubscription }
-                         : clientSessions client'
-    }
diff --git a/src/Data/Morpheus/Schema/SchemaAPI.hs b/src/Data/Morpheus/Schema/SchemaAPI.hs
--- a/src/Data/Morpheus/Schema/SchemaAPI.hs
+++ b/src/Data/Morpheus/Schema/SchemaAPI.hs
@@ -41,7 +41,7 @@
                                                 , lookupDataType
                                                 )
 import           Data.Morpheus.Types.Internal.Resolving
-                                                ( Resolver(..)
+                                                ( Resolver
                                                 , resolveUpdates
                                                 )
 
diff --git a/src/Data/Morpheus/Server.hs b/src/Data/Morpheus/Server.hs
--- a/src/Data/Morpheus/Server.hs
+++ b/src/Data/Morpheus/Server.hs
@@ -30,20 +30,20 @@
                                                 ( RootResCon
                                                 , coreResolver
                                                 )
-import           Data.Morpheus.Execution.Subscription.Apollo
+import           Data.Morpheus.Types.Internal.Apollo
                                                 ( SubAction(..)
                                                 , acceptApolloSubProtocol
                                                 , apolloFormat
                                                 , toApolloResponse
                                                 )
-import           Data.Morpheus.Execution.Subscription.ClientRegister
+import           Data.Morpheus.Execution.Server.Subscription
                                                 ( GQLState
-                                                , addClientSubscription
                                                 , connectClient
                                                 , disconnectClient
                                                 , initGQLState
-                                                , publishUpdates
-                                                , removeClientSubscription
+                                                , publishEvent
+                                                , startSubscription
+                                                , endSubscription
                                                 )
 import           Data.Morpheus.Types.Internal.Resolving
                                                 ( GQLRootResolver(..)
@@ -75,8 +75,8 @@
         clientConnection
         (toApolloResponse sessionId $ Errors errors)
  where
-  execute (Publish   pub) = publishUpdates state pub
-  execute (Subscribe sub) = addClientSubscription clientID sub sessionId state
+  execute (Publish   pub) = publishEvent state pub
+  execute (Subscribe sub) = startSubscription clientID sub sessionId state
 
 -- | Wai WebSocket Server App for GraphQL subscriptions
 gqlSocketMonadIOApp
@@ -102,7 +102,7 @@
       resolveMessage (AddSub sessionId request) =
         handleSubscription client state sessionId (coreResolver gqlRoot request)
       resolveMessage (RemoveSub sessionId) =
-        removeClientSubscription (clientID client) sessionId state
+        endSubscription (clientID client) sessionId state
 
 -- | Same as above but specific to IO
 gqlSocketApp
diff --git a/src/Data/Morpheus/Types.hs b/src/Data/Morpheus/Types.hs
--- a/src/Data/Morpheus/Types.hs
+++ b/src/Data/Morpheus/Types.hs
@@ -21,7 +21,7 @@
   , IORes
   , IOMutRes
   , IOSubRes
-  , Resolver(..)
+  , Resolver
   , QUERY
   , MUTATION
   , SUBSCRIPTION
@@ -32,6 +32,10 @@
   , ResolveS
   , failRes
   , WithOperation
+  , publish
+  , subscribe
+  , unsafeInternalContext
+  , SubField
   )
 where
 
@@ -57,11 +61,16 @@
 import           Data.Morpheus.Types.Internal.Resolving
                                                 ( Event(..)
                                                 , GQLRootResolver(..)
-                                                , Resolver(..)
+                                                , Resolver
                                                 , WithOperation
                                                 , lift
                                                 , failure
                                                 , Failure
+                                                , pushEvents
+                                                , PushEvents(..)
+                                                , subscribe
+                                                , unsafeInternalContext
+                                                , UnSubResolver
                                                 )
 import           Data.Morpheus.Types.IO         ( GQLRequest(..)
                                                 , GQLResponse(..)
@@ -81,12 +90,20 @@
 type ResolveM e m a = MutRes e m (a (MutRes e m))
 type ResolveS e m a = SubRes e m (a (Res e m))
 
+-- Subsciption Object Resolver Fields
+type SubField m a = (m (a (UnSubResolver m))) 
+
+publish :: Monad m => [e] -> Resolver MUTATION e m ()
+publish = pushEvents
+
 -- resolves constant value on any argument
 constRes :: (WithOperation o, Monad m) => b -> a -> Resolver o e m b
 constRes = const . pure
 
 constMutRes :: Monad m => [e] -> a -> args -> MutRes e m a
-constMutRes events value = const $ MutResolver $ pure (events, value)
+constMutRes events value = const $ do 
+  publish events  
+  pure value
 
 failRes :: (WithOperation o, Monad m) => String -> Resolver o e m a
 failRes = failure . pack
diff --git a/src/Data/Morpheus/Types/GQLType.hs b/src/Data/Morpheus/Types/GQLType.hs
--- a/src/Data/Morpheus/Types/GQLType.hs
+++ b/src/Data/Morpheus/Types/GQLType.hs
@@ -43,7 +43,7 @@
                                                 , QUERY
                                                 )
 import           Data.Morpheus.Types.Internal.Resolving
-                                                ( Resolver(..) )
+                                                ( Resolver )
 
 type TRUE = 'True
 
diff --git a/src/Data/Morpheus/Types/Internal/Apollo.hs b/src/Data/Morpheus/Types/Internal/Apollo.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Morpheus/Types/Internal/Apollo.hs
@@ -0,0 +1,92 @@
+{-# LANGUAGE DeriveGeneric     #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE NamedFieldPuns    #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+module Data.Morpheus.Types.Internal.Apollo
+  ( SubAction(..)
+  , apolloFormat
+  , acceptApolloSubProtocol
+  , toApolloResponse
+  ) where
+
+import           Data.Aeson                 (FromJSON (..), ToJSON (..), Value (..), eitherDecode, encode, pairs,
+                                             withObject, (.:), (.:?), (.=))
+import           Data.ByteString.Lazy.Char8 (ByteString)
+import           Data.Morpheus.Types        (GQLRequest (..))
+import           Data.Morpheus.Types.IO     (GQLResponse)
+import           Data.Semigroup             ((<>))
+import           Data.Text                  (Text)
+import           GHC.Generics               (Generic)
+import           Network.WebSockets         (AcceptRequest (..), RequestHead, getRequestSubprotocols)
+
+type ApolloID = Text
+
+data ApolloSubscription payload =
+  ApolloSubscription
+    { apolloId      :: Maybe ApolloID
+    , apolloType    :: Text
+    , apolloPayload :: Maybe payload
+    }
+  deriving (Show, Generic)
+
+instance FromJSON a => FromJSON (ApolloSubscription a) where
+  parseJSON = withObject "ApolloSubscription" objectParser
+    where
+      objectParser o =
+        ApolloSubscription <$> o .:? "id" <*> o .: "type" <*> o .:? "payload"
+
+data RequestPayload =
+  RequestPayload
+    { payloadOperationName :: Maybe Text
+    , payloadQuery         :: Maybe Text
+    , payloadVariables     :: Maybe Value
+    }
+  deriving (Show, Generic)
+
+instance FromJSON RequestPayload where
+  parseJSON = withObject "ApolloPayload" objectParser
+    where
+      objectParser o =
+        RequestPayload <$> o .:? "operationName" <*> o .:? "query" <*>
+        o .:? "variables"
+
+instance ToJSON a => ToJSON (ApolloSubscription a) where
+  toEncoding (ApolloSubscription id' type' payload') =
+    pairs $ "id" .= id' <> "type" .= type' <> "payload" .= payload'
+
+acceptApolloSubProtocol :: RequestHead -> AcceptRequest
+acceptApolloSubProtocol reqHead =
+  apolloProtocol (getRequestSubprotocols reqHead)
+  where
+    apolloProtocol ["graphql-subscriptions"] =
+      AcceptRequest (Just "graphql-subscriptions") []
+    apolloProtocol ["graphql-ws"] = AcceptRequest (Just "graphql-ws") []
+    apolloProtocol _ = AcceptRequest Nothing []
+
+toApolloResponse :: ApolloID -> GQLResponse -> ByteString
+toApolloResponse sid val =
+  encode $ ApolloSubscription (Just sid) "data" (Just val)
+
+data SubAction
+  = RemoveSub ApolloID
+  | AddSub ApolloID GQLRequest
+  | SubError String
+
+apolloFormat :: ByteString -> SubAction
+apolloFormat = toWsAPI . eitherDecode
+  where
+    toWsAPI :: Either String (ApolloSubscription RequestPayload) -> SubAction
+    toWsAPI (Right ApolloSubscription { apolloType = "start"
+                                      , apolloId = Just sessionId
+                                      , apolloPayload = Just RequestPayload { payloadQuery = Just query
+                                                                            , payloadOperationName = operationName
+                                                                            , payloadVariables = variables
+                                                                            }
+                                      }) =
+      AddSub sessionId (GQLRequest {query, operationName, variables})
+    toWsAPI (Right ApolloSubscription { apolloType = "stop"
+                                      , apolloId = Just sessionId
+                                      }) = RemoveSub sessionId
+    toWsAPI (Right x) = SubError (show x)
+    toWsAPI (Left x) = SubError x
diff --git a/src/Data/Morpheus/Types/Internal/Resolving.hs b/src/Data/Morpheus/Types/Internal/Resolving.hs
--- a/src/Data/Morpheus/Types/Internal/Resolving.hs
+++ b/src/Data/Morpheus/Types/Internal/Resolving.hs
@@ -2,14 +2,12 @@
     ( Event(..)
     , GQLRootResolver(..)
     , UnSubResolver
-    , Resolver(..)
-    , ResolvingStrategy(..)
+    , Resolver
     , MapStrategy(..)
     , LiftOperation
     , resolveObject
-    , toResponseRes
-    , withObject
-    , resolving
+    , runResolver
+    , unsafeBind
     , toResolver
     , lift
     , SubEvent
@@ -27,11 +25,15 @@
     , GQLErrors
     , GQLError(..)
     , Position
-    , resolveEnum
     , resolve__typename
     , DataResolver(..)
     , FieldRes
     , WithOperation
+    , PushEvents(..)
+    , runDataResolver
+    , subscribe
+    , Context(..)
+    , unsafeInternalContext
     )
 where
 
diff --git a/src/Data/Morpheus/Types/Internal/Resolving/Core.hs b/src/Data/Morpheus/Types/Internal/Resolving/Core.hs
--- a/src/Data/Morpheus/Types/Internal/Resolving/Core.hs
+++ b/src/Data/Morpheus/Types/Internal/Resolving/Core.hs
@@ -1,12 +1,15 @@
-{-# LANGUAGE FlexibleInstances     #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE DeriveFunctor         #-}
-{-# LANGUAGE DeriveAnyClass        #-}
-{-# LANGUAGE DeriveGeneric         #-}
-{-# LANGUAGE DataKinds             #-}
-{-# LANGUAGE PolyKinds             #-}
-{-# LANGUAGE NamedFieldPuns        #-}
-{-# LANGUAGE OverloadedStrings     #-}
+{-# LANGUAGE FlexibleInstances          #-}
+{-# LANGUAGE MultiParamTypeClasses      #-}
+{-# LANGUAGE DeriveFunctor              #-}
+{-# LANGUAGE DeriveAnyClass             #-}
+{-# LANGUAGE DeriveGeneric              #-}
+{-# LANGUAGE DataKinds                  #-}
+{-# LANGUAGE PolyKinds                  #-}
+{-# LANGUAGE NamedFieldPuns             #-}
+{-# LANGUAGE OverloadedStrings          #-}
+{-# LANGUAGE TypeFamilies               #-}
+{-# LANGUAGE FlexibleContexts           #-}
+{-# LANGUAGE UndecidableInstances       #-}
 
 module Data.Morpheus.Types.Internal.Resolving.Core
   ( GQLError(..)
@@ -16,15 +19,16 @@
   , Result(..)
   , Failure(..)
   , ResultT(..)
-  , fromEither
-  , fromEitherSingle
   , unpackEvents
   , LibUpdater
   , resolveUpdates
   , mapEvent
-  , mapFailure
   , cleanEvents
   , StatelessResT
+  , Event(..)
+  , Channel(..)
+  , GQLChannel(..)
+  , PushEvents(..)
   )
 where
 
@@ -64,6 +68,39 @@
 type StatelessResT = ResultT () GQLError 'True
 type Validation = Result () GQLError 'True
 
+
+-- EVENTS
+class PushEvents e m where 
+  pushEvents :: [e] -> m () 
+
+-- Channel
+newtype Channel event = Channel {
+  _unChannel :: StreamChannel event
+}
+
+instance (Eq (StreamChannel event)) => Eq (Channel event) where
+  Channel x == Channel y = x == y
+
+class GQLChannel a where
+  type StreamChannel a :: *
+  streamChannels :: a -> [Channel a]
+
+instance GQLChannel () where
+  type StreamChannel () = ()
+  streamChannels _ = []
+
+instance GQLChannel (Event channel content)  where
+  type StreamChannel (Event channel content) = channel
+  streamChannels Event { channels } = map Channel channels
+
+data Event e c = Event
+  { channels :: [e], content  :: c}
+
+
+unpackEvents :: Result event c e a -> [event]
+unpackEvents Success { events } = events
+unpackEvents _                  = []
+
 --
 -- Result
 --
@@ -93,18 +130,10 @@
   failure text =
     Failure [GQLError { message = "INTERNAL ERROR: " <> text, locations = [] }]
 
-unpackEvents :: Result event c e a -> [event]
-unpackEvents Success { events } = events
-unpackEvents _                  = []
+instance PushEvents events (Result events err con) where
+  pushEvents events = Success { result = (), warnings = [], events } 
 
-fromEither :: Either [er] a -> Result ev er co a
-fromEither (Left  e) = Failure e
-fromEither (Right a) = Success a [] []
 
-fromEitherSingle :: Either er a -> Result ev er co a
-fromEitherSingle (Left  e) = Failure [e]
-fromEitherSingle (Right a) = Success a [] []
-
 -- ResultT
 newtype ResultT event error (concurency :: Bool)  (m :: * -> * ) a = ResultT { runResultT :: m (Result event error concurency a )  }
   deriving (Functor)
@@ -135,6 +164,13 @@
   failure x =
     ResultT $ pure $ Failure [GQLError { message = pack x, locations = [] }]
 
+instance Monad m => Failure GQLErrors (ResultT event GQLError concurency m) where
+  failure = ResultT . pure . failure
+
+instance Applicative m => PushEvents events (ResultT events err con m) where
+  pushEvents = ResultT . pure . pushEvents
+
+
 cleanEvents
   :: Functor m
   => ResultT e1 error concurency m a
@@ -154,17 +190,6 @@
   mapEv Success { result, warnings, events } =
     Success { result, warnings, events = map func events }
   mapEv (Failure err) = Failure err
-
-mapFailure
-  :: Monad m
-  => (er1 -> er2)
-  -> ResultT ev er1 con m value
-  -> ResultT ev er2 con m value
-mapFailure f (ResultT ma) = ResultT $ mapF <$> ma
- where
-  mapF (Failure x    ) = Failure (map f x)
-  mapF (Success x w e) = Success x (map f w) e
-
 
 -- Helper Functions
 type LibUpdater lib = lib -> Validation lib
diff --git a/src/Data/Morpheus/Types/Internal/Resolving/Resolver.hs b/src/Data/Morpheus/Types/Internal/Resolving/Resolver.hs
--- a/src/Data/Morpheus/Types/Internal/Resolving/Resolver.hs
+++ b/src/Data/Morpheus/Types/Internal/Resolving/Resolver.hs
@@ -1,32 +1,33 @@
-{-# LANGUAGE DataKinds             #-}
-{-# LANGUAGE FlexibleContexts      #-}
-{-# LANGUAGE FlexibleInstances     #-}
-{-# LANGUAGE GADTs                 #-}
-{-# LANGUAGE InstanceSigs          #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE NamedFieldPuns        #-}
-{-# LANGUAGE OverloadedStrings     #-}
-{-# LANGUAGE PolyKinds             #-}
-{-# LANGUAGE ScopedTypeVariables   #-}
-{-# LANGUAGE TupleSections         #-}
-{-# LANGUAGE TypeFamilies          #-}
-{-# LANGUAGE TypeOperators         #-}
-{-# LANGUAGE UndecidableInstances  #-}
-{-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE DataKinds                  #-}
+{-# LANGUAGE FlexibleContexts           #-}
+{-# LANGUAGE FlexibleInstances          #-}
+{-# LANGUAGE GADTs                      #-}
+{-# LANGUAGE InstanceSigs               #-}
+{-# LANGUAGE MultiParamTypeClasses      #-}
+{-# LANGUAGE NamedFieldPuns             #-}
+{-# LANGUAGE OverloadedStrings          #-}
+{-# LANGUAGE PolyKinds                  #-}
+{-# LANGUAGE ScopedTypeVariables        #-}
+{-# LANGUAGE TupleSections              #-}
+{-# LANGUAGE TypeFamilies               #-}
+{-# LANGUAGE TypeOperators              #-}
+{-# LANGUAGE UndecidableInstances       #-}
+{-# LANGUAGE ConstraintKinds            #-}
+{-# LANGUAGE StandaloneDeriving         #-}
+{-# LANGUAGE DeriveFunctor              #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
 
 module Data.Morpheus.Types.Internal.Resolving.Resolver
   ( Event(..)
   , GQLRootResolver(..)
   , UnSubResolver
-  , Resolver(..)
-  , ResolvingStrategy(..)
+  , Resolver
   , MapStrategy(..)
   , LiftOperation
   , resolveObject
-  , resolveEnum
-  , toResponseRes
-  , withObject
-  , resolving
+  , runDataResolver
+  , runResolver
+  , unsafeBind
   , toResolver
   , lift
   , SubEvent
@@ -37,23 +38,25 @@
   , DataResolver(..)
   , FieldRes
   , WithOperation
+  , subscribe
+  , Context(..)
+  , unsafeInternalContext
   )
 where
 
-import           Control.Monad.Trans.Class      ( MonadTrans(..) )
+import           Control.Monad.Fail             (MonadFail(..))
+import           Control.Monad.Trans.Class      ( MonadTrans(..))
+import           Control.Monad.IO.Class         ( MonadIO(..) )
 import           Data.Maybe                     ( fromMaybe )
 import           Data.Semigroup                 ( (<>)
                                                 , Semigroup(..)
                                                 )
-import           Data.Text                      ( unpack
-                                                , pack
-                                                )
+import           Control.Monad.Trans.Reader     (ReaderT(..), ask,mapReaderT, withReaderT)
+import           Data.Text                      (pack)
 
 -- MORPHEUS
 import           Data.Morpheus.Error.Internal   ( internalResolvingError )
-import           Data.Morpheus.Error.Selection  ( resolvingFailedError
-                                                , subfieldsNotSelected
-                                                )
+import           Data.Morpheus.Error.Selection  ( subfieldsNotSelected )
 import           Data.Morpheus.Types.Internal.AST.Selection
                                                 ( Selection(..)
                                                 , SelectionContent(..)
@@ -61,6 +64,8 @@
                                                 , ValidSelectionRec
                                                 , ValidSelectionSet
                                                 , ValidSelection
+                                                , ValidArguments
+                                                , ValidOperation
                                                 )
 import           Data.Morpheus.Types.Internal.AST.Base
                                                 ( Message
@@ -72,20 +77,22 @@
                                                 , OperationType
                                                 , QUERY
                                                 , SUBSCRIPTION
+                                                , Schema
                                                 )
 import           Data.Morpheus.Types.Internal.Resolving.Core
                                                 ( GQLErrors
-                                                , GQLError
+                                                , GQLError(..)
                                                 , Validation
                                                 , Result(..)
                                                 , Failure(..)
                                                 , ResultT(..)
-                                                , fromEither
-                                                , fromEitherSingle
                                                 , cleanEvents
-                                                , mapFailure
                                                 , mapEvent
-                                                , StatelessResT
+                                                , Event(..)
+                                                , Channel(..)
+                                                , StreamChannel
+                                                , GQLChannel(..)
+                                                , PushEvents(..)
                                                 )
 import           Data.Morpheus.Types.Internal.AST.Value
                                                 ( GQLValue(..)
@@ -94,13 +101,8 @@
 import           Data.Morpheus.Types.IO         ( renderResponse
                                                 , GQLResponse
                                                 )
--- MORPHEUS
 
-class LiftOperation (o::OperationType) res where
-  type ResError res :: *
-  liftOperation :: Monad m => m (Either (ResError res) a) -> res o event m  a
-
-type WithOperation (o :: OperationType) = LiftOperation o Resolver
+type WithOperation (o :: OperationType) = LiftOperation o
 
 type ResponseStream event m = ResultT (ResponseEvent m event) GQLError 'True m
 
@@ -110,329 +112,330 @@
 
 type SubEvent m event = Event (Channel event) (event -> m GQLResponse)
 
-----------------------------------------------------------------------------------------
--- Recursive Resolver
-newtype RecResolver m a b = RecResolver {
-  unRecResolver :: a -> StatelessResT m b
-}
+data Context = Context {
+  currentSelection :: (Name,ValidSelection),
+  schema :: Schema,
+  operation :: ValidOperation
+} deriving (Show)
 
-instance Functor m => Functor (RecResolver m a) where
-  fmap f (RecResolver x) = RecResolver recX where recX event = f <$> x event
+-- Resolver Internal State
+newtype ResolverState event m a = ResolverState {
+  runResolverState :: ReaderT Context (ResultT event GQLError 'True m) a
+} deriving (Functor, Applicative, Monad)
 
-instance Monad m => Applicative (RecResolver m a) where
-  pure = RecResolver . const . pure
-  (RecResolver f) <*> (RecResolver res) = RecResolver recX
-    where recX event = f event <*> res event
+instance Monad m => MonadFail (ResolverState event m) where 
+  fail = failure . pack
 
-instance Monad m => Monad (RecResolver m a) where
-  (RecResolver x) >>= next = RecResolver recX
-    where recX event = x event >>= (\v -> v event) . unRecResolver . next
-------------------------------------------------------------
+instance MonadTrans (ResolverState e) where
+  lift = ResolverState . lift . lift
 
---- GraphQLT
-data ResolvingStrategy  (o::OperationType) event (m:: * -> *) value where
-  ResolveQ ::{ unResolveQ :: ResultT () GQLError 'True m value } -> ResolvingStrategy QUERY event m  value
-  ResolveM ::{ unResolveM :: ResultT event GQLError 'True m value } -> ResolvingStrategy MUTATION event m  value
-  ResolveS ::{ unResolveS :: ResultT (Channel event) GQLError 'True m (RecResolver m event value) } -> ResolvingStrategy SUBSCRIPTION event m value
+instance (Monad m) => Failure Message (ResolverState e m) where
+  failure message = ResolverState $ do 
+    selection <- currentSelection <$> ask 
+    lift $ failure [resolverFailureMessage selection message]
 
--- Functor
-instance Monad m => Functor (ResolvingStrategy o e m) where
-  fmap f (ResolveQ res) = ResolveQ $ f <$> res
-  fmap f (ResolveM res) = ResolveM $ f <$> res
-  fmap f (ResolveS res) = ResolveS $ (<$>) f <$> res
+instance (Monad m) => Failure GQLErrors (ResolverState e m) where
+  failure = ResolverState . lift . failure 
 
--- Applicative
-instance (LiftOperation o ResolvingStrategy, Monad m) => Applicative (ResolvingStrategy o e m) where
-  pure = liftOperation . pure . pure
-  -------------------------------------
-  (ResolveQ f) <*> (ResolveQ res) = ResolveQ (f <*> res)
-  ------------------------------------------------------------------------
-  (ResolveM f) <*> (ResolveM res) = ResolveM (f <*> res)
-  --------------------------------------------------------------
-  (ResolveS f) <*> (ResolveS res) = ResolveS $ (<*>) <$> f <*> res
+instance (Monad m) => PushEvents e (ResolverState e m) where
+    pushEvents = ResolverState . lift . pushEvents 
 
--- LiftOperation
-instance LiftOperation QUERY ResolvingStrategy where
-  type ResError ResolvingStrategy = GQLErrors
-  liftOperation = ResolveQ . ResultT . fmap fromEither
 
-instance LiftOperation MUTATION ResolvingStrategy where
-  type ResError ResolvingStrategy = GQLErrors
-  liftOperation = ResolveM . ResultT . fmap fromEither
+mapResolverState :: 
+  ( ReaderT Context (ResultT e1 GQLError 'True m1) a1 
+    -> ReaderT Context (ResultT e2 GQLError 'True m2) a2 
+  ) -> ResolverState e1 m1 a1 
+    -> ResolverState e2 m2 a2
+mapResolverState f (ResolverState x) = ResolverState (f x)
 
-instance LiftOperation SUBSCRIPTION ResolvingStrategy where
-  type ResError ResolvingStrategy = GQLErrors
-  liftOperation = ResolveS . ResultT . fmap (fromEither . fmap pure)
 
- -- Failure
-instance (LiftOperation o ResolvingStrategy, Monad m) => Failure GQLErrors (ResolvingStrategy o e m) where
-  failure = liftOperation . pure . Left
-
--- DataResolver
-data DataResolver o e m =
-    EnumRes  Name
-  | UnionRes  (Name,[FieldRes o e m])
-  | ObjectRes  [FieldRes o e m ]
-  | UnionRef (FieldRes o e m)
-  | InvalidRes Name
-
-instance Semigroup (DataResolver o e m) where
-  ObjectRes x <> ObjectRes y = ObjectRes (x <> y)
-  _           <> _           = InvalidRes "can't merge: incompatible resolvers"
-
-withObject
-  :: (LiftOperation o ResolvingStrategy, Monad m)
-  => (ValidSelectionSet -> ResolvingStrategy o e m value)
-  -> (Key, ValidSelection)
-  -> ResolvingStrategy o e m value
-withObject f (_, Selection { selectionContent = SelectionSet selection }) =
-  f selection
-withObject _ (key, Selection { selectionPosition }) =
-  failure (subfieldsNotSelected key "" selectionPosition)
-
-resolveObject
-  :: (Monad m, LiftOperation o ResolvingStrategy)
-  => ValidSelectionSet
-  -> DataResolver o e m
-  -> ResolvingStrategy o e m ValidValue
-resolveObject selectionSet (ObjectRes resolvers) =
-  gqlObject <$> traverse selectResolver selectionSet
- where
-  selectResolver (key, selection@Selection { selectionAlias }) =
-    (fromMaybe key selectionAlias, ) <$> lookupRes selection
-   where
-    lookupRes sel =
-      (fromMaybe (const $ pure gqlNull) $ lookup key resolvers) (key, sel)
-resolveObject _ _ =
-  failure $ internalResolvingError "expected object as resolver"
-
-resolveEnum
-  :: (Monad m, LiftOperation o ResolvingStrategy)
-  => Name
-  -> Name
-  -> ValidSelectionRec
-  -> ResolvingStrategy o e m ValidValue
-resolveEnum _        enum SelectionField              = pure $ gqlString enum
-resolveEnum typeName enum (UnionSelection selections) = resolveObject
-  currentSelection
-  resolvers
- where
-  enumObjectTypeName = typeName <> "EnumObject"
-  currentSelection   = fromMaybe [] $ lookup enumObjectTypeName selections
-  resolvers          = ObjectRes
-    [ ("enum", const $ pure $ gqlString enum)
-    , resolve__typename enumObjectTypeName
-    ]
-resolveEnum _ _ _ =
-  failure $ internalResolvingError "wrong selection on enum value"
+getState :: (Monad m) => ResolverState e m (Name,ValidSelection)
+getState = ResolverState $ currentSelection <$> ask 
 
+setState :: (Name,ValidSelection) -> ResolverState e m a -> ResolverState e m a
+setState currentSelection = mapResolverState (withReaderT (\ctx -> ctx { currentSelection } ))
 
-resolve__typename
-  :: (Monad m, LiftOperation o ResolvingStrategy)
-  => Name
-  -> (Key, (Key, ValidSelection) -> ResolvingStrategy o e m ValidValue)
-resolve__typename name = ("__typename", const $ pure $ gqlString name)
+-- clear evets and starts new resolver with diferenct type of events but with same value
+-- use properly. only if you know what you are doing
+clearStateResolverEvents :: (Functor m) => ResolverState e1 m a -> ResolverState e2 m a
+clearStateResolverEvents = mapResolverState (mapReaderT cleanEvents)
 
-toResponseRes
-  :: Monad m
-  => ResolvingStrategy o event m ValidValue
-  -> ResponseStream event m ValidValue
-toResponseRes (ResolveQ resT) = cleanEvents resT
-toResponseRes (ResolveM resT) = mapEvent Publish resT
-toResponseRes (ResolveS resT) = ResultT $ handleActions <$> runResultT resT
- where
-  handleActions (Failure gqlError                ) = Failure gqlError
-  handleActions (Success subRes warnings channels) = Success
-    { result   = gqlNull
-    , warnings
-    , events   = [Subscribe $ Event channels eventResolver]
-    }
-   where
-    eventResolver event =
-      renderResponse <$> runResultT (unRecResolver subRes event)
+resolverFailureMessage :: (Name,ValidSelection) -> Message -> GQLError
+resolverFailureMessage (name, Selection { selectionPosition }) message = GQLError
+  { message   = "Failure on Resolving Field \"" <> name <> "\": " <> message
+  , locations = [selectionPosition]
+  }
 
---
 --     
 -- GraphQL Field Resolver
 --
---
---ResultT  GQLError 'True m (RecResolver m event value)
 ---------------------------------------------------------------
 data Resolver (o::OperationType) event (m :: * -> * )  value where
-    QueryResolver::{ unQueryResolver :: ResultT () String 'True m value } -> Resolver QUERY   event m value
-    MutResolver ::{ unMutResolver :: ResultT event String 'True m ([event],value) } -> Resolver MUTATION event m  value
-    SubResolver ::{
-            subChannels :: [StreamChannel event] ,
-            subResolver :: event -> Resolver QUERY event m value
-        } -> Resolver SUBSCRIPTION event m  value
+    ResolverQ :: { runResolverQ :: ResolverState () m value } -> Resolver QUERY event m value
+    ResolverM :: { runResolverM :: ResolverState event m value } -> Resolver MUTATION event m  value
+    ResolverS :: { runResolverS :: ResolverState (Channel event) m (ReaderT event (Resolver QUERY event m) value) } -> Resolver SUBSCRIPTION event m  value
 
--- Functor
-instance Functor m => Functor (Resolver o e m) where
-  fmap f (QueryResolver res) = QueryResolver $ fmap f res
-  fmap f (MutResolver   res) = MutResolver $ tupleMap <$> res
-    where tupleMap (e, v) = (e, f v)
-  fmap f (SubResolver events mResolver) = SubResolver events
-                                                      (eventFmap mResolver)
-    where eventFmap res event = fmap f (res event)
+deriving instance (Functor m) => Functor (Resolver o e m)
 
 -- Applicative
-instance (LiftOperation o Resolver ,Monad m) => Applicative (Resolver o e m) where
-  pure = liftOperation . pure . pure
-  -------------------------------------
-  (QueryResolver f) <*> (QueryResolver res) = QueryResolver (f <*> res)
-  ---------------------------------------------------------------------
-  MutResolver res1 <*> MutResolver res2 = MutResolver $ join <$> res1 <*> res2
-    where join (e1, f) (e2, v) = (e1 <> e2, f v)
-  --------------------------------------------------------------
-  (SubResolver e1 f) <*> (SubResolver e2 res) = SubResolver (e1 <> e2) subRes
-    where subRes event = f event <*> res event
+instance (LiftOperation o ,Monad m) => Applicative (Resolver o e m) where
+  pure = packResolver . pure
+  ResolverQ r1 <*> ResolverQ r2 = ResolverQ $ r1 <*> r2
+  ResolverM r1 <*> ResolverM r2 = ResolverM $ r1 <*> r2
+  ResolverS r1 <*> ResolverS r2 = ResolverS $ (<*>) <$> r1 <*> r2
 
 -- Monad 
 instance (Monad m) => Monad (Resolver QUERY e m) where
   return = pure
-  -----------------------------------------------------
-  (QueryResolver f) >>= nextM = QueryResolver (f >>= unQueryResolver . nextM)
+  (>>=) = unsafeBind
 
 instance (Monad m) => Monad (Resolver MUTATION e m) where
   return = pure
-  -----------------------------------------------------
-  (MutResolver m1) >>= mFunc = MutResolver $ do
-    (e1, v1) <- m1
-    (e2, v2) <- unMutResolver $ mFunc v1
-    pure (e1 <> e2, v2)
+  (>>=) = unsafeBind
 
+-- MonadIO
+instance (MonadIO m) => MonadIO (Resolver QUERY e m) where
+    liftIO = lift . liftIO
+    
+instance (MonadIO m) => MonadIO (Resolver MUTATION e m) where
+    liftIO = lift . liftIO
+
 -- Monad Transformers    
 instance MonadTrans (Resolver QUERY e) where
-  lift = liftOperation . fmap pure
+  lift = packResolver . lift
 
 instance MonadTrans (Resolver MUTATION e) where
-  lift = liftOperation . fmap pure
+  lift = packResolver . lift
 
--- LiftOperation
-instance LiftOperation QUERY Resolver where
-  type ResError Resolver = String
-  liftOperation = QueryResolver . ResultT . fmap fromEitherSingle
+-- Failure
+instance (LiftOperation o, Monad m) => Failure Message (Resolver o e m) where
+   failure = packResolver .failure
 
-instance LiftOperation MUTATION Resolver where
-  type ResError Resolver = String
-  liftOperation = MutResolver . ResultT . fmap (fromEitherSingle . fmap ([], ))
+instance (LiftOperation o, Monad m) => Failure GQLErrors (Resolver o e m) where
+  failure = packResolver . failure 
 
-instance LiftOperation SUBSCRIPTION Resolver where
-  type ResError Resolver = String
-  liftOperation = SubResolver [] . const . liftOperation
+-- PushEvents
+instance (Monad m) => PushEvents e (Resolver MUTATION e m)  where
+    pushEvents = packResolver . pushEvents 
 
--- Failure
-instance (LiftOperation o Resolver, Monad m) => Failure Message (Resolver o e m) where
-  failure = liftOperation . pure . Left . unpack
+class LiftOperation (o::OperationType) where
+  packResolver :: Monad m => ResolverState e m a -> Resolver o e m a
+  withResolver :: Monad m => ResolverState e m a -> (a -> Resolver o e m b) -> Resolver o e m b
 
--- Type Helpers  
-type family UnSubResolver (a :: * -> *) :: (* -> *)
+-- packResolver
+instance LiftOperation QUERY where
+  packResolver = ResolverQ . clearStateResolverEvents
+  withResolver ctxRes toRes = ResolverQ $ do 
+     v <- clearStateResolverEvents ctxRes 
+     runResolverQ $ toRes v
 
-type instance UnSubResolver (Resolver SUBSCRIPTION m e) = Resolver QUERY m e
+instance LiftOperation MUTATION where
+  packResolver = ResolverM
+  withResolver ctxRes toRes = ResolverM $ ctxRes >>= runResolverM . toRes 
 
+instance LiftOperation SUBSCRIPTION where
+  packResolver = ResolverS . pure . lift . packResolver
+  withResolver ctxRes toRes = ResolverS $ do 
+    value <- clearStateResolverEvents ctxRes
+    runResolverS $ toRes value
 
--- RESOLVING
-type FieldRes o e m
-  = (Key, (Key, ValidSelection) -> ResolvingStrategy o e m ValidValue)
+setSelection :: Monad m => (Name, ValidSelection) -> Resolver o e m a -> Resolver o e m a 
+setSelection sel (ResolverQ res)  = ResolverQ (setState sel res)
+setSelection sel (ResolverM res)  = ResolverM (setState sel res) 
+setSelection sel (ResolverS resM)  = ResolverS $ do
+    res <- resM
+    pure $ ReaderT $ \e -> ResolverQ $ setState sel (runResolverQ (runReaderT res e)) 
 
-toResolver
-  :: (LiftOperation o Resolver, Monad m)
-  => Validation a
+-- unsafe variant of >>= , not for public api. user can be confused: 
+--  ignores `channels` on second Subsciption, only returns events from first Subscription monad.
+--    reason: second monad is waiting for `event` until he does not have some event can't tell which 
+--            channel does it want to listen
+unsafeBind
+  :: forall o e m a b
+   . Monad m
+  =>  Resolver o e m a
   -> (a -> Resolver o e m b)
-  -> Resolver o e m b
-toResolver Success { result } f = f result
-toResolver (Failure errors) _ =
-  failure ("TODO: errors" <> pack (show errors) :: Message)
+  -> Resolver o e m b 
+unsafeBind (ResolverQ x) m2 = ResolverQ (x >>= runResolverQ . m2)
+unsafeBind (ResolverM x) m2 = ResolverM (x >>= runResolverM . m2)
+unsafeBind (ResolverS res) m2 = ResolverS $ do 
+    (readResA :: ReaderT e (Resolver QUERY e m) a ) <- res 
+    pure $ ReaderT $ \e -> ResolverQ $ do 
+         let (resA :: Resolver QUERY e m a) = (runReaderT $ readResA) e
+         (valA :: a) <- runResolverQ resA
+         (readResB :: ReaderT e (Resolver QUERY e m) b) <- clearStateResolverEvents $ runResolverS (m2 valA) 
+         runResolverQ $ runReaderT readResB e
 
-resolving
-  :: forall o e m value
-   . Monad m
-  => (value -> (Key, ValidSelection) -> ResolvingStrategy o e m ValidValue)
-  -> Resolver o e m value
-  -> (Key, ValidSelection)
-  -> ResolvingStrategy o e m ValidValue
-resolving encode gResolver selection@(fieldName, Selection { selectionPosition })
-  = _resolve gResolver
- where
-  convert :: Monad m => ResultT ev String con m a -> ResultT ev GQLError con m a
-  convert =
-    mapFailure (resolvingFailedError selectionPosition fieldName . pack)
-  ------------------------------
-  _encode = (`encode` selection)
-  -------------------------------------------------------------------
-  _resolve (QueryResolver res) =
-    ResolveQ $ convert res >>= unResolveQ . _encode
-  ---------------------------------------------------------------------------------------------------------------------------------------
-  _resolve (MutResolver res) =
-    ResolveM $ replace (convert res) >>= unResolveM . _encode
-   where
-    replace (ResultT mx) = ResultT $ do
-      value <- mx
-      pure $ case value of
-        Success { warnings, events, result = (events2, result) } ->
-          Success { result, warnings, events = events <> events2 }
-        Failure x -> Failure x
-  --------------------------------------------------------------------------------------------------------------------------------
-  _resolve (SubResolver subChannels res) = ResolveS $ ResultT $ pure $ Success
-    { events   = map Channel subChannels
-    , result   = RecResolver eventResolver
-    , warnings = []
-    }
-   where
-    eventResolver :: e -> StatelessResT m ValidValue
-    eventResolver event =
-      convert (unQueryResolver $ res event) >>= unPureSub . _encode
-     where
-      unPureSub
-        :: Monad m
-        => ResolvingStrategy SUBSCRIPTION e m ValidValue
-        -> StatelessResT m ValidValue
-      unPureSub (ResolveS x) = cleanEvents x >>= passEvent
-        where passEvent (RecResolver f) = f event
+subscribe :: forall e m a . (PushEvents (Channel e) (ResolverState (Channel e) m), Monad m) => [StreamChannel e] -> Resolver QUERY e m (e -> Resolver QUERY e m a) -> Resolver SUBSCRIPTION e m a
+subscribe ch res = ResolverS $ do 
+  pushEvents (map Channel ch :: [Channel e])
+  (eventRes :: e -> Resolver QUERY e m a) <- clearStateResolverEvents (runResolverQ res)
+  pure $ ReaderT eventRes
 
+unsafeInternalContext :: (Monad m, LiftOperation o) => Resolver o e m Context
+unsafeInternalContext = packResolver $ ResolverState ask 
+
+-- Converts Subscription Resolver Type to Query Resolver
+type family UnSubResolver (a :: * -> * ) :: (* -> *)
+type instance UnSubResolver (Resolver SUBSCRIPTION e m) = Resolver QUERY e m
+
 -- map Resolving strategies 
 class MapStrategy (from :: OperationType) (to :: OperationType) where
-   mapStrategy :: Monad m => ResolvingStrategy from e m a -> ResolvingStrategy to e m a
+   mapStrategy :: Monad m => Resolver from e m a -> Resolver to e m a
 
 instance MapStrategy o o where
   mapStrategy = id
 
 instance MapStrategy QUERY SUBSCRIPTION where
-  mapStrategy (ResolveQ x) = ResolveS $ pure <$> cleanEvents x
+  mapStrategy  = ResolverS . pure . lift
 
--------------------------------------------------------------------
--- | GraphQL Root resolver, also the interpreter generates a GQL schema from it.
---  'queryResolver' is required, 'mutationResolver' and 'subscriptionResolver' are optional,
---  if your schema does not supports __mutation__ or __subscription__ , you can use __()__ for it.
-data GQLRootResolver (m :: * -> *) event (query :: (* -> *) -> * ) (mut :: (* -> *) -> * )  (sub :: (* -> *) -> * )  = GQLRootResolver
-  { queryResolver        :: query (Resolver QUERY event m)
-  , mutationResolver     :: mut (Resolver MUTATION event m)
-  , subscriptionResolver :: sub (Resolver SUBSCRIPTION  event m)
-  }
+--
+-- Selection Processing
+--
+type FieldRes o e m
+  = (Key, Resolver o e m ValidValue)
 
- -- EVENTS
+toResolver
+  :: forall o e m a b. (LiftOperation o, Monad m)
+  => (ValidArguments -> Validation a)
+  -> (a -> Resolver o e m b)
+  -> Resolver o e m b
+toResolver toArgs  = withResolver args 
+ where 
+  args :: ResolverState e m a
+  args = do
+    (_,Selection { selectionArguments }) <- getState
+    let resT = ResultT $ pure $ toArgs selectionArguments
+    ResolverState $ lift $ cleanEvents resT
 
+-- DataResolver
+data DataResolver o e m =
+    EnumRes  Name
+  | UnionRes  (Name,[FieldRes o e m])
+  | ObjectRes  [FieldRes o e m ]
+  | UnionRef (FieldRes o e m)
+  | InvalidRes Name
 
--- Channel
+instance Semigroup (DataResolver o e m) where
+  ObjectRes x <> ObjectRes y = ObjectRes (x <> y)
+  _           <> _           = InvalidRes "can't merge: incompatible resolvers"
 
-newtype Channel event = Channel {
-  _unChannel :: StreamChannel event
-}
+pickSelection :: Name -> [(Name, ValidSelectionSet)] -> ValidSelectionSet
+pickSelection name = fromMaybe [] . lookup name
 
-instance (Eq (StreamChannel event)) => Eq (Channel event) where
-  Channel x == Channel y = x == y
+resolve__typename
+  :: (Monad m, LiftOperation o)
+  => Name
+  -> (Key, Resolver o e m ValidValue)
+resolve__typename name = ("__typename", pure $ gqlString name)
 
-class GQLChannel a where
-  type StreamChannel a :: *
-  streamChannels :: a -> [Channel a]
+resolveEnum
+  :: (Monad m, LiftOperation o)
+  => Name
+  -> Name
+  -> ValidSelectionRec
+  -> Resolver o e m ValidValue
+resolveEnum _        enum SelectionField              = pure $ gqlString enum
+resolveEnum typeName enum (UnionSelection selections) = resolveObject
+  currentSelection
+  resolvers
+ where
+  enumObjectTypeName = typeName <> "EnumObject"
+  currentSelection   = fromMaybe [] $ lookup enumObjectTypeName selections
+  resolvers          = ObjectRes
+    [ ("enum", pure $ gqlString enum)
+    , resolve__typename enumObjectTypeName
+    ]
+resolveEnum _ _ _ =
+  failure $ internalResolvingError "wrong selection on enum value"
 
-instance GQLChannel () where
-  type StreamChannel () = ()
-  streamChannels _ = []
+withObject
+  :: (LiftOperation o, Monad m)
+  => (ValidSelectionSet -> Resolver o e m value)
+  -> (Key, ValidSelection)
+  -> Resolver o e m value
+withObject f (key, Selection { selectionContent , selectionPosition }) = checkContent selectionContent
+ where
+  checkContent (SelectionSet selection) = f selection
+  checkContent _ = failure (subfieldsNotSelected key "" selectionPosition)
 
-instance GQLChannel (Event channel content)  where
-  type StreamChannel (Event channel content) = channel
-  streamChannels Event { channels } = map Channel channels
+lookupRes :: (LiftOperation o, Monad m) => Name -> [(Name,Resolver o e m ValidValue)] -> Resolver o e m ValidValue
+lookupRes key = fromMaybe (pure gqlNull) . lookup key 
 
-data Event e c = Event
-  { channels :: [e], content  :: c}
+outputSelectionName :: (Name,ValidSelection) -> Name
+outputSelectionName (name,Selection { selectionAlias }) = fromMaybe name selectionAlias
+
+resolveObject
+  :: forall o e m. (LiftOperation o , Monad m)
+  => ValidSelectionSet
+  -> DataResolver o e m
+  -> Resolver o e m ValidValue
+resolveObject selectionSet (ObjectRes resolvers) =
+  gqlObject <$> traverse resolver selectionSet
+ where
+  resolver :: (Name,ValidSelection) -> Resolver o e m (Name,ValidValue)
+  resolver sel@(name,_) = setSelection sel $ (outputSelectionName sel, ) <$> lookupRes name resolvers
+resolveObject _ _ =
+  failure $ internalResolvingError "expected object as resolver"
+
+toEventResolver :: Monad m => (ReaderT event (Resolver QUERY event m) ValidValue) -> Context -> event -> m GQLResponse
+toEventResolver (ReaderT subRes) sel event = do 
+  value <- runResultT $ runReaderT (runResolverState $ runResolverQ (subRes event)) sel
+  pure $ renderResponse value
+
+runDataResolver :: (Monad m, LiftOperation o) => Name -> DataResolver o e m -> Resolver o e m ValidValue
+runDataResolver typename  = withResolver getState . __encode
+   where
+    __encode obj (key, sel@Selection { selectionContent })  = encodeNode obj selectionContent 
+      where 
+      -- Object -----------------
+      encodeNode (ObjectRes fields) _ = withObject encodeObject (key, sel)
+        where
+        encodeObject selection =
+          resolveObject selection
+            $ ObjectRes
+            $ resolve__typename typename
+            : fields
+      encodeNode (EnumRes enum) _ =
+        resolveEnum typename enum selectionContent
+      -- Type Reference --------
+      encodeNode (UnionRef (fieldTypeName, fieldResolver)) (UnionSelection selections)
+        = setSelection (key, sel { selectionContent = SelectionSet currentSelection }) fieldResolver
+          where currentSelection = pickSelection fieldTypeName selections
+      -- Union Record ----------------
+      encodeNode (UnionRes (name, fields)) (UnionSelection selections) =
+        resolveObject selection resolver
+        where
+          selection = pickSelection name selections
+          resolver = ObjectRes (resolve__typename name : fields)
+      encodeNode _ _ = failure $ internalResolvingError
+        "union Resolver should only recieve UnionSelection"
+
+runResolver
+  :: Monad m
+  => Resolver o event m ValidValue
+  -> Context
+  -> ResponseStream event m ValidValue
+runResolver (ResolverQ resT) sel = cleanEvents $ (runReaderT $ runResolverState resT) sel
+runResolver (ResolverM resT) sel = mapEvent Publish $ (runReaderT $ runResolverState $ resT) sel 
+runResolver (ResolverS resT) sel = ResultT $ do 
+    (readResValue :: Result (Channel event1) GQLError 'True (ReaderT event (Resolver QUERY event m) ValidValue))  <- runResultT $ (runReaderT $ runResolverState $ resT) sel
+    pure $ case readResValue of 
+      Failure x -> Failure x
+      Success { warnings ,result , events = channels } -> do
+        let eventRes = toEventResolver result sel
+        Success {
+          events = [Subscribe $ Event channels eventRes],
+          warnings,
+          result = gqlNull
+        } 
+
+-------------------------------------------------------------------
+-- | GraphQL Root resolver, also the interpreter generates a GQL schema from it.
+--  'queryResolver' is required, 'mutationResolver' and 'subscriptionResolver' are optional,
+--  if your schema does not supports __mutation__ or __subscription__ , you can use __()__ for it.
+data GQLRootResolver (m :: * -> *) event (query :: (* -> *) -> * ) (mut :: (* -> *) -> * )  (sub :: (* -> *) -> * )  = GQLRootResolver
+  { queryResolver        :: query (Resolver QUERY event m)
+  , mutationResolver     :: mut (Resolver MUTATION event m)
+  , subscriptionResolver :: sub (Resolver SUBSCRIPTION  event m)
+  }
diff --git a/src/Data/Morpheus/Types/Internal/WebSocket.hs b/src/Data/Morpheus/Types/Internal/WebSocket.hs
--- a/src/Data/Morpheus/Types/Internal/WebSocket.hs
+++ b/src/Data/Morpheus/Types/Internal/WebSocket.hs
@@ -3,7 +3,9 @@
 module Data.Morpheus.Types.Internal.WebSocket
   ( GQLClient(..)
   , ClientID
-  , ClientSession(..)
+  , ClientDB
+  , GQLState
+  , SesionID
   )
 where
 
@@ -11,28 +13,29 @@
 import           Data.Text                      ( Text )
 import           Data.UUID                      ( UUID )
 import           Network.WebSockets             ( Connection )
+import           Data.HashMap.Lazy              ( HashMap , keys)
+import           Control.Concurrent             ( MVar )
 
 -- MORPHEUS
 import           Data.Morpheus.Types.Internal.Resolving
                                                 ( SubEvent )
 
-type ClientID = UUID
 
-data ClientSession m e =
-  ClientSession
-    { sessionId           :: Text
-    , sessionSubscription :: SubEvent m e
-    }
+-- | shared GraphQL state between __websocket__ and __http__ server,
+-- stores information about subscriptions
+type GQLState m e = MVar (ClientDB m e) -- SharedState
 
-instance (Show e) => Show (ClientSession m e ) where
-  show ClientSession { sessionId } =
-    "GQLSession { id: " <> show sessionId <> ", sessions: " <> "" <> " }"
+type ClientDB m e = HashMap ClientID (GQLClient m e)
 
+type ClientID = UUID
+
+type SesionID = Text
+
 data GQLClient m e  =
   GQLClient
     { clientID         :: ClientID
     , clientConnection :: Connection
-    , clientSessions   :: [ClientSession m e ]
+    , clientSessions   :: HashMap SesionID (SubEvent m e)
     }
 
 instance (Show e) => Show (GQLClient m e) where
@@ -40,5 +43,5 @@
     "GQLClient {id:"
       <> show clientID
       <> ", sessions:"
-      <> show clientSessions
+      <> show (keys clientSessions)
       <> "}"
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
@@ -26,9 +26,9 @@
                                                 , GQLType(..)
                                                 , ID(..)
                                                 , ScalarValue(..)
-                                                , Resolver(..)
                                                 , failRes
                                                 , liftEither
+                                                , subscribe
                                                 )
 import           Data.Text                      ( Text )
 import           GHC.Generics                   ( Generic )
@@ -68,13 +68,7 @@
                                  , fail2 =  failRes "fail with failRes"
                                  }
   , mutationResolver     = Mutation { createUser = const user }
-  , subscriptionResolver = Subscription
-
-                             { newUser = SubResolver
-                                           { subChannels = [Channel]
-                                           , subResolver = const user
-                                           }
-                             }
+  , subscriptionResolver = Subscription { newUser = subscribe [Channel] (pure $ const user)}
   }
  where
   user :: Applicative m => m (User m)
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
@@ -10,7 +10,7 @@
 
 import           Data.Morpheus       (interpreter)
 import           Data.Morpheus.Types (Event, GQLRequest, GQLResponse, GQLRootResolver (..), GQLType (..), IORes,
-                                      Resolver (..), constRes)
+                                      constRes, subscribe)
 import           Data.Text           (Text)
 import           GHC.Generics        (Generic)
 
@@ -43,9 +43,9 @@
 type EVENT =  Event Channel ()
 
 data Subscription (m :: * -> *) = Subscription
-  { sub1 :: () -> m (Maybe (WA (IORes EVENT)))
-  , sub2 :: () -> m (Maybe (Wrapped Int Int))
-  , sub3 :: () -> m (Maybe (Wrapped (Wrapped Text Int) Text))
+  { sub1 :: m (Maybe (WA (IORes EVENT)))
+  , sub2 :: m (Maybe (Wrapped Int Int))
+  , sub3 :: m (Maybe (Wrapped (Wrapped Text Int) Text))
   } deriving (Generic, GQLType)
 
 rootResolver :: GQLRootResolver IO EVENT Query Mutation Subscription
@@ -54,9 +54,9 @@
     { queryResolver = Query {a1 = WA {aText = const $ pure "test1", aInt = 0}, a2 = Nothing, a3 = Nothing}
     , mutationResolver = Mutation {mut1 = Nothing, mut2 = Nothing, mut3 = Nothing}
     , subscriptionResolver = Subscription
-            { sub1 = const SubResolver {subChannels = [Channel], subResolver = constRes Nothing}
-            , sub2 = const SubResolver {subChannels = [Channel], subResolver = constRes  Nothing}
-            , sub3 = const SubResolver {subChannels = [Channel], subResolver = constRes Nothing}
+            { sub1 = subscribe [Channel] (pure $ constRes Nothing)
+            , sub2 = subscribe [Channel] (pure $ constRes Nothing)
+            , sub3 = subscribe [Channel] (pure $ constRes Nothing)
             }
     }
 
