packages feed

rest-core 0.29 → 0.30

raw patch · 7 files changed

+65/−48 lines, 7 filesdep +rest-stringmapdep +unordered-containersdep −tostringdep ~rest-typesPVP ok

version bump matches the API change (PVP)

Dependencies added: rest-stringmap, unordered-containers

Dependencies removed: tostring

Dependency ranges changed: rest-types

API changes (from Hackage documentation)

- Rest.Container: mappingI :: (Typeable k, IsString k, ToString k) => Inputs i -> Maybe (Inputs (StringMap k i))
+ Rest.Container: mappingI :: Inputs i -> Maybe (Inputs (StringHashMap String i))
- Rest.Container: mappingO :: (Typeable k, IsString k, ToString k) => Outputs o -> Maybe (Outputs (StringMap k o))
+ Rest.Container: mappingO :: Outputs o -> Maybe (Outputs (StringHashMap String o))
- Rest.Dictionary.Types: data Dict h_a7yA p_a7yB i_a7yC o_a7yD e_a7yE
+ Rest.Dictionary.Types: data Dict h_abNM p_abNN i_abNO o_abNP e_abNQ
- Rest.Driver.RestM: RestInput :: Map String String -> Map String String -> ByteString -> Method -> [String] -> Map String String -> RestInput
+ Rest.Driver.RestM: RestInput :: HashMap String String -> HashMap String String -> ByteString -> Method -> [String] -> HashMap String String -> RestInput
- Rest.Driver.RestM: RestOutput :: Map String String -> Maybe Int -> RestOutput
+ Rest.Driver.RestM: RestOutput :: HashMap String String -> Maybe Int -> RestOutput
- Rest.Driver.RestM: headers :: RestInput -> Map String String
+ Rest.Driver.RestM: headers :: RestInput -> HashMap String String
- Rest.Driver.RestM: headersSet :: RestOutput -> Map String String
+ Rest.Driver.RestM: headersSet :: RestOutput -> HashMap String String
- Rest.Driver.RestM: mimeTypes :: RestInput -> Map String String
+ Rest.Driver.RestM: mimeTypes :: RestInput -> HashMap String String
- Rest.Driver.RestM: parameters :: RestInput -> Map String String
+ Rest.Driver.RestM: parameters :: RestInput -> HashMap String String

Files

CHANGELOG.md view
@@ -1,5 +1,16 @@ # Changelog +## 0.30++* Use `Content-Disposition` to provide filenames for file responses.+  This slightly changes the semantics of `FileO`: what used to be+  interpreted as the file extension is now used for the whole file name.++* `Rest.Types.Container.StringMap` Has been replaced by `rest-stringmap`. This+  changes the XML serialization format of multi part messages, the old format+  was `<map><key>k</key>v[...]</map>` and the new one is+  `<map><value key="k">v</value>[...]</map>`.+ ## 0.29  * Add multi-delete handler. It is used on a DELETE to
rest-core.cabal view
@@ -1,5 +1,5 @@ Name:               rest-core-Version:            0.29+Version:            0.30 Description:        Rest API library. Synopsis:           Rest API library. Maintainer:         code@silk.co@@ -28,12 +28,13 @@     , mtl                       >= 2.0    &&  < 2.2     , multipart                 >= 0.1.1  &&  < 0.2     , random                    == 1.0.*-    , rest-types                == 1.9.*+    , rest-stringmap            == 0.1.*+    , rest-types                == 1.10.*     , safe                      >= 0.2    &&  < 0.4     , split                     >= 0.1    &&  < 0.3     , text                      >= 0.11   &&  < 1.2-    , tostring                  == 0.2.*     , transformers              >= 0.2    &&  < 0.4+    , unordered-containers      == 0.2.*     , uri-encode                == 1.5.*     , utf8-string               == 0.3.*     , uuid                      >= 1.2    &&  < 1.4
src/Rest/Container.hs view
@@ -1,11 +1,11 @@ {-# LANGUAGE-    TemplateHaskell+    DeriveDataTypeable   , EmptyDataDecls-  , TypeFamilies   , FlexibleInstances-  , ScopedTypeVariables-  , DeriveDataTypeable   , GADTs+  , ScopedTypeVariables+  , TemplateHaskell+  , TypeFamilies   #-} module Rest.Container   ( module Rest.Types.Container@@ -18,12 +18,10 @@   ) where  import Data.Maybe-import Data.String-import Data.String.ToString-import Data.Typeable  import Rest.Dictionary import Rest.Error+import Rest.StringMap.HashMap.Strict import Rest.Types.Container  listI :: Inputs a -> Maybe (Inputs (List a))@@ -50,26 +48,26 @@     listDictO JsonO = Just JsonO     listDictO _     = Nothing -mappingI :: forall k i. (Typeable k, IsString k, ToString k) => Inputs i -> Maybe (Inputs (StringMap k i))+mappingI :: forall i. Inputs i -> Maybe (Inputs (StringHashMap String i)) mappingI None       = Just (Dicts [XmlI, JsonI]) mappingI (Dicts is) =   case mapMaybe mappingDictI is of     []  -> Nothing     mis -> Just (Dicts mis)   where-    mappingDictI :: Input i -> Maybe (Input (StringMap k i))+    mappingDictI :: Input i -> Maybe (Input (StringHashMap String i))     mappingDictI XmlI  = Just XmlI     mappingDictI JsonI = Just JsonI     mappingDictI _     = Nothing -mappingO :: forall k o. (Typeable k, IsString k, ToString k) => Outputs o -> Maybe (Outputs (StringMap k o))+mappingO :: forall o. Outputs o -> Maybe (Outputs (StringHashMap String o)) mappingO None       = Just (Dicts [XmlO, JsonO]) mappingO (Dicts os) =   case mapMaybe mappingDictO os of     []  -> Nothing     mos -> Just (Dicts mos)   where-    mappingDictO :: Output o -> Maybe (Output (StringMap k o))+    mappingDictO :: Output o -> Maybe (Output (StringHashMap String o))     mappingDictO XmlO  = Just XmlO     mappingDictO JsonO = Just JsonO     mappingDictO _     = Nothing
src/Rest/Driver/Perform.hs view
@@ -330,9 +330,11 @@         tryD (JsonO      : _ ) JsonFormat   = contentType JsonFormat   >> ok (encode v)         tryD (StringO    : _ ) StringFormat = contentType StringFormat >> ok (UTF8.fromString v)         tryD (MultipartO : _ ) _            = outputMultipart v-        tryD (FileO      : _ ) FileFormat   = do mime <- fromMaybe "application/octet-stream" <$> lookupMimeType (map toLower (snd v))+        tryD (FileO      : _ ) FileFormat   = do let ext = (reverse . takeWhile (/='.') . reverse) $ snd v+                                                 mime <- fromMaybe "application/octet-stream" <$> lookupMimeType (map toLower ext)                                                  setHeader "Content-Type" mime                                                  setHeader "Cache-Control" "max-age=604800"+                                                 setHeader "Content-Disposition" ("filename=" ++ snd v)                                                  ok (fst v)         tryD []                t            = throwError (UnsupportedFormat (show t))         tryD (_          : xs) t            = tryD xs t
src/Rest/Driver/RestM.hs view
@@ -11,48 +11,47 @@ import Control.Applicative import Control.Monad.Reader import Control.Monad.Writer-import Data.Map (Map)--import qualified Data.Map                  as Map+import Data.HashMap.Strict (HashMap) import qualified Data.ByteString.Lazy.UTF8 as UTF8+import qualified Data.HashMap.Strict       as H  import Rest.Driver.Perform (Rest)-import qualified Rest.Driver.Types   as Rest import qualified Rest.Driver.Perform as Rest+import qualified Rest.Driver.Types   as Rest  data RestInput = RestInput-  { headers      :: Map String String-  , parameters   :: Map String String-  , body         :: UTF8.ByteString-  , method       :: Rest.Method-  , paths        :: [String]-  , mimeTypes    :: Map String String+  { headers    :: HashMap String String+  , parameters :: HashMap String String+  , body       :: UTF8.ByteString+  , method     :: Rest.Method+  , paths      :: [String]+  , mimeTypes  :: HashMap String String   }  emptyInput :: RestInput emptyInput = RestInput-  { headers    = Map.empty-  , parameters = Map.empty+  { headers    = H.empty+  , parameters = H.empty   , body       = mempty   , method     = Rest.GET   , paths      = []-  , mimeTypes  = Map.empty+  , mimeTypes  = H.empty   }  data RestOutput = RestOutput-  { headersSet   :: Map String String+  { headersSet   :: HashMap String String   , responseCode :: Maybe Int   } deriving Show  instance Monoid RestOutput where-  mempty = RestOutput { headersSet = Map.empty, responseCode = Nothing }+  mempty = RestOutput { headersSet = H.empty, responseCode = Nothing }   o1 `mappend` o2 = RestOutput-    { headersSet   = headersSet o2 `Map.union` headersSet o1+    { headersSet   = headersSet o2 `H.union` headersSet o1     , responseCode = responseCode o2 <|> responseCode o1     }  outputHeader :: String -> String -> RestOutput-outputHeader h v = mempty { headersSet = Map.singleton h v }+outputHeader h v = mempty { headersSet = H.singleton h v }  outputCode :: Int -> RestOutput outputCode cd = mempty { responseCode = Just cd }@@ -70,11 +69,11 @@ runRestM_ i = fmap fst . runRestM i  instance (Functor m, Applicative m, Monad m) => Rest (RestM m) where-  getHeader    h     = RestM $ asks (Map.lookup h . headers   )-  getParameter p     = RestM $ asks (Map.lookup p . parameters)+  getHeader    h     = RestM $ asks (H.lookup h . headers   )+  getParameter p     = RestM $ asks (H.lookup p . parameters)   getBody            = RestM $ asks body   getMethod          = RestM $ asks method   getPaths           = RestM $ asks paths-  lookupMimeType t   = RestM $ asks (Map.lookup t . mimeTypes)+  lookupMimeType t   = RestM $ asks (H.lookup t . mimeTypes)   setHeader h v      = RestM $ tell (outputHeader h v)   setResponseCode cd = RestM $ tell (outputCode cd)
src/Rest/Driver/Routing.hs view
@@ -4,6 +4,8 @@            , NamedFieldPuns            , FlexibleContexts            , StandaloneDeriving+    , ViewPatterns+    , NamedFieldPuns            , GADTs            , ScopedTypeVariables            , DeriveDataTypeable@@ -34,13 +36,14 @@ import Safe import qualified Control.Monad.State       as State import qualified Data.ByteString.Lazy.UTF8 as LUTF8+import qualified Data.HashMap.Strict       as H import qualified Data.Label.Total          as L-import qualified Data.Map                  as Map  import Network.URI.Encode (decode) import Rest.Api (Some1(..)) import Rest.Container import Rest.Dictionary+import qualified Rest.StringMap.HashMap.Strict as StringHashMap import Rest.Error import Rest.Handler (ListHandler, Handler, GenHandler (..), Env (..), range, mkInputHandler, Range (..)) import Rest.Types.Container.Resource (Resource, Resources (..))@@ -308,11 +311,11 @@     mNewDict =  L.traverse inputs mappingI             <=< L.traverse outputs (mappingO <=< statusO (L.get errors newErrDict))              $  newErrDict-    newAct (Env hs ps (StringMap vs)) =-      do bs <- lift $ forM vs $ \(k, v) -> runErrorT $+    newAct (Env hs ps vs) =+      do bs <- lift $ forM (StringHashMap.toList vs) $ \(k, v) -> runErrorT $            do i <- parseIdent sBy k               mapErrorT (run i) (act (Env hs ps v))-         return (StringMap (zipWith (\(k, _) b -> (k, eitherToStatus b)) vs bs))+         return . StringHashMap.fromList $ zipWith (\(k, _) b -> (k, eitherToStatus b)) (StringHashMap.toList vs) bs  mkMultiGetHandler :: forall m s. (Applicative m, Monad m) => Rest.Router m s -> Handler m mkMultiGetHandler root = mkInputHandler (xmlJsonI . someI . multipartO) $ \(Resources rs) -> multiGetHandler rs@@ -332,13 +335,13 @@     routeResource uri = runRouter GET (splitUriString uri) (routeRoot root)      toRestInput r = Rest.emptyInput-      { Rest.headers    = Map.map R.unValue . fromStringMap . R.headers    $ r-      , Rest.parameters = Map.map R.unValue . fromStringMap . R.parameters $ r+      { Rest.headers    = H.map (R.unValue) . StringHashMap.toHashMap . R.headers    $ r+      , Rest.parameters = H.map (R.unValue) . StringHashMap.toHashMap . R.parameters $ r       , Rest.body       = LUTF8.fromString (R.input r)       , Rest.paths      = splitUriString (R.uri r)       } -    mkHeaders = map (first HeaderName) . Map.toList+    mkHeaders = map (first HeaderName) . H.toList      mkBodyPart bdy restOutput =       let hdrs = (HeaderName "X-Response-Code", maybe "200" show (Rest.responseCode restOutput))
tests/Runner.hs view
@@ -1,4 +1,7 @@-{-# LANGUAGE ScopedTypeVariables, OverloadedStrings #-}+{-# LANGUAGE+    OverloadedStrings+  , ScopedTypeVariables+  #-}  import Control.Applicative import Control.Monad@@ -6,12 +9,13 @@ import Data.Monoid import Test.Framework (defaultMain) import Test.Framework.Providers.HUnit (testCase)-import Test.HUnit (Assertion, assertFailure, assertEqual)+import Test.HUnit (Assertion, assertEqual, assertFailure)  import qualified Data.ByteString.Char8 as Char8-import qualified Data.Map as Map+import qualified Data.HashMap.Strict   as H  import Rest.Api hiding (route)+import Rest.Dictionary import Rest.Driver.Perform (accept) import Rest.Driver.RestM (runRestM_) import Rest.Driver.Routing@@ -19,8 +23,7 @@ import Rest.Handler import Rest.Resource import Rest.Schema-import Rest.Dictionary-import qualified Rest.Api as Rest+import qualified Rest.Api          as Rest import qualified Rest.Driver.RestM as RestM  main :: IO ()@@ -202,5 +205,5 @@  testAcceptHeaders :: Assertion testAcceptHeaders =-  do fmt <- runRestM_ RestM.emptyInput { RestM.headers = Map.singleton "Accept" "text/json" } accept+  do fmt <- runRestM_ RestM.emptyInput { RestM.headers = H.singleton "Accept" "text/json" } accept      assertEqual "Accept json format." [JsonFormat] fmt