Skip to content

Commit

Permalink
Provide Amazonka.Send.{sendUnsigned,sendUnsignedEither}
Browse files Browse the repository at this point in the history
And re-export sending functions from `Amazonka`.
  • Loading branch information
endgame committed Apr 28, 2022
1 parent 88413a3 commit c554fd6
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 107 deletions.
1 change: 1 addition & 0 deletions lib/amazonka-core/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ haskell_library(
"@stackage//:case-insensitive",
"@stackage//:conduit",
"@stackage//:conduit-extra",
"@stackage//:containers",
"@stackage//:cryptonite",
"@stackage//:deepseq",
"@stackage//:hashable",
Expand Down
4 changes: 4 additions & 0 deletions lib/amazonka/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ haskell_library(
"src/Amazonka/Auth/Exception.hs",
"src/Amazonka/Auth/InstanceProfile.hs",
"src/Amazonka/Auth/Keys.hs",
"src/Amazonka/Auth/SSO.hs",
"src/Amazonka/Auth/STS.hs",
"src/Amazonka/EC2/Metadata.hs",
"src/Amazonka/Env.hs",
"src/Amazonka/HTTP.hs",
"src/Amazonka/Logger.hs",
"src/Amazonka/Presign.hs",
"src/Amazonka/Send.hs",
],
compiler_flags = [
"-XNoImplicitPrelude",
Expand Down Expand Up @@ -84,7 +86,9 @@ haskell_library(
visibility = ["//visibility:public"],
deps = [
"//lib/amazonka-core",
"//lib/services/amazonka-sso",
"//lib/services/amazonka-sts",
"@stackage//:aeson",
"@stackage//:base",
"@stackage//:bytestring",
"@stackage//:conduit",
Expand Down
2 changes: 2 additions & 0 deletions lib/amazonka/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ Released: **?**, Compare: [2.0.0-rc1](https://github.com/brendanhay/amazonka/com

### Changed

- `amazonka`: Add a public interface to send unsigned requests. Sending functions are now defined in `Amazonka.Send`, but are re-exported from `Amazonka`.
[\#769](https://github.com/brendanhay/amazonka/pull/769)
- `amazonka-dynamodb`: Mark various fields as required
[\#724](https://github.com/brendanhay/amazonka/pull/724)
- `amazonka-dynamodb`: Provide a sum type for `AttributeValue`
Expand Down
1 change: 1 addition & 0 deletions lib/amazonka/amazonka.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ library
Amazonka.HTTP
Amazonka.Logger
Amazonka.Presign
Amazonka.Send

reexported-modules:
Amazonka.Data, Amazonka.Types, Amazonka.Bytes, Amazonka.Endpoint, Amazonka.Crypto
Expand Down
121 changes: 14 additions & 107 deletions lib/amazonka/src/Amazonka.hs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ module Amazonka
await,
awaitEither,

-- ** Unsigned
sendUnsigned,
sendUnsignedEither,

-- ** Streaming
-- $streaming
ToBody (..),
Expand Down Expand Up @@ -142,20 +146,23 @@ import qualified Amazonka.EC2.Metadata as EC2
import qualified Amazonka.Endpoint as Endpoint
import qualified Amazonka.Env as Env
import qualified Amazonka.Error as Error
import qualified Amazonka.HTTP as HTTP
import qualified Amazonka.Lens as Lens
import Amazonka.Logger
import qualified Amazonka.Pager as Pager
import Amazonka.Prelude
import qualified Amazonka.Presign as Presign
import Amazonka.Request (clientRequestURL)
import qualified Amazonka.Waiter as Waiter
import qualified Control.Exception as Exception
import Amazonka.Send
( await,
awaitEither,
paginate,
paginateEither,
send,
sendEither,
sendUnsigned,
sendUnsignedEither,
)
import Control.Monad.Trans.Resource (runResourceT)
import Data.Conduit (ConduitM)
import qualified Data.Conduit as Conduit
import Data.Monoid (Dual (..), Endo (..))
import qualified Network.HTTP.Client as Client

-- $usage
-- The key functions dealing with the request/response lifecycle are:
Expand Down Expand Up @@ -400,106 +407,6 @@ import qualified Network.HTTP.Client as Client
-- <http://hackage.haskell.org/package/tinylog tinylog> or
-- <http://hackage.haskell.org/package/fast-logger fast-logger>.

-- | Send a request, returning the associated response if successful.
--
-- See 'send'.
sendEither ::
( MonadResource m,
AWSRequest a
) =>
Env ->
a ->
m (Either Error (AWSResponse a))
sendEither env =
fmap (second Client.responseBody) . HTTP.retryRequest env

-- | Send a request, returning the associated response if successful.
--
-- Errors are thrown in 'IO'.
--
-- See 'sendEither'.
send ::
( MonadResource m,
AWSRequest a
) =>
Env ->
a ->
m (AWSResponse a)
send env =
sendEither env >=> hoistEither

-- | Repeatedly send a request, automatically setting markers and performing pagination.
--
-- Exits on the first encountered error.
--
-- See 'paginate'.
paginateEither ::
( MonadResource m,
AWSPager a
) =>
Env ->
a ->
ConduitM () (AWSResponse a) m (Either Error ())
paginateEither env = go
where
go rq =
lift (sendEither env rq) >>= \case
Left err -> pure (Left err)
Right rs -> do
Conduit.yield rs
maybe (pure (Right ())) go (Pager.page rq rs)

-- | Repeatedly send a request, automatically setting markers and performing pagination.
-- Exits on the first encountered error.
--
-- Errors are thrown in 'IO'.
--
-- See 'paginateEither'.
paginate ::
( MonadResource m,
AWSPager a
) =>
Env ->
a ->
ConduitM () (AWSResponse a) m ()
paginate env =
paginateEither env >=> hoistEither

-- | Poll the API with the supplied request until a specific 'Wait' condition
-- is fulfilled.
--
-- See 'await'.
awaitEither ::
( MonadResource m,
AWSRequest a
) =>
Env ->
Waiter.Wait a ->
a ->
m (Either Error Waiter.Accept)
awaitEither env wait =
HTTP.awaitRequest env wait

-- | Poll the API with the supplied request until a specific 'Wait' condition
-- is fulfilled.
--
-- Errors are thrown in 'IO'.
--
-- See 'awaitEither'.
await ::
( MonadResource m,
AWSRequest a
) =>
Env ->
Waiter.Wait a ->
a ->
m Waiter.Accept
await env wait =
awaitEither env wait >=> hoistEither

hoistEither :: MonadIO m => Either Error a -> m a
hoistEither = either (liftIO . Exception.throwIO) pure

-- | Presign an URL that is valid from the specified time until the
-- number of seconds expiry has elapsed.
presignURL ::
Expand Down
156 changes: 156 additions & 0 deletions lib/amazonka/src/Amazonka/Send.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
module Amazonka.Send
( send,
sendEither,
paginate,
paginateEither,
await,
awaitEither,
sendUnsigned,
sendUnsignedEither,
)
where

import Amazonka.Core (AWSPager, AWSRequest, AWSResponse, Error)
import Amazonka.Env (Env, Env' (..))
import qualified Amazonka.HTTP as HTTP
import qualified Amazonka.Pager as Pager
import Amazonka.Prelude
import qualified Amazonka.Waiter as Waiter
import qualified Control.Exception as Exception
import Data.Conduit (ConduitM)
import qualified Data.Conduit as Conduit
import qualified Network.HTTP.Client as Client

-- | Send a request, returning the associated response if successful.
--
-- See 'send'.
sendEither ::
( MonadResource m,
AWSRequest a
) =>
Env ->
a ->
m (Either Error (AWSResponse a))
sendEither env =
fmap (second Client.responseBody) . HTTP.retryRequest env

-- | Send a request, returning the associated response if successful.
--
-- Errors are thrown in 'IO'.
--
-- See 'sendEither'.
send ::
( MonadResource m,
AWSRequest a
) =>
Env ->
a ->
m (AWSResponse a)
send env =
sendEither env >=> hoistEither

-- | Make a request without signing it. You will almost never need to
-- do this, but some authentication methods
-- (e.g. @sts:AssumeRoleWithWebIdentity@ and @sso:GetRoleCredentials@)
-- require you to exchange a token using an unsigned
-- request. Amazonka's support for these authentication methods calls
-- 'sendUnsigned', and we re-export these functions in case you need
-- to support similar authentication methods in your code.
--
-- See 'sendUnsigned'.
sendUnsignedEither ::
( MonadResource m,
AWSRequest a
) =>
Env' withAuth ->
a ->
m (Either Error (AWSResponse a))
sendUnsignedEither env =
fmap (second Client.responseBody) . HTTP.retryRequest (env {envAuth = Proxy})

-- | Make an unsigned request, returning the associated response if successful.
--
-- Errors are thrown in 'IO'.
--
-- See 'sendUnsignedEither'.
sendUnsigned ::
( MonadResource m,
AWSRequest a
) =>
Env' withAuth ->
a ->
m (AWSResponse a)
sendUnsigned env =
sendUnsignedEither env >=> hoistEither

-- | Repeatedly send a request, automatically setting markers and performing pagination.
--
-- Exits on the first encountered error.
--
-- See 'paginate'.
paginateEither ::
( MonadResource m,
AWSPager a
) =>
Env ->
a ->
ConduitM () (AWSResponse a) m (Either Error ())
paginateEither env = go
where
go rq =
lift (sendEither env rq) >>= \case
Left err -> pure (Left err)
Right rs -> do
Conduit.yield rs
maybe (pure (Right ())) go (Pager.page rq rs)

-- | Repeatedly send a request, automatically setting markers and performing pagination.
-- Exits on the first encountered error.
--
-- Errors are thrown in 'IO'.
--
-- See 'paginateEither'.
paginate ::
( MonadResource m,
AWSPager a
) =>
Env ->
a ->
ConduitM () (AWSResponse a) m ()
paginate env =
paginateEither env >=> hoistEither

-- | Poll the API with the supplied request until a specific 'Wait' condition
-- is fulfilled.
--
-- See 'await'.
awaitEither ::
( MonadResource m,
AWSRequest a
) =>
Env ->
Waiter.Wait a ->
a ->
m (Either Error Waiter.Accept)
awaitEither env wait =
HTTP.awaitRequest env wait

-- | Poll the API with the supplied request until a specific 'Wait' condition
-- is fulfilled.
--
-- Errors are thrown in 'IO'.
--
-- See 'awaitEither'.
await ::
( MonadResource m,
AWSRequest a
) =>
Env ->
Waiter.Wait a ->
a ->
m Waiter.Accept
await env wait =
awaitEither env wait >=> hoistEither

hoistEither :: MonadIO m => Either Error a -> m a
hoistEither = either (liftIO . Exception.throwIO) pure

0 comments on commit c554fd6

Please sign in to comment.