api-builder 0.5.0.0 → 0.6.0.0
raw patch · 8 files changed
+111/−10 lines, 8 filesdep +Cabaldep +api-builderdep +containersdep ~aesondep ~basedep ~bifunctors
Dependencies added: Cabal, api-builder, containers, datetime, hspec, http-client
Dependency ranges changed: aeson, base, bifunctors, bytestring, http-conduit, text, transformers
Files
- api-builder.cabal +56/−3
- src/Network/API/Builder/Examples/StackOverflow.hs +1/−1
- src/Network/API/Builder/Query.hs +10/−0
- src/Network/API/Builder/Receive.hs +13/−0
- src/Network/API/Builder/Routes.hs +10/−6
- src/Network/API/Builder/Send/Multipart.hs +19/−0
- test-io/Spec.hs +1/−0
- test/Spec.hs +1/−0
api-builder.cabal view
@@ -1,14 +1,24 @@ name: api-builder-version: 0.5.0.0+version: 0.6.0.0 synopsis: Library for easily building REST API wrappers in Haskell license: BSD3 author: Fraser Murray maintainer: fraser.m.murray@gmail.com+homepage: https://github.com/intolerable/api-builder copyright: (c) Fraser Murray 2014 category: Network build-type: Simple cabal-version: >= 1.10 +source-repository head+ type: git+ location: git://github.com/intolerable/api-builder.git++source-repository this+ type: git+ location: git://github.com/intolerable/api-builder.git+ tag: v0.6.0.0+ library exposed-modules: Network.API.Builder@@ -20,16 +30,18 @@ Network.API.Builder.Receive Network.API.Builder.Routes Network.API.Builder.Send+ Network.API.Builder.Send.Multipart build-depends: base >= 4.6 && < 4.8, aeson >= 0.7 && < 0.9, attoparsec >= 0.11 && < 0.13,- bifunctors,+ bifunctors == 4.*, bytestring == 0.10.*, either == 4.*, HTTP == 4000.*,- http-types == 0.8.*,+ http-client >= 0.4.7 && < 0.4.10, http-conduit == 2.*,+ http-types == 0.8.*, text == 1.*, transformers >= 0.3 && < 0.5 hs-source-dirs: src/@@ -38,3 +50,44 @@ FlexibleInstances OverloadedStrings ghc-options: -Wall++test-suite test+ hs-source-dirs: test+ main-is: Spec.hs+ default-extensions:+ OverloadedStrings+ ScopedTypeVariables+ default-language: Haskell2010+ type: exitcode-stdio-1.0+ build-depends:+ base == 4.*,+ Cabal >= 1.16.0,+ api-builder,+ aeson,+ bytestring,+ datetime,+ hspec,+ http-conduit,+ text,+ transformers+ GHC-options: -Wall -Werror++test-suite test-io+ hs-source-dirs: test-io+ main-is: Spec.hs+ default-extensions:+ LambdaCase+ default-language: Haskell2010+ type: exitcode-stdio-1.0+ build-depends:+ base == 4.*,+ Cabal >= 1.16.0,+ api-builder,+ aeson,+ bytestring,+ containers,+ datetime,+ hspec,+ text,+ transformers+ GHC-options: -Wall -Werror
src/Network/API/Builder/Examples/StackOverflow.hs view
@@ -36,7 +36,7 @@ stackOverflow = basicBuilder "StackOverflow API" "http://api.stackexchange.com" answersRoute :: Route-answersRoute = Route { fragments = [ "2.2", "questions" ]+answersRoute = Route { urlPieces = [ "2.2", "questions" ] , urlParams = [ "order" =. ("desc" :: Text) , "sort" =. ("activity" :: Text) , "site" =. ("stackoverflow" :: Text) ]
src/Network/API/Builder/Query.hs view
@@ -1,5 +1,6 @@ module Network.API.Builder.Query where +import Data.Monoid import Data.Text (Text) import qualified Data.Text as Text @@ -26,3 +27,12 @@ instance ToQuery a => ToQuery [a] where toQuery _ [] = [] toQuery k xs = [(k, Text.intercalate "," $ map snd $ concatMap (toQuery k) xs)]++newtype IndexedList a = IndexedList [a]+ deriving (Show, Read, Eq)++instance ToQuery a => ToQuery (IndexedList a) where+ toQuery _ (IndexedList []) = []+ toQuery k (IndexedList l) =+ zipWith (\n (x, y) -> (x <> "[" <> tshow n <> "]", y)) ([0..] :: [Integer]) $ concatMap (toQuery k) l+ where tshow = Text.pack . show
src/Network/API/Builder/Receive.hs view
@@ -2,6 +2,7 @@ import Network.API.Builder.Error +import Control.Applicative import Data.Aeson hiding (decode, eitherDecode) import Data.Aeson.Parser import Data.Aeson.Types (parseEither)@@ -20,6 +21,18 @@ instance Receivable Value where receive = useFromJSON++instance (Receivable a, Receivable b) => Receivable (a, b) where+ receive x = (,) <$> receive x <*> receive x++instance (Receivable a, Receivable b, Receivable c) => Receivable (a, b, c) where+ receive x = (,,) <$> receive x <*> receive x <*> receive x++instance (Receivable a, Receivable b, Receivable c, Receivable d) => Receivable (a, b, c, d) where+ receive x = (,,,) <$> receive x <*> receive x <*> receive x <*> receive x++instance (Receivable a, Receivable b, Receivable c, Receivable d, Receivable e) => Receivable (a, b, c, d, e) where+ receive x = (,,,,) <$> receive x <*> receive x <*> receive x <*> receive x <*> receive x useFromJSON :: (FromJSON a, ErrorReceivable e) => Response ByteString -> Either (APIError e) a useFromJSON resp =
src/Network/API/Builder/Routes.hs view
@@ -1,6 +1,6 @@ module Network.API.Builder.Routes ( Route(..)- , URLFragment+ , URLPiece , URLParam , (=.) , routeURL ) where@@ -15,7 +15,7 @@ import Network.API.Builder.Query -- | Alias for @Text@ to store the URL fragments for each @Route@.-type URLFragment = Text+type URLPiece = Text -- | Alias to @(Text, Maybe Text)@ used to store each query that gets -- tacked onto the request.@@ -34,7 +34,7 @@ -- | Main type for routes in the API. Used to represent the URL minus the actual -- endpoint URL as well as the query string and the HTTP method used to communicate -- with the server.-data Route = Route { fragments :: [URLFragment]+data Route = Route { urlPieces :: [URLPiece] , urlParams :: [URLParam] , httpMethod :: HTTP.Method } deriving (Show, Read, Eq)@@ -45,10 +45,14 @@ -> Route -- ^ the @Route@ to process -> Text -- ^ the finalized URL as a @Text@ routeURL baseURL (Route fs ps _) =- let path = T.intercalate "/" fs- in baseURL <> "/" <> path <> pathParamsSep fs <> buildParams ps+ baseURL <> firstSep <> path <> querySep <> buildParams ps+ where+ firstSep = if null fs then T.empty else "/"+ path = T.intercalate "/" fs+ querySep = if null ps then T.empty else pathParamsSep fs -pathParamsSep :: [URLFragment] -> Text++pathParamsSep :: [URLPiece] -> Text pathParamsSep [] = "?" pathParamsSep xs = if T.isInfixOf "." (last xs) then "?" else "/?"
+ src/Network/API/Builder/Send/Multipart.hs view
@@ -0,0 +1,19 @@+module Network.API.Builder.Send.Multipart where++import Network.API.Builder.Builder+import Network.API.Builder.Routes+import Network.API.Builder.Send++import Control.Monad+import Control.Monad.IO.Class+import Network.HTTP.Client.MultipartFormData+import Network.HTTP.Conduit (Request)++data Multipart = Multipart [Part]+ deriving (Show)++sendMultipart :: MonadIO m => Builder -> Route -> Multipart -> m (Maybe Request)+sendMultipart b r (Multipart ps) = do+ case send b r () of+ Nothing -> return Nothing+ Just req -> liftM Just $ formDataBody ps req
+ test-io/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
+ test/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}