packages feed

request (empty) → 0.1.0.0

raw patch · 5 files changed

+254/−0 lines, 5 filesdep +basedep +bytestringdep +case-insensitivesetup-changed

Dependencies added: base, bytestring, case-insensitive, http-client, http-client-tls, http-types

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright An Long (c) 2021++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Author name here nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,100 @@+# request++![](https://miro.medium.com/max/1200/1*5KglaZoNp4fNpNHUao5u5w.jpeg)++HTTP client for haskell, inpired by [requests](https://requests.readthedocs.io/) and [http-dispatch](https://github.com/owainlewis/http-dispatch).++## Usage++You can try this in haskell REPL once you have `request` installed:++```haskell+import Network.HTTP.Request++resp <- get "https://api.leancloud.cn/1.1/date"+print $ requestStatus resp+```++## Core API++Request's API has three core concepts: `Request` record type, `Response` record type, `send` function.++### Request++`Request` is all about the information you will send to the target URL.++```haskell+data Request = Request+  { requestMethod  :: Method+  , requestUrl     :: String+  , requestHeaders :: Headers+  , requestBody    :: Maybe Data.ByteString.ByteString+  } deriving (Show)+```++### send++Once you have constructed your own `Request` record, you can call the `send` function to send it to the server. The `send` function's type is:++```haskell+send :: Request -> IO Response+```++### Response++`Response` is what you got from the server URL.++```haskell+data Response = Response+  { responseStatus  :: Int+  , responseHeaders :: Headers+  , responseBody    :: Data.ByteString.ByteString+  } deriving (Show)+```++### Example++```haskell+:set -XOverloadedStrings++import Network.HTTP.Request++-- Construct a Request record.+let req = Request GET "https://api.leancloud.cn/1.1/date" [] Nothing+-- Send it.+res <- send req+-- access the fields on Response.+print $ requestStatus resp+```++## Shortcuts++As you expected, there are some shortcuts for the most used scenarios.++```haskell+get :: String -> IO Response+get url =+  send $ Request GET url [] Nothing++delete :: String -> IO Response+delete url =+  send $ Request DELETE url [] Nothing++post :: (String, Maybe Data.ByteString.ByteString) -> IO Response+post (url, body) =+  send $ Request POST url [] body++put :: (String, Maybe Data.ByteString.ByteString) -> IO Response+put (url, body) =+  send $ Request PUT url [] body+```++These shortcuts' definitions are simple and direct. You are encouraged to add your own if the built-in does not match your use cases, like add custom headers in every request.++## About the Project++Request is &copy; 2020-2021 by [aisk](https://github.com/aisk).++### License++Request is distributed by a [BSD license](https://github.com/aisk/request/tree/master/LICENSE).
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ request.cabal view
@@ -0,0 +1,29 @@+name:                request+version:             0.1.0.0+-- synopsis:+description:         "HTTP client for haskell, inpired by requests and http-dispatch."+homepage:            https://github.com/aisk/request#readme+license:             BSD3+license-file:        LICENSE+author:              An Long+maintainer:          aisk1988@gmail.com+copyright:           2020 An Long+category:            Web+build-type:          Simple+extra-source-files:  README.md+cabal-version:       >=1.10++library+  hs-source-dirs:      src+  exposed-modules:     Network.HTTP.Request+  build-depends:       base               >= 4.7 && < 5+                     , bytestring         >= 0.10.12 && < 0.11+                     , case-insensitive   >= 1.2.1 && < 1.3+                     , http-client        >= 0.7.7 && < 0.8+                     , http-types         >= 0.12.3 && < 0.13+                     , http-client-tls    >= 0.3.5 && < 0.4+  default-language:    Haskell2010++source-repository head+  type:     git+  location: https://github.com/aisk/request
+ src/Network/HTTP/Request.hs view
@@ -0,0 +1,93 @@+{-# LANGUAGE DatatypeContexts #-}+{-# LANGUAGE OverloadedStrings #-}++module Network.HTTP.Request+  ( Request+  , Response+  , Header+  , Headers+  ) where++import qualified Data.String               as S+import qualified Data.ByteString           as BS+import qualified Data.ByteString.Char8     as C+import qualified Data.ByteString.Lazy      as LBS+import qualified Data.CaseInsensitive      as CI+import qualified Data.List                 as List+import qualified Network.HTTP.Client       as LowLevelClient+import qualified Network.HTTP.Client.TLS   as LowLevelTLSClient+import qualified Network.HTTP.Types.Status as LowLevelStatus++type Header = (BS.ByteString, BS.ByteString)++type Headers = [Header]++data Method+  = DELETE+  | GET+  | HEAD+  | OPTIONS+  | PATCH+  | POST+  | PUT+  | TRACE+  deriving (Eq, Show)++data (S.IsString a) => Request a = Request+  { requestMethod  :: Method+  , requestUrl     :: String+  , requestHeaders :: Headers+  , requestBody    :: Maybe a+  } deriving (Show)++toLowlevelRequest :: (S.IsString a) => Request a -> IO LowLevelClient.Request+toLowlevelRequest req = do+  initReq <- LowLevelClient.parseRequest $ requestUrl req+  return $ initReq { LowLevelClient.method = C.pack . show $ requestMethod req+                   , LowLevelClient.requestHeaders = map (\(k, v) -> (CI.mk k, v)) $ requestHeaders req+                   }++data Response = Response+  { responseStatus  :: Int+  , responseHeaders :: Headers+  , responseBody    :: BS.ByteString+  } deriving (Show)++fromLowLevelRequest :: LowLevelClient.Response LBS.ByteString -> Response+fromLowLevelRequest res =+  let status = LowLevelStatus.statusCode . LowLevelClient.responseStatus $ res+      body = LBS.toStrict $ LowLevelClient.responseBody res+      headers = LowLevelClient.responseHeaders res+  in+  Response status (map (\(k,v) ->+                         let hk = CI.original k+                         in+                         (hk, v)) headers) body++getManagerForUrl :: String -> IO LowLevelClient.Manager+getManagerForUrl url =+    if "https" `List.isPrefixOf` url then LowLevelClient.newManager LowLevelTLSClient.tlsManagerSettings+                                     else LowLevelClient.newManager LowLevelClient.defaultManagerSettings++send :: (S.IsString a) => Request a -> IO Response+send req = do+  manager <- getManagerForUrl $ requestUrl req+  llreq <- toLowlevelRequest req+  llres <- LowLevelClient.httpLbs llreq manager+  return $ fromLowLevelRequest llres++get :: String -> IO Response+get url =+  send $ Request GET url [] Nothing++delete :: String -> IO Response+delete url =+  send $ Request DELETE url [] Nothing++post :: (String, Maybe BS.ByteString) -> IO Response+post (url, body) =+  send $ Request POST url [] body++put :: (String, Maybe BS.ByteString) -> IO Response+put (url, body) =+  send $ Request PUT url [] body