{-# LANGUAGE TypeSynonymInstances #-} {-# LANGUAGE CPP #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Yesod.Json ( -- * Convert from a JSON value defaultLayoutJson , jsonToRepJson -- * Convert to a JSON value , parseJsonBody -- * Produce JSON values , J.Value (..) , object , array ) where import Yesod.Handler (GHandler, waiRequest, lift) import Yesod.Content ( ToContent (toContent), RepHtmlJson (RepHtmlJson), RepHtml (RepHtml) , RepJson (RepJson), Content (ContentBuilder) ) import Yesod.Core (defaultLayout, Yesod) import Yesod.Widget (GWidget) import Control.Arrow (second) import qualified Data.Aeson as J import qualified Data.Aeson.Encode as JE import Data.Aeson.Encode (fromValue) import Data.Conduit.Attoparsec (sinkParser) import Data.Text (Text) import qualified Data.Vector as V import Text.Julius (ToJavascript (..)) import Data.Text.Lazy.Builder (fromLazyText) import Data.Text.Lazy.Encoding (decodeUtf8) import Data.Text.Lazy.Builder (toLazyText) import qualified Blaze.ByteString.Builder.Char.Utf8 as Blaze import Data.Conduit (($$)) import Network.Wai (requestBody) instance ToContent J.Value where toContent = flip ContentBuilder Nothing . Blaze.fromLazyText . toLazyText . fromValue -- | Provide both an HTML and JSON representation for a piece of -- data, using the default layout for the HTML output -- ('defaultLayout'). -- -- /Since: 0.3.0/ defaultLayoutJson :: (Yesod master, J.ToJSON a) => GWidget sub master () -- ^ HTML -> a -- ^ JSON -> GHandler sub master RepHtmlJson defaultLayoutJson w json = do RepHtml html' <- defaultLayout w return $ RepHtmlJson html' $ toContent (J.toJSON json) -- | Wraps a data type in a 'RepJson'. The data type must -- support conversion to JSON via 'J.ToJSON'. -- -- /Since: 0.3.0/ jsonToRepJson :: J.ToJSON a => a -> GHandler sub master RepJson jsonToRepJson = return . RepJson . toContent . J.toJSON -- | Parse the request body to a data type as a JSON value. The -- data type must support conversion from JSON via 'J.FromJSON'. -- If you want the raw JSON value, just ask for a @'J.Result' -- 'J.Value'@. -- -- /Since: 0.3.0/ parseJsonBody :: J.FromJSON a => GHandler sub master (J.Result a) parseJsonBody = do req <- waiRequest fmap J.fromJSON $ lift $ requestBody req $$ sinkParser J.json' instance ToJavascript J.Value where toJavascript = fromLazyText . decodeUtf8 . JE.encode -- | Convert a list of pairs to an 'J.Object'. object :: J.ToJSON a => [(Text, a)] -> J.Value object = J.object . map (second J.toJSON) -- | Convert a list of values to an 'J.Array'. array :: J.ToJSON a => [a] -> J.Value array = J.Array . V.fromList . map J.toJSON