diff --git a/Erb/Compute.hs b/Erb/Compute.hs
--- a/Erb/Compute.hs
+++ b/Erb/Compute.hs
@@ -18,7 +18,7 @@
 type TemplateAnswer = Either String String
 
 initTemplateDaemon :: Prefs -> IO (String -> String -> [(String, GeneralValue)] -> IO (Either String String))
-initTemplateDaemon (Prefs _ modpath templatepath _ _) = do
+initTemplateDaemon (Prefs _ modpath templatepath _ _ _) = do
     controlchan <- newChan
     forkIO (templateDaemon modpath templatepath controlchan)
     return (templateQuery controlchan)
@@ -77,4 +77,5 @@
 toRuby' (ResolvedBool False) = "false"
 toRuby' (ResolvedArray rr) = "[" ++ intercalate ", " (map toRuby' rr) ++ "]"
 toRuby' (ResolvedHash hh) = "{ " ++ intercalate ", " (map (\(varname, varval) -> show varname ++ " => " ++ toRuby' varval) hh) ++ " }"
+toRuby' ResolvedUndefined = ":undef"
 toRuby' x = show x
diff --git a/Puppet/Daemon.hs b/Puppet/Daemon.hs
--- a/Puppet/Daemon.hs
+++ b/Puppet/Daemon.hs
@@ -19,6 +19,7 @@
 import qualified Data.List.Utils as DLU
 import qualified Data.Map as Map
 import Text.Parsec.Pos (initialPos)
+import PuppetDB.Rest
 
 -- this daemon returns a catalog when asked for a node and facts
 data DaemonMessage
@@ -50,6 +51,12 @@
 It is recommended to ask for as many parser and interpreter threads as there are
 CPUs.
 
+It can optionnaly talk with PuppetDB, by setting an URL in the 'Prefs' data
+structure. The recommended way to set it to http://localhost:8080 and set a SSH
+tunnel :
+
+> ssh -L 8080:localhost:8080 puppet.host
+
 Known bugs :
 
 * It might be buggy when top level statements that are not class/define/nodes
@@ -86,7 +93,10 @@
     case message of
         QCatalog (nodename, facts, respchan) -> do
             logDebug ("Received query for node " ++ nodename)
-            (stmts, warnings) <- getCatalog getstmts gettemplate nodename facts
+            let pdbfunc = case (puppetDBurl prefs) of
+                              Just x  -> Just (pdbResRequest x)
+                              Nothing -> Nothing
+            (stmts, warnings) <- getCatalog getstmts gettemplate pdbfunc nodename facts
             mapM_ logWarning warnings
             case stmts of
                 Left x -> writeChan respchan (RCatalog $ Left x)
diff --git a/Puppet/Init.hs b/Puppet/Init.hs
--- a/Puppet/Init.hs
+++ b/Puppet/Init.hs
@@ -9,14 +9,15 @@
     modules :: FilePath, -- ^ The path to the modules.
     templates :: FilePath, -- ^ The path to the template.
     compilepoolsize :: Int, -- ^ Size of the compiler pool.
-    parsepoolsize :: Int -- ^ Size of the parser pool.
+    parsepoolsize :: Int, -- ^ Size of the parser pool.
+    puppetDBurl :: Maybe String -- ^ Url of the PuppetDB connector (must be cleartext).
 } deriving (Show)
 
 -- | Generates the 'Prefs' structure from a single path.
 --
 -- > genPrefs "/etc/puppet"
 genPrefs :: String -> Prefs
-genPrefs basedir = Prefs (basedir ++ "/manifests") (basedir ++ "/modules") (basedir ++ "/templates") 1 1
+genPrefs basedir = Prefs (basedir ++ "/manifests") (basedir ++ "/modules") (basedir ++ "/templates") 1 1 Nothing
 
 -- | Generates 'Facts' from pairs of strings.
 --
diff --git a/Puppet/Interpreter/Catalog.hs b/Puppet/Interpreter/Catalog.hs
--- a/Puppet/Interpreter/Catalog.hs
+++ b/Puppet/Interpreter/Catalog.hs
@@ -38,11 +38,12 @@
 import Puppet.Interpreter.Functions
 import Puppet.Interpreter.Types
 import Puppet.Printers
+import qualified PuppetDB.Query as PDB
 
 import System.IO.Unsafe
 import Data.List
 import Data.Char (isDigit,toLower,toUpper, isAlpha, isAlphaNum, isSpace)
-import Data.Maybe (isJust, fromJust, catMaybes)
+import Data.Maybe (isJust, fromJust, catMaybes, isNothing)
 import Data.Either (lefts, rights, partitionEithers)
 import Data.Ord (comparing)
 import Text.Parsec.Pos
@@ -78,14 +79,33 @@
     -> (String -> String -> [(String, GeneralValue)] -> IO (Either String String))
     -- ^ The \"get template\" function. Given a file name, a scope name and a
     -- list of variables, it should return the computed template.
+    -> Maybe (String -> PDB.Query -> IO (Either String [CResource]))
+    -- ^ The \"puppetDB Rest API\" function. Given the machine fqdn, a request
+    -- type (resources, nodes, facts, ..) and a query, it returns a
+    -- ResolvedValue, or some error.
     -> String -- ^ Name of the node.
     -> Facts -- ^ Facts of this node.
     -> IO (Either String FinalCatalog, [String])
-getCatalog getstatements gettemplate nodename facts = do
+getCatalog getstatements gettemplate puppetdb nodename facts = do
     let convertedfacts = Map.map
             (\fval -> (Right fval, initialPos "FACTS"))
             facts
-    (output, finalstate) <- runStateT ( runErrorT ( computeCatalog getstatements nodename ) ) (ScopeState [["::"]] convertedfacts Map.empty [] 1 (initialPos "dummy") Map.empty getstatements [] [] [] gettemplate)
+    (output, finalstate) <- runStateT ( runErrorT ( computeCatalog getstatements nodename ) )
+                                (ScopeState
+                                   { curScope                   = [["::"]]
+                                   , curVariables               = convertedfacts
+                                   , curClasses                 = Map.empty
+                                   , curDefaults                = []
+                                   , curResId                   = 1
+                                   , curPos                     = (initialPos "dummy")
+                                   , nestedtoplevels            = Map.empty
+                                   , getStatementsFunction      = getstatements
+                                   , getWarnings                = []
+                                   , curCollect                 = []
+                                   , unresolvedRels             = []
+                                   , computeTemplateFunction    = gettemplate
+                                   , puppetDBFunction           = puppetdb
+                                   } )
     case output of
         Left x -> return (Left x, getWarnings finalstate)
         Right _ -> return (output, getWarnings finalstate)
@@ -130,7 +150,7 @@
         else do
             -- Note that amending attributes with a collector does collect virtual
             -- values. Hence no filtering on the collectors is done here.
-            isCollected <- liftM curCollect get >>= mapM (\(x, _) -> x res)
+            isCollected <- liftM curCollect get >>= mapM (\(x, _, _) -> x res)
             case (or isCollected, crvirtuality res) of
                 (True, Exported)    -> return [res { crvirtuality = Normal }, res]
                 (True,  _)          -> return [res { crvirtuality = Normal }     ]
@@ -138,9 +158,9 @@
 
 processOverride :: CResource -> Map.Map String ResolvedValue -> CatalogMonad (Map.Map String ResolvedValue)
 processOverride cr prms =
-    let applyOverride :: CResource -> Map.Map String ResolvedValue -> (CResource -> CatalogMonad Bool, [(GeneralString, GeneralValue)]) -> CatalogMonad (Map.Map String ResolvedValue)
+    let applyOverride :: CResource -> Map.Map String ResolvedValue -> (CResource -> CatalogMonad Bool, [(GeneralString, GeneralValue)], Maybe PDB.Query) -> CatalogMonad (Map.Map String ResolvedValue)
         -- this checks if the collection function matches
-        applyOverride c prm (func, overs) = do
+        applyOverride c prm (func, overs, _) = do
             check <- func c
             if check
                 then foldM tryReplace prm overs
@@ -153,13 +173,37 @@
             rv <- resolveGeneralValue gv
             return $ Map.insert rs rv curmap
     -- Collectors are filtered so that only those with overrides are passed to the fold.
-    in liftM (filter (not . null . snd) . curCollect) get >>= foldM (applyOverride cr) prms
+    in liftM (filter (\(_, x, _) -> not $ null x) . curCollect) get >>= foldM (applyOverride cr) prms
 
+retrieveRemoteResources :: (PDB.Query -> IO (Either String [CResource])) -> PDB.Query -> CatalogMonad [CResource]
+retrieveRemoteResources f q = do
+    res <- liftIO $ f q
+    hashes <- case res of
+        Right h     -> return h
+        Left err    -> throwError $ "PuppetDB error: " ++ err
+    return hashes
 
+extractRelations :: CResource -> CatalogMonad CResource
+extractRelations cr = do
+    let (params, rels) = partitionParamsRelations (crparams cr)
+    -- TODO export relations
+    return cr { crparams = params }
+
 finalResolution :: Catalog -> CatalogMonad FinalCatalog
 finalResolution cat = do
-    --liftIO $ putStrLn $ "FINAL RESOLUTION"
-    collected <- mapM collectionChecks cat >>= mapM evaluateDefine . concat
+    pdbfunction <- fmap puppetDBFunction get
+    fqdnr       <- getVariable "::fqdn"
+    collectedRemote <- case pdbfunction of
+                           Just f -> do
+                               fqdn <- case fqdnr of
+                                   Just (Right (ResolvedString f), _) -> return f
+                                   _ -> throwError "Could not get FQDN during final resolution"
+                               remoteCollects <- fmap (catMaybes . map (\(_,_,x) -> x) . curCollect) get
+                               fmap concat (mapM (retrieveRemoteResources (f fqdn)) remoteCollects)
+                           Nothing -> return []
+    collectedRemote' <- mapM extractRelations collectedRemote
+    collectedLocal <- fmap concat (mapM collectionChecks cat)
+    collected <- mapM evaluateDefine (collectedLocal ++ collectedRemote')
     let (real,  allvirtual)  = partition (\x -> crvirtuality x == Normal)  (concat collected)
         (_,  exported) = partition (\x -> crvirtuality x == Virtual)  allvirtual
     --export stuff
@@ -231,7 +275,7 @@
         nstate = curstate { nestedtoplevels = ntop }
     put nstate
 addWarning = modify . pushWarning
-addCollect = modify . pushCollect
+addCollect ((func, query), overrides) = modify $ pushCollect (func, overrides, query)
 -- this pushes the relations only if they exist
 -- the parameter is of the form
 -- ( [dstrelations], srcresource, type, pos )
@@ -326,16 +370,23 @@
 evaluateDefine r@(CResource _ rname rtype rparams rvirtuality rpos) = let
     evaluateDefineDeclaration dtype args dstmts dpos = do
         --oldpos <- getPos
-        setPos dpos
         pushScope ["#DEFINE#" ++ dtype]
         -- add variables
         mrrparams <- mapM (\(gs, gv) -> do { rgs <- resolveGeneralString gs; rgv <- tryResolveGeneralValue gv; return (rgs, (rgv, dpos)); }) rparams
         let expr = gs2gv rname
             mparams = Map.fromList mrrparams
+            defineparamset = Set.fromList $ map fst args
+            mandatoryparams = Set.fromList $ map fst $ filter (isNothing . snd) args
+            resourceparamset = Set.fromList $ map fst mrrparams
+            extraparams = Set.difference resourceparamset (Set.union defineparamset metaparameters)
+            unsetparams = Set.difference mandatoryparams resourceparamset
+        unless (Set.null extraparams) $ throwPosError $ "Spurious parameters set for " ++ dtype ++ ": " ++ intercalate ", " (Set.toList extraparams)
+        unless (Set.null unsetparams) $ throwPosError $ "Unset parameters set for " ++ dtype ++ ": " ++ intercalate ", " (Set.toList unsetparams)
         putVariable "title" (expr, rpos)
         putVariable "name" (expr, rpos)
         mapM_ (loadClassVariable rpos mparams) args
 
+        setPos dpos
         -- parse statements
         res <- mapM evaluateStatements dstmts
         nres <- handleDelayedActions (concat res)
@@ -903,7 +954,7 @@
         myfunction (CResource _ mcrname mcrtype _ _ _) = do
             srname <- resolveGeneralString mcrname
             return ((srname == rname) && (mcrtype == rtype))
-    addCollect (myfunction, [])
+    addCollect ((myfunction, Just $ PDB.queryRealize rtype rname) , [])
     return ()
 pushRealize (ResolvedRReference _ x) = throwPosError (show x ++ " was not resolved to a string")
 pushRealize x                        = throwPosError ("A reference was expected instead of " ++ show x)
@@ -1022,10 +1073,10 @@
 gs2gv (Left e)  = Left e
 gs2gv (Right s) = Right $ ResolvedString s
 
-collectionFunction :: Virtuality -> String -> Expression -> CatalogMonad (CResource -> CatalogMonad Bool)
+collectionFunction :: Virtuality -> String -> Expression -> CatalogMonad (CResource -> CatalogMonad Bool, Maybe PDB.Query)
 collectionFunction virt mrtype exprs = do
-    finalfunc <- case exprs of
-        BTrue -> return (\_ -> return True)
+    (finalfunc, pdbquery) <- case exprs of
+        BTrue -> return (\_ -> return True, Just (PDB.collectAll mrtype))
         EqualOperation a b -> do
             ra <- resolveExpression a
             rb <- resolveExpression b
@@ -1052,6 +1103,10 @@
                                 let filtered = filter (compareRValues rb) xs
                                 in  return $ not $ null filtered
                             _ -> return $ compareRValues cmp rb
+                , case (paramname, rb) of
+                      ("tag", ResolvedString tagval) -> Just (PDB.collectTag mrtype tagval)
+                      (param, ResolvedString prmval) -> Just (PDB.collectParam mrtype param prmval)
+                      _                              -> Nothing
                 )
         x -> throwPosError $ "TODO : implement collection function for " ++ show x
     return (\res -> do
@@ -1059,7 +1114,10 @@
         if (crtype res == mrtype) && ( ((virt == Virtual) &&  (crvirtuality res == Normal)) || (crvirtuality res == virt))
             then finalfunc res
             else return False
-            )
+        , if (virt == Exported)
+              then pdbquery
+              else Nothing
+        )
 
 
 generalValue2Expression :: GeneralValue -> Expression
diff --git a/Puppet/Interpreter/Types.hs b/Puppet/Interpreter/Types.hs
--- a/Puppet/Interpreter/Types.hs
+++ b/Puppet/Interpreter/Types.hs
@@ -1,6 +1,7 @@
 module Puppet.Interpreter.Types where
 
 import Puppet.DSL.Types
+import qualified PuppetDB.Query as PDB
 import Text.Parsec.Pos
 import Control.Monad.State
 import Control.Monad.Error
@@ -118,17 +119,20 @@
     -- ^ This is a function that, given the type of a top level statement and
     -- its name, should return it.
     getWarnings :: ![String], -- ^ List of warnings.
-    curCollect :: ![(CResource -> CatalogMonad Bool, [(GeneralString, GeneralValue)])],
+    curCollect :: ![(CResource -> CatalogMonad Bool, [(GeneralString, GeneralValue)], Maybe PDB.Query)],
     -- ^ A bit complicated, this stores the collection functions. These are
     -- functions that determine whether a resource should be collected or not.
     -- It can optionally store overrides, which will be applied in the end on
-    -- all resources.
+    -- all resources. It can also store a PuppetDB query.
     unresolvedRels :: ![([(LinkType, GeneralValue, GeneralValue)], (String, GeneralString), RelUpdateType, SourcePos)],
     -- ^ This stores unresolved relationships, because the original string name
     -- can't be resolved. Fieds are [ ( [dstrelations], srcresource, type, pos ) ]
-    computeTemplateFunction :: String -> String -> [(String, GeneralValue)] -> IO (Either String String)
+    computeTemplateFunction :: String -> String -> [(String, GeneralValue)] -> IO (Either String String),
     -- ^ Function that takes a filename, the current scope and a list of
     -- variables. It returns an error or the computed template.
+    puppetDBFunction :: Maybe (String -> PDB.Query -> IO (Either String [CResource]))
+    -- ^ Function that takes a fqdn, request type (resources, nodes, facts, ..)
+    -- and a query, and returns a resolved value from puppetDB.
 }
 
 -- | The monad all the interpreter lives in. It is 'ErrorT' with a state.
@@ -144,7 +148,7 @@
 generalizeStringS = Right
 
 -- |This is the set of meta parameters
-metaparameters = Set.fromList ["tag","stage","name","title","alias","audit","check","loglevel","noop","schedule"]
+metaparameters = Set.fromList ["tag","stage","name","title","alias","audit","check","loglevel","noop","schedule", "EXPORTEDSOURCE"]
 
 getPos               = liftM curPos get
 modifyScope     f sc = sc { curScope       = f $ curScope sc }
diff --git a/PuppetDB/Query.hs b/PuppetDB/Query.hs
new file mode 100644
--- /dev/null
+++ b/PuppetDB/Query.hs
@@ -0,0 +1,67 @@
+module PuppetDB.Query where
+
+import Data.List (intercalate)
+import Data.Char (toUpper)
+import Data.String.Utils (split)
+
+data Operator = OEqual | OOver | OUnder | OOverE | OUnderE | OAnd | OOr | ONot
+    deriving (Show, Ord, Eq)
+
+-- [Field] Value
+data Query = Query Operator [Query] | Term String | Terms [String]
+    deriving (Show, Ord, Eq)
+
+capitalize :: String -> String
+capitalize = intercalate "::" . map capitalize' . split "::"
+
+capitalize' :: String -> String
+capitalize' "" = ""
+capitalize' (x:xs) = toUpper x : xs
+
+-- | Query used for realizing a resources, when its type and title is known.
+queryRealize :: String -> String -> Query
+queryRealize rtype rtitle = Query OAnd
+                                [ Query OEqual [ Term "type",       Term (capitalize rtype) ]
+                                , Query OEqual [ Term "title",      Term rtitle ]
+                                , Query OEqual [ Term "exported",   Term "true" ]
+                                ]
+
+-- | Collects all resources of a given type
+collectAll :: String -> Query
+collectAll rtype = Query OAnd [ Query OEqual [ Term "type",     Term (capitalize rtype) ]
+                              , Query OEqual [ Term "exported", Term "true" ]
+                              ]
+
+-- | Collections based on tags.
+collectTag :: String -> String -> Query
+collectTag rtype tagval = Query OAnd
+                                [ Query OEqual [ Term "type",     Term (capitalize rtype) ]
+                                , Query OEqual [ Term "tag" ,     Term tagval ]
+                                , Query OEqual [ Term "exported", Term "true" ]
+                                ]
+
+-- | Used to emulate collections such as `Type<|| prmname == "prmval" ||>`
+collectParam :: String -> String -> String -> Query
+collectParam rtype prmname prmval = Query OAnd
+                                    [ Query OEqual [ Term "type",                    Term (capitalize rtype) ]
+                                    , Query OEqual [ Terms ["parameter", "prmname"], Term prmval ]
+                                    , Query OEqual [ Term "exported",                Term "true" ]
+                                    ]
+
+dq :: String -> String
+dq x = '"' : x ++ "\""
+
+showOperator :: Operator -> String
+showOperator OEqual     = dq "="
+showOperator OOver      = dq ">"
+showOperator OUnder     = dq "<"
+showOperator OOverE     = dq ">="
+showOperator OUnderE    = dq "<="
+showOperator OAnd       = dq "and"
+showOperator OOr        = dq "or"
+showOperator ONot       = dq "not"
+
+showQuery :: Query -> String
+showQuery (Query op subqueries) = "[" ++ intercalate ", " (showOperator op : map showQuery subqueries) ++ "]"
+showQuery (Term t)              = show t
+showQuery (Terms ts)            = show ts
diff --git a/PuppetDB/Rest.hs b/PuppetDB/Rest.hs
--- a/PuppetDB/Rest.hs
+++ b/PuppetDB/Rest.hs
@@ -2,8 +2,9 @@
 
 module PuppetDB.Rest where
 
+import qualified Puppet.DSL.Types as DT
 import Puppet.Interpreter.Types
-import Puppet.Printers
+import qualified PuppetDB.Query as PDB
 
 import Network.HTTP.Conduit
 import qualified Network.HTTP.Types as W
@@ -15,6 +16,10 @@
 import qualified Data.Text as T
 import Data.Attoparsec.Number
 import qualified Codec.Text.IConv as IConv
+import qualified Control.Exception as X
+import Control.Monad.Error
+import Control.Applicative
+import qualified Text.Parsec.Pos as TPP
 
 instance FromJSON ResolvedValue where
     parseJSON Null = return ResolvedUndefined
@@ -29,29 +34,64 @@
                                                                  ) (HM.toList o))
     parseJSON (Bool b) = return $ ResolvedBool b
 
-toAndQuery = undefined
+instance FromJSON CResource where
+    parseJSON (Object o) = do
+        utitle     <- o .: "title"
+        params     <- o .: "parameters"
+        sourcefile <- o .: "sourcefile"
+        sourceline <- o .: "sourceline"
+        certname   <- o .: "certname"
+        let _ = params :: HM.HashMap String ResolvedValue
+            parameters = map (\(k,v) -> (Right k, Right v)) $ ("EXPORTEDSOURCE", ResolvedString certname) : HM.toList params :: [(GeneralString, GeneralValue)]
+            position   = TPP.newPos (sourcefile ++ "(host: " ++ certname ++ ")") sourceline 1
+        CResource <$> pure 0
+                  <*> pure (Right utitle)
+                  <*> fmap (T.unpack . T.toLower) (o .: "type")
+                  <*> pure parameters
+                  <*> pure DT.Normal
+                  <*> pure position
+    parseJSON _ = mzero
 
-simpleNodeQuery :: String -> [(String, String)] -> IO (Either String ResolvedValue)
-simpleNodeQuery url query = rawRequest url "nodes" (toAndQuery query)
+runRequest req = do
+    let doRequest = withManager (\manager -> fmap responseBody $ httpLbs req manager) :: IO L.ByteString
+        eHandler :: X.SomeException -> IO (Either String  L.ByteString)
+        eHandler e = return $ Left $ show e ++ ", with queryString " ++ (BC.unpack $ queryString req)
+    mo <- liftIO ((fmap Right doRequest) `X.catch` eHandler)
+    case mo of
+        Right o -> do
+            let utf8 = IConv.convert "LATIN1" "UTF-8" o
+            case decode' utf8 of
+                Just x                   -> return x
+                Nothing                  -> throwError "Json decoding has failed"
+        Left err -> throwError err
 
-simpleResourceQuery :: String -> [(String, String)] -> IO (Either String ResolvedValue)
-simpleResourceQuery url query = rawRequest url "resources" (toAndQuery query)
+isNotLocal :: String -> CResource -> Bool
+isNotLocal fqdn cr =
+    let prms = crparams cr
+        e    = filter ((== Right "EXPORTEDSOURCE") . fst ) prms :: [(GeneralString, GeneralValue)]
+    in case e of
+        [(_, Right (ResolvedString x))] -> x /= fqdn
+        _ -> True
 
-rawRequest :: String -> String -> String -> IO (Either String ResolvedValue)
-rawRequest url querytype query = do
-        let q = BC.unpack $ W.renderSimpleQuery False [("query", BC.pack query)]
-            pfunc = parseUrl (url ++ "/" ++ querytype ++ "?" ++ q)
-        eInitReq <- case querytype of
-                       "resources"  -> fmap Right pfunc
-                       "nodes"      -> fmap Right pfunc
-                       _            -> return $ Left $ "Invalid query type " ++ querytype
-        case eInitReq of
-            Right initReq -> do
-                let req = initReq { requestHeaders = [("Accept", "application/json")] }
-                o <- withManager (\manager -> fmap responseBody $ httpLbs req manager) :: IO L.ByteString
-                let utf8 = IConv.convert "LATIN1" "UTF-8" o
-                case decode' utf8 :: Maybe ResolvedValue of
-                    Just x@(ResolvedArray _) -> return $ Right x
-                    Just x                   -> return $ Left $ "PuppetDB should have returned an array, not " ++ showValue x
-                    Nothing                  -> return $ Left "Json decoding has failed"
-            Left err -> return $ Left err
+pdbResRequest :: String -> String -> PDB.Query -> IO (Either String [CResource])
+pdbResRequest url fqdn qquery = do
+        res <- rawRequest url "resources" (PDB.showQuery qquery)
+        case res of
+            Left x -> return $ Left x
+            Right y -> return $ Right $ filter ( isNotLocal fqdn ) y
+
+pdbRequest :: String -> String -> PDB.Query -> IO (Either String ResolvedValue)
+pdbRequest url querytype qquery = rawRequest url querytype (PDB.showQuery qquery)
+
+rawRequest :: (FromJSON a) => String -> String -> String -> IO (Either String a)
+rawRequest url querytype query = runErrorT $ do
+        unless (querytype `elem` ["resources", "nodes", "facts"]) (throwError $ "Invalid query type " ++ querytype)
+        let q = case querytype of
+                    "facts" -> '/' : query
+                    _       -> "?" ++ (BC.unpack $ W.renderSimpleQuery False [("query", BC.pack query)])
+            fullurl = url ++ "/" ++ querytype ++ q
+        initReq <- case (parseUrl fullurl :: Maybe (Request a)) of
+            Just x -> return x
+            Nothing -> throwError "Something failed when parsing the PuppetDB URL"
+        let req = initReq { requestHeaders = [("Accept", "application/json")] }
+        runRequest req
diff --git a/language-puppet.cabal b/language-puppet.cabal
--- a/language-puppet.cabal
+++ b/language-puppet.cabal
@@ -7,7 +7,7 @@
 -- The package version. See the Haskell package versioning policy
 -- (http://www.haskell.org/haskellwiki/Package_versioning_policy) for
 -- standards guiding when and how versions should be incremented.
-Version:             0.1.7.2
+Version:             0.1.8.0
 
 -- A short (one-line) description of the package.
 Synopsis:            Tools to parse and evaluate the Puppet DSL.
@@ -52,11 +52,11 @@
     ghc-options:       -Wall -fno-warn-missing-signatures -fno-warn-unused-do-bind -funbox-strict-fields
   -- Modules exported by the library.
   Exposed-modules:     Puppet.DSL.Parser, Puppet.DSL.Printer, Puppet.Daemon, Puppet.Init, Puppet.DSL.Loader, Puppet.Printers, Puppet.NativeTypes, Puppet.DSL.Types,
-                       Puppet.Interpreter.Types, Puppet.Interpreter.Catalog, Puppet.NativeTypes.Helpers, PuppetDB.Rest
+                       Puppet.Interpreter.Types, Puppet.Interpreter.Catalog, Puppet.NativeTypes.Helpers, PuppetDB.Rest, PuppetDB.Query
 
   -- Packages needed in order to build this package.
   Build-depends:       base >=3 && <5,parsec,MissingH,containers,pretty,mtl,unix,hslogger,filepath,Glob,regexpr,process,bytestring,cryptohash,base16-bytestring,regex-pcre-builtin,
-                        iconv, text, unordered-containers, aeson, vector, http-types, http-conduit, attoparsec
+                        iconv, text, unordered-containers, aeson, vector, http-types, http-conduit, attoparsec, failure
 
   -- Modules not exported by this package.
   Other-modules:       Puppet.Interpreter.Functions, Puppet.NativeTypes.File, Erb.Compute, SafeProcess, Paths_language_puppet, Erb.Parser, Erb.Ruby, Erb.Evaluate
diff --git a/ruby/calcerb.rb b/ruby/calcerb.rb
--- a/ruby/calcerb.rb
+++ b/ruby/calcerb.rb
@@ -15,7 +15,7 @@
         elsif has_variable?(@context + "::" + name)
             @mvars[@context + "::" + name]
         else
-            :undef
+            throw("Unknown variable " + name)
         end
     end
 
