packages feed

yesod-json 0.2.3 → 0.3.1

raw patch · 2 files changed

+99/−54 lines, 2 filesdep +attoparsec-conduitdep +bytestringdep +conduitdep −attoparsec-enumeratordep −unordered-containersdep ~aesondep ~containersdep ~shakespeare-js

Dependencies added: attoparsec-conduit, bytestring, conduit, safe, wai, wai-extra, yesod-routes

Dependencies removed: attoparsec-enumerator, unordered-containers

Dependency ranges changed: aeson, containers, shakespeare-js, text, yesod-core

Files

Yesod/Json.hs view
@@ -1,88 +1,128 @@-{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE TypeSynonymInstances, OverloadedStrings #-} {-# LANGUAGE CPP #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Yesod.Json     ( -- * Convert from a JSON value       defaultLayoutJson     , jsonToRepJson+       -- * Convert to a JSON value     , parseJsonBody-      -- * Compatibility wrapper for old API-    , Json-    , jsonScalar-    , jsonList-    , jsonMap+    , parseJsonBody_++      -- * Produce JSON values+    , J.Value (..)+    , object+    , array+    , (.=)++      -- * Convenience functions+    , jsonOrRedirect     ) where -import Yesod.Handler (GHandler)+import Yesod.Handler (GHandler, waiRequest, lift, invalidArgs, redirect) import Yesod.Content     ( ToContent (toContent), RepHtmlJson (RepHtmlJson), RepHtml (RepHtml)     , RepJson (RepJson), Content (ContentBuilder)     ) import Yesod.Core (defaultLayout, Yesod) import Yesod.Widget (GWidget)+import Yesod.Routes.Class+import Control.Arrow (second)+import Control.Applicative ((<$>))+import Control.Monad (join) import qualified Data.Aeson as J+import Data.Aeson ((.=)) import qualified Data.Aeson.Encode as JE import Data.Aeson.Encode (fromValue)-import Data.Attoparsec.Enumerator (iterParser)-import Data.Text (pack)-import Control.Arrow (first)-import Control.Monad.Trans.Class (lift)-#if MIN_VERSION_aeson(0, 4, 0)-import Data.HashMap.Strict (fromList)-#else-import Data.Map (fromList)-#endif+import Data.Conduit.Attoparsec (sinkParser)+import Data.Text (Text, pack) import qualified Data.Vector as V import Text.Julius (ToJavascript (..)) import Data.Text.Lazy.Builder (fromLazyText) import Data.Text.Lazy.Encoding (decodeUtf8)-#if MIN_VERSION_aeson(0, 5, 0) import Data.Text.Lazy.Builder (toLazyText) import qualified Blaze.ByteString.Builder.Char.Utf8 as Blaze-#endif+import Data.Conduit (($$))+import Network.Wai (requestBody, requestHeaders)+import Network.Wai.Parse (parseHttpAccept)+import qualified Data.ByteString.Char8 as B8+import Safe (headMay)  instance ToContent J.Value where-#if MIN_VERSION_aeson(0, 5, 0)     toContent = flip ContentBuilder Nothing               . Blaze.fromLazyText               . toLazyText               . fromValue-#else-    toContent = flip ContentBuilder Nothing . fromValue-#endif --- | Provide both an HTML and JSON representation for a piece of data, using--- the default layout for the HTML output ('defaultLayout').-defaultLayoutJson :: Yesod master-                  => GWidget sub master ()-                  -> J.Value+-- | 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 json---- | Wraps the 'Content' generated by 'jsonToContent' in a 'RepJson'.-jsonToRepJson :: J.Value -> GHandler sub master RepJson-jsonToRepJson = return . RepJson . toContent+    return $ RepHtmlJson html' $ toContent (J.toJSON json) --- | Parse the request body as a JSON value.+-- | Wraps a data type in a 'RepJson'.  The data type must+-- support conversion to JSON via 'J.ToJSON'. ----- /Since: 0.2.3/-parseJsonBody :: GHandler sub master J.Value-parseJsonBody = lift $ iterParser J.json'+-- /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' -type Json = J.Value+-- | Same as 'parseJsonBody', but return an invalid args response on a parse+-- error.+parseJsonBody_ :: J.FromJSON a => GHandler sub master a+parseJsonBody_ = do+    ra <- parseJsonBody+    case ra of+        J.Error s -> invalidArgs [pack s]+        J.Success a -> return a -jsonScalar :: String -> Json-jsonScalar = J.String . pack+instance ToJavascript J.Value where+    toJavascript = fromLazyText . decodeUtf8 . JE.encode -jsonList :: [Json] -> Json-jsonList = J.Array . V.fromList+-- | Convert a list of pairs to an 'J.Object'.+object :: J.ToJSON a => [(Text, a)] -> J.Value+object = J.object . map (second J.toJSON) -jsonMap :: [(String, Json)] -> Json-jsonMap = J.Object . fromList . map (first pack)+-- | Convert a list of values to an 'J.Array'.+array :: J.ToJSON a => [a] -> J.Value+array = J.Array . V.fromList . map J.toJSON -instance ToJavascript J.Value where-    toJavascript = fromLazyText . decodeUtf8 . JE.encode+-- | jsonOrRedirect simplifies the scenario where a POST handler sends a different+-- response based on Accept headers:+--+--     1. 200 with JSON data if the client prefers application/json (e.g. AJAX).+--+--     2. 3xx otherwise, following the PRG pattern.+jsonOrRedirect :: (Yesod master, J.ToJSON a)+               => Route master -- ^ Redirect target+               -> a            -- ^ Data to send via JSON+               -> GHandler sub master RepJson+jsonOrRedirect r j = do+    q <- acceptsJson+    if q then jsonToRepJson (J.toJSON j)+         else redirect r+  where+    acceptsJson = maybe False ((== "application/json") . B8.takeWhile (/= ';'))+                . join+                . fmap (headMay . parseHttpAccept)+                . lookup "Accept" . requestHeaders+                <$> waiRequest
yesod-json.cabal view
@@ -1,5 +1,5 @@ name:            yesod-json-version:         0.2.3+version:         0.3.1 license:         BSD3 license-file:    LICENSE author:          Michael Snoyman <michael@snoyman.com>@@ -14,19 +14,24 @@  library     build-depends:   base                  >= 4        && < 5-                   , yesod-core            >= 0.9      && < 0.10-                   , aeson                 >= 0.3-                   , text                  >= 0.8      && < 0.12-                   , shakespeare-js        >= 0.10     && < 0.11+                   , yesod-core            >= 0.10.1   && < 0.11+                   , yesod-routes                         < 0.1+                   , aeson                 >= 0.5+                   , text                  >= 0.8      && < 1.0+                   , shakespeare-js        >= 0.11     && < 0.12                    , vector                >= 0.9-                   , containers            >= 0.2      && < 0.5-                   , unordered-containers+                   , containers            >= 0.2                    , blaze-builder-                   , attoparsec-enumerator >= 0.3      && < 0.4+                   , attoparsec-conduit    >= 0.2      && < 0.3+                   , conduit               >= 0.2      && < 0.3                    , transformers          >= 0.2.2    && < 0.3+                   , wai                   >= 1.1      && < 1.2+                   , wai-extra             >= 1.1      && < 1.2+                   , bytestring            >= 0.9      && < 0.10+                   , safe                  >= 0.2      && < 0.4     exposed-modules: Yesod.Json     ghc-options:     -Wall  source-repository head   type:     git-  location: git://github.com/yesodweb/yesod.git+  location: https://github.com/yesodweb/yesod