From f13ea2ade18c8d79664a18ef15acad28ced3a013 Mon Sep 17 00:00:00 2001 From: kokobd Date: Fri, 10 Nov 2023 14:55:06 +0000 Subject: [PATCH 1/7] fix error handling in pure runtimes --- src/AWS/Lambda/Combinators.hs | 10 +++++++--- src/AWS/Lambda/Context.hs | 7 ++++--- src/AWS/Lambda/Runtime.hs | 15 +++++++++------ src/AWS/Lambda/Runtime/Value.hs | 11 ++++++----- 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/AWS/Lambda/Combinators.hs b/src/AWS/Lambda/Combinators.hs index c8e69ce..3d94e7d 100644 --- a/src/AWS/Lambda/Combinators.hs +++ b/src/AWS/Lambda/Combinators.hs @@ -13,11 +13,12 @@ They map functions (instead of values) to turn basic handlers into handlers comp module AWS.Lambda.Combinators ( withoutContext, - withInfallibleParse + withInfallibleParse, + withInfallibleParseEither ) where -import Data.Aeson (FromJSON, parseJSON, Value) -import Data.Aeson.Types (parseEither) +import Data.Aeson (FromJSON, Value, parseJSON) +import Data.Aeson.Types (parseEither) -- | An alias of 'const', this upgrades a handler that does not accept -- 'AWS.Lambda.Context.LambdaContext' as its first curried argument to one that does. @@ -70,3 +71,6 @@ withoutContext = const -- on a failure to convert the JSON AST sent to the Lambda. withInfallibleParse :: FromJSON a => (a -> b) -> Value -> b withInfallibleParse fn = either error fn . parseEither parseJSON + +withInfallibleParseEither :: FromJSON a => (a -> b) -> Value -> Either String b +withInfallibleParseEither fn = fmap fn . parseEither parseJSON diff --git a/src/AWS/Lambda/Context.hs b/src/AWS/Lambda/Context.hs index abcc97f..5ee8918 100644 --- a/src/AWS/Lambda/Context.hs +++ b/src/AWS/Lambda/Context.hs @@ -1,4 +1,5 @@ -{-# LANGUAGE NamedFieldPuns, OverloadedStrings #-} +{-# LANGUAGE NamedFieldPuns #-} + {-| Module : AWS.Lambda.Context @@ -21,8 +22,8 @@ import Control.Monad.IO.Class (MonadIO, liftIO) import Data.Aeson (FromJSON, ToJSON) import Data.Map (Map) import Data.Text (Text) -import Data.Time.Clock (DiffTime, UTCTime, - diffUTCTime, getCurrentTime) +import Data.Time.Clock (DiffTime, UTCTime, diffUTCTime, + getCurrentTime) import GHC.Generics (Generic) data ClientApplication = ClientApplication diff --git a/src/AWS/Lambda/Runtime.hs b/src/AWS/Lambda/Runtime.hs index 32e38b7..ed63bf6 100644 --- a/src/AWS/Lambda/Runtime.hs +++ b/src/AWS/Lambda/Runtime.hs @@ -29,9 +29,12 @@ module AWS.Lambda.Runtime ( mRuntimeWithContext ) where -import AWS.Lambda.Combinators (withInfallibleParse) -import AWS.Lambda.Context (LambdaContext(..)) +import AWS.Lambda.Combinators (withInfallibleParse, + withInfallibleParseEither, + withoutContext) +import AWS.Lambda.Context (LambdaContext (..)) import qualified AWS.Lambda.Runtime.Value as ValueRuntime +import Control.Monad (join) import Control.Monad.Catch (MonadCatch) import Control.Monad.IO.Class (MonadIO) import Control.Monad.Reader (ReaderT) @@ -253,7 +256,7 @@ ioRuntime = ValueRuntime.ioRuntime . withInfallibleParse -- @ fallibleRuntimeWithContext :: (FromJSON event, ToJSON result) => (LambdaContext -> event -> Either String result) -> IO () -fallibleRuntimeWithContext = ValueRuntime.fallibleRuntimeWithContext . fmap withInfallibleParse +fallibleRuntimeWithContext fn = ValueRuntime.fallibleRuntimeWithContext $ \lc -> join . withInfallibleParseEither (fn lc) -- | For pure functions that can still fail. -- @@ -286,7 +289,7 @@ fallibleRuntimeWithContext = ValueRuntime.fallibleRuntimeWithContext . fmap with -- @ fallibleRuntime :: (FromJSON event, ToJSON result) => (event -> Either String result) -> IO () -fallibleRuntime = ValueRuntime.fallibleRuntime . withInfallibleParse +fallibleRuntime = fallibleRuntimeWithContext . withoutContext -- | For pure functions that can never fail that also need access to the context. -- @@ -318,7 +321,7 @@ fallibleRuntime = ValueRuntime.fallibleRuntime . withInfallibleParse -- @ pureRuntimeWithContext :: (FromJSON event, ToJSON result) => (LambdaContext -> event -> result) -> IO () -pureRuntimeWithContext = ValueRuntime.pureRuntimeWithContext . fmap withInfallibleParse +pureRuntimeWithContext fn = ValueRuntime.fallibleRuntimeWithContext $ withInfallibleParseEither . fn -- | For pure functions that can never fail. -- @@ -345,4 +348,4 @@ pureRuntimeWithContext = ValueRuntime.pureRuntimeWithContext . fmap withInfallib -- main = pureRuntime myHandler -- @ pureRuntime :: (FromJSON event, ToJSON result) => (event -> result) -> IO () -pureRuntime = ValueRuntime.pureRuntime . withInfallibleParse +pureRuntime = pureRuntimeWithContext . withoutContext diff --git a/src/AWS/Lambda/Runtime/Value.hs b/src/AWS/Lambda/Runtime/Value.hs index 16778ef..d046838 100644 --- a/src/AWS/Lambda/Runtime/Value.hs +++ b/src/AWS/Lambda/Runtime/Value.hs @@ -39,12 +39,13 @@ module AWS.Lambda.Runtime.Value ( mRuntimeWithContext, ) where -import AWS.Lambda.RuntimeClient (RuntimeClientConfig, getRuntimeClientConfig, - getNextData, sendEventError, sendEventSuccess) import AWS.Lambda.Combinators (withoutContext) -import AWS.Lambda.Context (LambdaContext(..)) +import AWS.Lambda.Context (LambdaContext (..)) +import AWS.Lambda.RuntimeClient (RuntimeClientConfig, getNextData, + getRuntimeClientConfig, + sendEventError, sendEventSuccess) import Control.Exception (SomeException, displayException) -import Control.Monad ((<=<), forever) +import Control.Monad (forever, (<=<)) import Control.Monad.Catch (MonadCatch, try) import Control.Monad.IO.Class (MonadIO, liftIO) import Control.Monad.Reader (ReaderT, runReaderT) @@ -331,7 +332,7 @@ ioRuntime = ioRuntimeWithContext . withoutContext -- @ fallibleRuntimeWithContext :: ToJSON result => (LambdaContext -> Value -> Either String result) -> IO () -fallibleRuntimeWithContext = mRuntimeWithContext . fmap (fmap pure) +fallibleRuntimeWithContext fn = mRuntimeWithContext (\lc -> either error pure . fn lc) -- | For pure functions that can still fail. -- From 15b1e70290d494bf8e245962e019e845eafc353a Mon Sep 17 00:00:00 2001 From: kokobd Date: Mon, 13 Nov 2023 14:32:29 +0000 Subject: [PATCH 2/7] rename withInfallibleParseEither --- src/AWS/Lambda/Combinators.hs | 7 ++++--- src/AWS/Lambda/Runtime.hs | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/AWS/Lambda/Combinators.hs b/src/AWS/Lambda/Combinators.hs index 3d94e7d..17feb02 100644 --- a/src/AWS/Lambda/Combinators.hs +++ b/src/AWS/Lambda/Combinators.hs @@ -14,7 +14,7 @@ They map functions (instead of values) to turn basic handlers into handlers comp module AWS.Lambda.Combinators ( withoutContext, withInfallibleParse, - withInfallibleParseEither + withFallibleParse ) where import Data.Aeson (FromJSON, Value, parseJSON) @@ -72,5 +72,6 @@ withoutContext = const withInfallibleParse :: FromJSON a => (a -> b) -> Value -> b withInfallibleParse fn = either error fn . parseEither parseJSON -withInfallibleParseEither :: FromJSON a => (a -> b) -> Value -> Either String b -withInfallibleParseEither fn = fmap fn . parseEither parseJSON +-- | Like 'withInfallibleParse', but return the result in an 'Either' instead of using 'error'. +withFallibleParse :: FromJSON a => (a -> b) -> Value -> Either String b +withFallibleParse fn = fmap fn . parseEither parseJSON diff --git a/src/AWS/Lambda/Runtime.hs b/src/AWS/Lambda/Runtime.hs index ed63bf6..e1ea77f 100644 --- a/src/AWS/Lambda/Runtime.hs +++ b/src/AWS/Lambda/Runtime.hs @@ -30,7 +30,7 @@ module AWS.Lambda.Runtime ( ) where import AWS.Lambda.Combinators (withInfallibleParse, - withInfallibleParseEither, + withFallibleParse, withoutContext) import AWS.Lambda.Context (LambdaContext (..)) import qualified AWS.Lambda.Runtime.Value as ValueRuntime @@ -256,7 +256,7 @@ ioRuntime = ValueRuntime.ioRuntime . withInfallibleParse -- @ fallibleRuntimeWithContext :: (FromJSON event, ToJSON result) => (LambdaContext -> event -> Either String result) -> IO () -fallibleRuntimeWithContext fn = ValueRuntime.fallibleRuntimeWithContext $ \lc -> join . withInfallibleParseEither (fn lc) +fallibleRuntimeWithContext fn = ValueRuntime.fallibleRuntimeWithContext $ \lc -> join . withFallibleParse (fn lc) -- | For pure functions that can still fail. -- @@ -321,7 +321,7 @@ fallibleRuntime = fallibleRuntimeWithContext . withoutContext -- @ pureRuntimeWithContext :: (FromJSON event, ToJSON result) => (LambdaContext -> event -> result) -> IO () -pureRuntimeWithContext fn = ValueRuntime.fallibleRuntimeWithContext $ withInfallibleParseEither . fn +pureRuntimeWithContext fn = ValueRuntime.fallibleRuntimeWithContext $ withFallibleParse . fn -- | For pure functions that can never fail. -- From 8ac1e244fef5f120d341f95ab039f25fcec72dc5 Mon Sep 17 00:00:00 2001 From: kokobd Date: Thu, 23 Nov 2023 20:19:10 -0500 Subject: [PATCH 3/7] revert unnecessary changes --- src/AWS/Lambda/Combinators.hs | 4 ++-- src/AWS/Lambda/Context.hs | 7 +++---- src/AWS/Lambda/Runtime.hs | 2 +- src/AWS/Lambda/Runtime/Value.hs | 4 ++-- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/AWS/Lambda/Combinators.hs b/src/AWS/Lambda/Combinators.hs index 17feb02..735e268 100644 --- a/src/AWS/Lambda/Combinators.hs +++ b/src/AWS/Lambda/Combinators.hs @@ -17,8 +17,8 @@ module AWS.Lambda.Combinators ( withFallibleParse ) where -import Data.Aeson (FromJSON, Value, parseJSON) -import Data.Aeson.Types (parseEither) +import Data.Aeson (FromJSON, parseJSON, Value) +import Data.Aeson.Types (parseEither) -- | An alias of 'const', this upgrades a handler that does not accept -- 'AWS.Lambda.Context.LambdaContext' as its first curried argument to one that does. diff --git a/src/AWS/Lambda/Context.hs b/src/AWS/Lambda/Context.hs index 5ee8918..c5f8f63 100644 --- a/src/AWS/Lambda/Context.hs +++ b/src/AWS/Lambda/Context.hs @@ -1,5 +1,4 @@ -{-# LANGUAGE NamedFieldPuns #-} - +{-# LANGUAGE NamedFieldPuns #-} {-| Module : AWS.Lambda.Context @@ -22,8 +21,8 @@ import Control.Monad.IO.Class (MonadIO, liftIO) import Data.Aeson (FromJSON, ToJSON) import Data.Map (Map) import Data.Text (Text) -import Data.Time.Clock (DiffTime, UTCTime, diffUTCTime, - getCurrentTime) +import Data.Time.Clock (DiffTime, UTCTime, + diffUTCTime, getCurrentTime) import GHC.Generics (Generic) data ClientApplication = ClientApplication diff --git a/src/AWS/Lambda/Runtime.hs b/src/AWS/Lambda/Runtime.hs index e1ea77f..fde6f63 100644 --- a/src/AWS/Lambda/Runtime.hs +++ b/src/AWS/Lambda/Runtime.hs @@ -32,7 +32,7 @@ module AWS.Lambda.Runtime ( import AWS.Lambda.Combinators (withInfallibleParse, withFallibleParse, withoutContext) -import AWS.Lambda.Context (LambdaContext (..)) +import AWS.Lambda.Context (LambdaContext(..)) import qualified AWS.Lambda.Runtime.Value as ValueRuntime import Control.Monad (join) import Control.Monad.Catch (MonadCatch) diff --git a/src/AWS/Lambda/Runtime/Value.hs b/src/AWS/Lambda/Runtime/Value.hs index d046838..db6343c 100644 --- a/src/AWS/Lambda/Runtime/Value.hs +++ b/src/AWS/Lambda/Runtime/Value.hs @@ -40,12 +40,12 @@ module AWS.Lambda.Runtime.Value ( ) where import AWS.Lambda.Combinators (withoutContext) -import AWS.Lambda.Context (LambdaContext (..)) +import AWS.Lambda.Context (LambdaContext(..)) import AWS.Lambda.RuntimeClient (RuntimeClientConfig, getNextData, getRuntimeClientConfig, sendEventError, sendEventSuccess) import Control.Exception (SomeException, displayException) -import Control.Monad (forever, (<=<)) +import Control.Monad ((<=<), forever) import Control.Monad.Catch (MonadCatch, try) import Control.Monad.IO.Class (MonadIO, liftIO) import Control.Monad.Reader (ReaderT, runReaderT) From 2d57afa52a7e77ecadb8e64722d89d8653011628 Mon Sep 17 00:00:00 2001 From: kokobd Date: Thu, 23 Nov 2023 20:26:10 -0500 Subject: [PATCH 4/7] add changelog entry --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60b1915..4cf18b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,9 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog][chg] and this project adheres to [Haskell's Package Versioning Policy][pvp] -## unreleased - 2023-07-06 +## unreleased - 2023-11-23 - Add support for aeson 2.2 + - `fallibleRuntime` and `fallibleRuntimeWithContext` reports errors to AWS + instead of returning `{"Left": "some error"}`. + - `pureRuntime`, `pureRuntimeWithContext`, `fallibleRuntime` and `fallibleRuntimeWithContext` + no longer crash the Lambda runtime if input can't be parsed from JSON. ## `1.0.0.1` - 2022-09-10 From 4a03ab134a341587c31fe2c8e511f5c9c3216628 Mon Sep 17 00:00:00 2001 From: kokobd Date: Mon, 18 Dec 2023 18:35:14 -0500 Subject: [PATCH 5/7] simplify pureRuntimeWithContext impl --- src/AWS/Lambda/Runtime.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AWS/Lambda/Runtime.hs b/src/AWS/Lambda/Runtime.hs index fde6f63..8eed552 100644 --- a/src/AWS/Lambda/Runtime.hs +++ b/src/AWS/Lambda/Runtime.hs @@ -321,7 +321,7 @@ fallibleRuntime = fallibleRuntimeWithContext . withoutContext -- @ pureRuntimeWithContext :: (FromJSON event, ToJSON result) => (LambdaContext -> event -> result) -> IO () -pureRuntimeWithContext fn = ValueRuntime.fallibleRuntimeWithContext $ withFallibleParse . fn +pureRuntimeWithContext = fallibleRuntimeWithContext . fmap (fmap pure) -- | For pure functions that can never fail. -- From 7ec0fa83a2769e1ff935d9641f2fe2a89a148849 Mon Sep 17 00:00:00 2001 From: kokobd Date: Mon, 18 Dec 2023 18:35:29 -0500 Subject: [PATCH 6/7] update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cf18b7..7c02b6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ The format is based on [Keep a Changelog][chg] and this project adheres to - Add support for aeson 2.2 - `fallibleRuntime` and `fallibleRuntimeWithContext` reports errors to AWS instead of returning `{"Left": "some error"}`. + - `fallibleRuntime` and `fallibleRuntimeWithContext` no longer wrap their + successful responses in `{"Right": ...}` - `pureRuntime`, `pureRuntimeWithContext`, `fallibleRuntime` and `fallibleRuntimeWithContext` no longer crash the Lambda runtime if input can't be parsed from JSON. From 8029c0efb8156075f4bd84aa9169f719f58b3352 Mon Sep 17 00:00:00 2001 From: kokobd Date: Mon, 18 Dec 2023 18:37:54 -0500 Subject: [PATCH 7/7] update changelog --- CHANGELOG.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43663cd..05217eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,11 +7,10 @@ The format is based on [Keep a Changelog][chg] and this project adheres to ## unreleased - 2023-11-23 - - Add support for aeson 2.2 - - `fallibleRuntime` and `fallibleRuntimeWithContext` reports errors to AWS + - `fallibleRuntime` and `fallibleRuntimeWithContext` report errors to AWS instead of returning `{"Left": "some error"}`. - `fallibleRuntime` and `fallibleRuntimeWithContext` no longer wrap their - successful responses in `{"Right": ...}` + successful responses in `{"Right": ...}`. - `pureRuntime`, `pureRuntimeWithContext`, `fallibleRuntime` and `fallibleRuntimeWithContext` no longer crash the Lambda runtime if input can't be parsed from JSON.