packages feed

rest-core 0.39 → 0.39.0.1

raw patch · 14 files changed

+147/−81 lines, 14 filesdep ~aesondep ~basedep ~transformers-compat

Dependency ranges changed: aeson, base, transformers-compat

Files

rest-core.cabal view
@@ -1,5 +1,5 @@ name:                rest-core-version:             0.39+version:             0.39.0.1 description:         Rest API library. synopsis:            Rest API library. maintainer:          code@silk.co@@ -40,13 +40,13 @@     Rest.Schema     Rest.ShowUrl   build-depends:-      base >= 4.5 && < 4.10-    , aeson >= 0.7 && < 0.12+      base >= 4.5 && < 4.12+    , aeson >= 0.7 && < 1.4     , aeson-utils >= 0.2 && < 0.4     , base-compat >= 0.8 && < 0.10     , bytestring >= 0.9 && < 0.11     , case-insensitive >= 1.2 && < 1.3-    , errors >= 1.4 && < 2.2+    , errors >= 1.4 && < 2.3     , fclabels == 2.0.*     , hxt >= 9.2 && < 9.4     , hxt-pickle-utils == 0.1.*@@ -61,7 +61,7 @@     , split >= 0.1 && < 0.3     , text >= 0.11 && < 1.3     , transformers >= 0.2 && < 0.6-    , transformers-compat >= 0.3 && < 0.6+    , transformers-compat >= 0.3 && < 0.7     , unordered-containers == 0.2.*     , uri-encode == 1.5.*     , utf8-string >= 0.3 && < 1.1@@ -73,13 +73,14 @@   main-is:           Runner.hs   type:              exitcode-stdio-1.0   build-depends:-      base >= 4.5 && < 4.10-    , HUnit >= 1.2 && < 1.4+      base >= 4.5 && < 4.12+    , aeson >= 0.7 && < 1.4+    , HUnit >= 1.2 && < 1.7     , bytestring >= 0.9 && < 0.11     , mtl >= 2.0 && < 2.3     , rest-core     , test-framework == 0.8.*     , test-framework-hunit == 0.3.*     , transformers >= 0.3 && < 0.6-    , transformers-compat >= 0.3 && < 0.6+    , transformers-compat >= 0.3 && < 0.7     , unordered-containers == 0.2.*
src/Rest.hs view
@@ -26,3 +26,5 @@                     ) import Rest.Resource (Resource, mkResource, mkResourceId, mkResourceReader, mkResourceReaderWith, Void) import Rest.Schema++{-# ANN module "HLint: ignore Use import/export shortcut" #-}
src/Rest/Api.hs view
@@ -1,8 +1,12 @@ {-# LANGUAGE-    GADTs+    CPP+  , GADTs   , KindSignatures   , NoImplicitPrelude   #-}+#if MIN_VERSION_base(4,9,0)+{-# OPTIONS_GHC -Wno-redundant-constraints #-}+#endif -- | This module allows you to combine 'Resource's into an 'Api'. This -- can then be served using 'rest-happstack' or 'rest-snap', or used -- to generate clients or documentation using 'rest-gen'.@@ -129,7 +133,7 @@ -- | Get the latest version of an API.  latest :: VersionSet m -> Maybe (Version, Some1 (Router m))-latest = headMay . reverse . sortBy (compare `on` fst)+latest = headMay . sortBy (flip compare `on` fst)  -- | Parse a 'String' as a 'Version'. The string should contain two or -- three numbers separated by dots, e.g. @1.12.3@.
src/Rest/Container.hs view
@@ -1,11 +1,7 @@ {-# LANGUAGE     DataKinds-  , DeriveDataTypeable-  , EmptyDataDecls-  , FlexibleInstances   , GADTs   , ScopedTypeVariables-  , TemplateHaskell   , TypeFamilies   #-} module Rest.Container@@ -84,7 +80,7 @@  mkStatusDict :: forall e o. [Error e] -> [Output o] -> Maybe (Outputs ('Just (Status e o))) mkStatusDict es os =-    case mapMaybe mappingDictO (intersect es os) of+    case mapMaybe mappingDictO (es `intersect` os) of       []  -> Nothing       sos -> Just (Dicts sos)     where
src/Rest/Driver/Perform.hs view
@@ -1,10 +1,14 @@ {-# LANGUAGE-    FlexibleContexts+    CPP+  , FlexibleContexts   , GADTs   , OverloadedStrings   , RankNTypes   , ScopedTypeVariables   #-}+#if MIN_VERSION_base(4,9,0)+{-# OPTIONS_GHC -Wno-redundant-constraints #-}+#endif module Rest.Driver.Perform   ( Rest (..)   , failureWriter@@ -29,11 +33,10 @@ import Data.List.Split import Data.Maybe import Data.Text.Lazy.Encoding (decodeUtf8)-import Data.UUID (UUID)+import Data.UUID.V4 (nextRandom) import Network.Multipart (BodyPart (..), MultiPart (..), showMultipartBody) import Safe import System.IO.Unsafe-import System.Random (randomIO) import Text.Xml.Pickle  import qualified Data.ByteString.Lazy      as B@@ -355,14 +358,14 @@ tryOutputs :: Rest m => (t -> Format -> ExceptT (Last DataError) m a) -> t -> ExceptT (Reason e) m a tryOutputs try outputs = do   formats <- lift acceptM-  rethrowLast $ (msum $ try outputs <$> formats) <|> unsupportedFormat formats+  rethrowLast $ msum (try outputs <$> formats) <|> unsupportedFormat formats   where     rethrowLast :: Monad m => ExceptT (Last DataError) m a -> ExceptT (Reason e) m a     rethrowLast = either (maybe (error "Rest.Driver.Perform: ExceptT threw Last Nothing, this is a bug") (throwError . OutputError) . getLast) return <=< lift . runExceptT  outputMultipart :: Rest m => [BodyPart] -> m UTF8.ByteString outputMultipart vs =-  do let boundary = show $ unsafePerformIO (randomIO :: IO UUID)+  do let boundary = show $ unsafePerformIO nextRandom      setHeader "Content-Type" ("multipart/mixed; boundary=" ++ boundary)      return $ showMultipartBody boundary (MultiPart vs) @@ -388,7 +391,7 @@   in (fromQuery ++ fromAccept)   where     allFormats :: Maybe Format -> [Format]-    allFormats ct = (maybe id (:) ct) [minBound .. maxBound]+    allFormats ct = maybe id (:) ct [minBound .. maxBound]     splitter :: Maybe Format -> String -> [Format]     splitter ct hdr = nub (match ct =<< takeWhile (/= ';') . trim <$> splitOn "," hdr) 
src/Rest/Driver/RestM.hs view
@@ -1,4 +1,10 @@-{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE+    CPP+  , GeneralizedNewtypeDeriving+  #-}+#if MIN_VERSION_base(4,9,0)+{-# OPTIONS_GHC -Wno-redundant-constraints #-}+#endif module Rest.Driver.RestM   ( RestM   , runRestM@@ -44,12 +50,15 @@   , responseCode :: Maybe Int   } deriving Show -instance Monoid RestOutput where-  mempty = RestOutput { headersSet = H.empty, responseCode = Nothing }-  o1 `mappend` o2 = RestOutput+instance Semigroup RestOutput where+  o1 <> o2 = RestOutput     { headersSet   = headersSet o2 `H.union` headersSet o1     , responseCode = responseCode o2 <|> responseCode o1     }++instance Monoid RestOutput where+  mempty = RestOutput { headersSet = H.empty, responseCode = Nothing }+  mappend = (<>)  outputHeader :: String -> String -> RestOutput outputHeader h v = mempty { headersSet = H.singleton h v }
src/Rest/Driver/Routing/Internal.hs view
@@ -1,5 +1,5 @@ {-# LANGUAGE-    DeriveDataTypeable+    CPP   , ExistentialQuantification   , FlexibleContexts   , GADTs@@ -7,9 +7,12 @@   , NamedFieldPuns   , RankNTypes   , ScopedTypeVariables-  , StandaloneDeriving   , TupleSections   #-}+#if MIN_VERSION_base(4,9,0)+{-# OPTIONS_GHC -Wno-redundant-constraints #-}+#endif+ module Rest.Driver.Routing.Internal where  import Prelude hiding (id, (.))@@ -51,6 +54,8 @@  import qualified Rest.Driver.RestM as Rest +{-# ANN module "HLint: ignore Reduce duplication" #-}+ type UriParts = [String]  apiError :: (MonadError (Reason e) m) => Reason e -> m a@@ -76,11 +81,11 @@                       . unRouter  route :: (Applicative m, Monad m) => Maybe Method -> UriParts -> Rest.Api m -> Either Reason_ (RunnableHandler m)-route mtd uri = routeWith defaultConfig mtd uri+route = routeWith defaultConfig  routeWith :: Config m -> Maybe Method -> UriParts -> Rest.Api m -> Either Reason_ (RunnableHandler m) routeWith _    Nothing   _   _   = apiError UnsupportedMethod-routeWith cfg (Just mtd) uri api = runRouter cfg mtd uri $ do+routeWith cfg (Just mtd) uri api = runRouter cfg mtd uri $   case api of     Rest.Unversioned (Some1 router) -> routeRoot router     Rest.Versioned   vrs            -> do@@ -102,7 +107,7 @@      return (RunnableHandler id (mkMultiGetHandler cfg root))  routeRouter :: Rest.Router m s -> Router n (RunnableHandler m)-routeRouter (Rest.Embed resource@(Rest.Resource { Rest.schema }) subRouters) =+routeRouter (Rest.Embed resource@Rest.Resource { Rest.schema } subRouters) =   case schema of     (Rest.Schema mToplevel step) -> maybe (apiError UnsupportedRoute) return =<< runMaybeT        (  routeToplevel resource subRouters mToplevel@@ -114,7 +119,7 @@               -> [Some1 (Rest.Router s)]               -> Maybe (Rest.Cardinality sid mid)               -> MaybeT (Router n) (RunnableHandler m)-routeToplevel resource@(Rest.Resource { Rest.list }) subRouters mToplevel =+routeToplevel resource@Rest.Resource { Rest.list } subRouters mToplevel =   hoistMaybe mToplevel >>= \toplevel ->   case toplevel of     Rest.Single sid -> lift $ withSubresource sid resource subRouters@@ -124,7 +129,7 @@          lift $ routeListHandler (list mid)  routeCreate :: Rest.Resource m s sid mid aid -> MaybeT (Router n) (RunnableHandler m)-routeCreate (Rest.Resource { Rest.create }) = guardNullPath >> guardMethod POST >>+routeCreate Rest.Resource { Rest.create } = guardNullPath >> guardMethod POST >>   maybe (apiError UnsupportedRoute) (return . RunnableHandler id) create  routeStep :: Rest.Resource m s sid mid aid@@ -143,7 +148,7 @@            -> [Some1 (Rest.Router s)]            -> Rest.Endpoint sid mid aid            -> Router n (RunnableHandler m)-routeNamed resource@(Rest.Resource { Rest.list, Rest.statics }) subRouters h =+routeNamed resource@Rest.Resource { Rest.list, Rest.statics } subRouters h =   case h of     Left aid -> noRestPath >> hasMethod POST >> return (RunnableHandler id (statics aid))     Right (Rest.Single getter) -> routeGetter getter resource subRouters@@ -153,10 +158,10 @@              -> [Some1 (Rest.Router s)]              -> Rest.Cardinality (Rest.Id sid) (Rest.Id mid)              -> Router n (RunnableHandler m)-routeUnnamed resource@(Rest.Resource { Rest.list }) subRouters cardinality =+routeUnnamed resource@Rest.Resource { Rest.list } subRouters cardinality =   case cardinality of-    Rest.Single sBy -> withSegment (multi resource sBy) $ \seg ->-      parseIdent sBy seg >>= \sid -> withSubresource sid resource subRouters+    Rest.Single sBy -> withSegment (multi resource sBy) $+      parseIdent sBy >=> \sid -> withSubresource sid resource subRouters     Rest.Many   mBy ->       do seg <- popSegment          mid <- parseIdent mBy seg@@ -171,13 +176,13 @@ routeGetter getter resource subRouters =   case getter of     Rest.Singleton sid -> getOrDeep sid-    Rest.By        sBy -> withSegment (multi resource sBy) $ \seg ->-                            parseIdent sBy seg >>= getOrDeep+    Rest.By        sBy -> withSegment (multi resource sBy) $+                            parseIdent sBy >=> getOrDeep   where     getOrDeep sid = withSubresource sid resource subRouters  multi :: Rest.Resource m s sid mid aid -> Rest.Id sid -> Router n (RunnableHandler m)-multi (Rest.Resource { Rest.update, Rest.remove, Rest.enter }) sBy =+multi Rest.Resource { Rest.update, Rest.remove, Rest.enter } sBy =   asks method >>= \mtd ->   case mtd of     PUT    -> handleOrNotFound update@@ -206,7 +211,7 @@                 -> Rest.Resource m s sid mid aid                 -> [Some1 (Rest.Router s)]                 -> Router n (RunnableHandler m)-withSubresource sid resource@(Rest.Resource { Rest.enter, Rest.selects, Rest.actions }) subRouters =+withSubresource sid resource@Rest.Resource { Rest.enter, Rest.selects, Rest.actions } subRouters =   withSegment (routeSingle sid resource) $ \seg ->   case lookup seg selects of     Just select -> noRestPath >> hasMethod GET >> return (RunnableHandler (enter sid) select)@@ -220,7 +225,7 @@           Nothing -> apiError UnsupportedRoute  routeSingle :: sid -> Rest.Resource m s sid mid aid -> Router n (RunnableHandler m)-routeSingle sid (Rest.Resource { Rest.enter, Rest.get, Rest.update, Rest.remove }) =+routeSingle sid Rest.Resource { Rest.enter, Rest.get, Rest.update, Rest.remove } =   asks method >>= \mtd ->   case mtd of     GET    -> handleOrNotFound get@@ -231,7 +236,7 @@     handleOrNotFound = maybe (apiError UnsupportedRoute) (return . RunnableHandler (enter sid))  routeName :: String -> Router n ()-routeName ident = when (not . null $ ident) $+routeName ident = unless (null ident) $   do identStr <- popSegment      when (identStr /= ident) $        apiError UnsupportedRoute@@ -287,9 +292,8 @@  hasMethod :: Method -> Router n () hasMethod wantedMethod = asks method >>= \mtd ->-  if mtd == wantedMethod-  then return ()-  else apiError UnsupportedMethod+  unless (mtd == wantedMethod) $+    apiError UnsupportedMethod  guardMethod :: (MonadPlus m, MonadReader (RouterData c) m) => Method -> m () guardMethod mtd = asks method >>= guard . (== mtd)@@ -322,7 +326,7 @@          return . StringHashMap.fromList $ zipWith (\(k, _) b -> (k, eitherToStatus b)) (StringHashMap.toList vs) bs  mkMultiGetHandler :: forall m s. (Applicative m, Monad m) => Config m -> Rest.Router m s -> Handler m-mkMultiGetHandler cfg root = mkInputHandler (xmlJsonI . multipartO) $ \(Resources rs) -> (runMultiResources cfg) cfg root rs+mkMultiGetHandler cfg root = mkInputHandler (xmlJsonI . multipartO) $ \(Resources rs) -> runMultiResources cfg cfg root rs  defaultRunMultiResources :: (Applicative m, Monad m) => Config m -> Rest.Router m s -> [Resource] -> ExceptT Reason_ m [BodyPart] defaultRunMultiResources cfg root rs = lift $ forM rs (runResource cfg root)@@ -342,8 +346,8 @@  toRestInput :: Resource -> Rest.RestInput toRestInput r = Rest.emptyInput-  { Rest.headers    = H.map (R.unValue) . StringHashMap.toHashMap . R.headers    $ r-  , Rest.parameters = H.map (R.unValue) . StringHashMap.toHashMap . 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.method     = Just (R.method r)   , Rest.paths      = splitUriString (R.uri r)
src/Rest/Driver/Types.hs view
@@ -27,7 +27,7 @@ mapHandler :: Run m n -> RunnableHandler m -> RunnableHandler n mapHandler run (RunnableHandler run' h) = RunnableHandler (run . run') h -data Config m+newtype Config m   = Config   { runMultiResources :: forall s. Config m -> Router m s -> [Resource] -> ExceptT Reason_ m [BodyPart]   }
src/Rest/Error.hs view
@@ -1,8 +1,12 @@ {-# LANGUAGE-    FlexibleContexts+    CPP+  , FlexibleContexts   , GADTs   , NoImplicitPrelude   #-}+#if MIN_VERSION_base(4,9,0)+{-# OPTIONS_GHC -Wno-redundant-constraints #-}+#endif -- | Error types that can be returned by handlers, as well as some -- utilities for manipulating these errors. module Rest.Error
src/Rest/Handler.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE-    DataKinds+    CPP+  , DataKinds   , DeriveDataTypeable   , GADTs   , KindSignatures@@ -7,6 +8,9 @@   , TupleSections   , TypeFamilies   #-}+#if MIN_VERSION_base(4,9,0)+{-# OPTIONS_GHC -Wno-redundant-constraints #-}+#endif -- | Handlers for endpoints in a 'Resource'. module Rest.Handler   ( -- * Single handlers.
src/Rest/Resource.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE-    FlexibleContexts+    CPP+  , FlexibleContexts   , FlexibleInstances   , GADTs   , KindSignatures@@ -7,9 +8,11 @@   , NamedFieldPuns   , NoImplicitPrelude   , RankNTypes-  , TemplateHaskell   , TypeSynonymInstances   #-}+#if MIN_VERSION_base(4,9,0)+{-# OPTIONS_GHC -Wno-redundant-constraints #-}+#endif -- | A 'Resource' type for representing a REST resource, as well as -- smart constructors for empty resources which can then be filled in -- using record updates.
src/Rest/Run.hs view
@@ -1,7 +1,11 @@ {-# LANGUAGE-    NoImplicitPrelude+    CPP+  , NoImplicitPrelude   , RankNTypes   #-}+#if MIN_VERSION_base(4,9,0)+{-# OPTIONS_GHC -Wno-redundant-constraints #-}+#endif module Rest.Run   ( apiToHandler   , apiToHandler'@@ -23,7 +27,7 @@ apiToHandler = apiToHandler' id  apiToHandler' :: (Applicative m, Monad m) => Rest n => Run m n -> Api m -> n UTF8.ByteString-apiToHandler' run = apiToHandlerWith I.defaultConfig run+apiToHandler' = apiToHandlerWith I.defaultConfig  apiToHandlerWith :: Config m -> Rest n => Run m n -> Api m -> n UTF8.ByteString apiToHandlerWith cfg run api = do
src/Rest/Schema.hs view
@@ -82,7 +82,7 @@  -- | A single resource endpoint with an identifier that can be read. -singleRead :: (Show a, Read a, Info a) => (a -> sid) -> Endpoint sid mid aid+singleRead :: (Read a, Info a) => (a -> sid) -> Endpoint sid mid aid singleRead = singleIdent ReadId  -- | A single resource identified as specified by the 'Ident'.@@ -102,7 +102,7 @@  -- | A listing with an identifier that can be read. -listingRead :: (Show a, Read a, Info a) => (a -> mid) -> Endpoint sid mid aid+listingRead :: (Read a, Info a) => (a -> mid) -> Endpoint sid mid aid listingRead = listingIdent ReadId  -- | A listing identified as specified by the 'Ident'.@@ -118,7 +118,7 @@  -- | An unnamed single resource with an identifier that can be read. -unnamedSingleRead :: (Show a, Read a, Info a) => (a -> sid) -> Step sid mid aid+unnamedSingleRead :: (Read a, Info a) => (a -> sid) -> Step sid mid aid unnamedSingleRead = unnamedSingleIdent ReadId  -- | An unnamed single resource identified as specified by the@@ -133,7 +133,7 @@ unnamedListing = unnamedListingIdent StringId  -- | An unnamed listing with an identifier that can be read.-unnamedListingRead :: (Show a, Read a, Info a) => (a -> mid) -> Step sid mid aid+unnamedListingRead :: (Read a, Info a) => (a -> mid) -> Step sid mid aid unnamedListingRead = unnamedListingIdent ReadId  -- | An unnamed listing identified as specified by the 'Ident'.
tests/Runner.hs view
@@ -1,32 +1,38 @@ {-# LANGUAGE-    OverloadedStrings+    CPP+  , OverloadedStrings+  , RankNTypes   , ScopedTypeVariables   #-}--import Control.Applicative+#if MIN_VERSION_base(4,9,0)+{-# OPTIONS_GHC -Wno-redundant-constraints #-}+#endif import Control.Monad+import Control.Monad.Except+import Control.Monad.Identity import Control.Monad.Reader+import Data.Aeson import Data.Monoid import Test.Framework (defaultMain) import Test.Framework.Providers.HUnit (testCase) import Test.HUnit (Assertion, assertEqual, assertFailure)--import qualified Data.HashMap.Strict as H+import qualified Data.HashMap.Strict  as H +import Rest hiding (input) import Rest.Api hiding (route)-import Rest.Dictionary+import Rest.Dictionary (Format (..), Ident (..)) import Rest.Driver.Perform (accept)-import Rest.Driver.RestM (runRestM_) import Rest.Driver.Routing import Rest.Driver.Types-import Rest.Handler import Rest.Resource-import Rest.Schema import qualified Rest.Api          as Rest-import qualified Rest.Driver.RestM as RestM+import qualified Rest.Container    as C+import qualified Rest.Driver.RestM as RM+import qualified Rest.Resource     as Res+import qualified Rest.Run          as Run  main :: IO ()-main = do+main =   defaultMain [ testCase "Top level listing." testListing               , testCase "Top level listing (trailing slash)." testListingTrailingSlash               , testCase "Top level singleton." testToplevelSingleton@@ -44,21 +50,19 @@               , testCase "Multi-PUT." testMultiPut               , testCase "Multi-POST" testMultiPost               , testCase "Accept headers." testAcceptHeaders+              , testCase "Test listing count" testListingCount               ] -testListing :: Assertion-testListing = checkRoute GET "resource" (Rest.root -/ Rest.route resource)+listResource :: Resource IO IO Void () Void+listResource = mkResourceId { name = "resource", schema = Schema (Just (Many ())) (Named []), list = listHandler }   where-    resource :: Resource IO IO Void () Void-    resource = mkResourceId { name = "resource", schema = Schema (Just (Many ())) (Named []), list = listHandler }     listHandler () = mkListing id $ \_ -> return [] +testListing :: Assertion+testListing = checkRoute GET "resource" (Rest.root -/ Rest.route listResource)+ testListingTrailingSlash :: Assertion-testListingTrailingSlash = checkRoute GET "resource/" (Rest.root -/ Rest.route resource)-  where-    resource :: Resource IO IO Void () Void-    resource = mkResourceId { name = "resource", schema = Schema (Just (Many ())) (Named []), list = listHandler }-    listHandler () = mkListing id $ \_ -> return []+testListingTrailingSlash = checkRoute GET "resource/" (Rest.root -/ Rest.route listResource)  testToplevelSingleton :: Assertion testToplevelSingleton = checkSingleRoute "resource" resource handler_@@ -159,7 +163,7 @@     resource = mkResourceReader       { name   = "resource"       , schema = Schema Nothing (Named [("foo", Right (Single (By (Id StringId id))))])-      , update = Just (mkConstHandler xmlJsonO (liftM void ask))+      , update = Just (mkConstHandler xmlJsonO (fmap void ask))       }  testMultiPost :: Assertion@@ -181,7 +185,7 @@  checkRoutes :: (Applicative m, Monad m) => [(Method, Uri)] -> Rest.Router m s -> Assertion checkRoutes reqs router =-  do forM_ reqs $ uncurry $ checkRouteWithIgnoredMethods (map fst reqs) router+  forM_ reqs $ uncurry $ checkRouteWithIgnoredMethods (map fst reqs) router  checkRouteWithIgnoredMethods :: (Applicative m, Monad m) => [Method] -> Rest.Router m s -> Method -> Uri -> Assertion checkRouteWithIgnoredMethods ignoredMethods router method uri =@@ -208,3 +212,31 @@ testAcceptHeaders =   do let fmt = accept (Just "text/json") Nothing Nothing      assertEqual "Accept json format." [JsonFormat] fmt++testListingCount :: Assertion+testListingCount = assertEqual "listing count" (Right $ C.List 0 5 [1..5::Int]) (eitherDecode bs)+  where+    (bs, _meta) = runIdentity . RM.runRestM input $ Run.apiToHandler api+    input :: RM.RestInput+    input = RM.emptyInput+      { RM.parameters = H.fromList [("count", "5")]+      , RM.paths      = splitUriString "resource"+      , RM.headers    = H.fromList+          [ ("Accept"      , "application/json")+          , ("Content-Type", "application/json")+          ]+      }+    api :: Api (RM.RestM Identity)+    api = Unversioned (Some1 $ Rest.root -/ Rest.route resource)+    resource :: Resource (RM.RestM Identity) (RM.RestM Identity) String () Void+    resource = mkResourceId+      { Res.name   = "resource"+      , Res.schema = withListing () $ named []+      , Res.list   = const listHandler+      }+      where+      listHandler :: ListHandler (RM.RestM Identity)+      listHandler = mkListing jsonO h+        where+          h :: Range -> ExceptT Reason_ (RM.RestM Identity) [Int]+          h _rng = return [1..10]