aws-lambda-haskell-runtime 2.0.6 → 3.0.0
raw patch · 10 files changed
+187/−111 lines, 10 files
Files
- aws-lambda-haskell-runtime.cabal +3/−2
- src/Aws/Lambda/Configuration.hs +0/−1
- src/Aws/Lambda/Meta/Dispatch.hs +25/−38
- src/Aws/Lambda/Meta/Main.hs +1/−1
- src/Aws/Lambda/Runtime.hs +15/−10
- src/Aws/Lambda/Runtime/ApiGatewayInfo.hs +72/−34
- src/Aws/Lambda/Runtime/Common.hs +41/−11
- src/Aws/Lambda/Runtime/Context.hs +13/−6
- src/Aws/Lambda/Runtime/Publish.hs +8/−8
- src/Aws/Lambda/Utilities.hs +9/−0
aws-lambda-haskell-runtime.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: eab5b338b49db7854613ecd43b17245f105c8c936c40230ecf9d08c5dfad9d6d+-- hash: c21b3c988844f7c4bfb806aff4e307c5d5dc63a7973eff4a83eb329e7bccb1c9 name: aws-lambda-haskell-runtime-version: 2.0.6+version: 3.0.0 synopsis: Haskell runtime for AWS Lambda description: Please see the README on GitHub at <https://github.com/theam/aws-lambda-haskell-runtime#readme> category: AWS@@ -46,6 +46,7 @@ Aws.Lambda.Runtime.Environment Aws.Lambda.Runtime.Error Aws.Lambda.Runtime.Publish+ Aws.Lambda.Utilities Paths_aws_lambda_haskell_runtime hs-source-dirs: src
src/Aws/Lambda/Configuration.hs view
@@ -3,7 +3,6 @@ ( Main.LambdaOptions(..) , generateLambdaDispatcher , Dispatch.decodeObj- , Dispatch.encodeObj ) where
src/Aws/Lambda/Meta/Dispatch.hs view
@@ -1,50 +1,41 @@ {-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE BangPatterns #-} {-| Dispatcher generation -} module Aws.Lambda.Meta.Dispatch ( generate , decodeObj- , encodeObj , Runtime.LambdaResult(..) ) where +import qualified Data.Char as Char import Data.Function ((&)) import Data.Text (Text) import qualified Data.Text as Text-import qualified Data.Char as Char import Data.Aeson import qualified Data.ByteString.Lazy.Char8 as LazyByteString import qualified Language.Haskell.TH as Meta import Aws.Lambda.Meta.Common+import qualified Aws.Lambda.Meta.Main as Main+import qualified Aws.Lambda.Runtime.ApiGatewayInfo as ApiGatewayInfo+import Aws.Lambda.Runtime.Common (toStandaloneLambdaResponse) import qualified Aws.Lambda.Runtime.Common as Runtime import qualified Aws.Lambda.Runtime.Error as Error-import qualified Aws.Lambda.Runtime.ApiGatewayInfo as ApiGatewayInfo import qualified Control.Exception as Unchecked-import qualified Aws.Lambda.Meta.Main as Main-import Data.Typeable (Typeable, typeRep, Proxy (..))+import Data.Typeable (Proxy (..), Typeable, typeRep) {-| Helper function that the dispatcher will use to decode the JSON that comes as an AWS Lambda event into the appropriate type expected by the handler. -}-decodeObj :: forall a. (FromJSON a, Typeable a) => String -> Either Error.Parsing a+decodeObj :: forall a. (FromJSON a, Typeable a) => LazyByteString.ByteString -> Either Error.Parsing a decodeObj x = let objName = show (typeRep (Proxy :: Proxy a)) in- case (eitherDecode $ LazyByteString.pack x) of- Left e -> Left $ Error.Parsing e x objName+ case (eitherDecode x) of+ Left e -> Left $ Error.Parsing e (LazyByteString.unpack x) objName Right v -> return v -{-| Helper function that the dispatcher will use to-decode the JSON that comes as an AWS Lambda event into the-appropriate type expected by the handler.--}-encodeObj :: ToJSON a => a -> String-encodeObj x = LazyByteString.unpack (encode x)-- {-| Generates the dispatcher out of a list of handler names in the form @src/Foo/Bar.handler@ @@ -70,20 +61,18 @@ let pat = Meta.LitP (Meta.StringL $ Text.unpack lambdaHandler) body <- [e|do case decodeObj $(expressionName "eventObject") of- Right eventObject -> case decodeObj $(expressionName "contextObject") of- Right context -> (do- result <- $(expressionName (qualifiedHandlerName lambdaHandler)) eventObject context- either (pure . Left . Runtime.StandaloneLambdaError . encodeObj) (pure . Right . Runtime.StandaloneLambdaResult . encodeObj) result)- `Unchecked.catch` \(handlerError :: Unchecked.SomeException) -> pure . Left . Runtime.StandaloneLambdaError . encodeObj . show $ handlerError- Left err -> pure . Left . Runtime.StandaloneLambdaError . encodeObj $ err- Left err -> pure . Left . Runtime.StandaloneLambdaError . encodeObj $ err|]+ Right eventObject -> (do+ result <- $(expressionName (qualifiedHandlerName lambdaHandler)) eventObject contextObject+ either (pure . Left . Runtime.StandaloneLambdaError . toStandaloneLambdaResponse) (pure . Right . Runtime.StandaloneLambdaResult . toStandaloneLambdaResponse) result)+ `Unchecked.catch` \(handlerError :: Unchecked.SomeException) -> pure . Left . Runtime.StandaloneLambdaError . toStandaloneLambdaResponse . show $ handlerError+ Left err -> pure . Left . Runtime.StandaloneLambdaError . toStandaloneLambdaResponse $ err|] pure $ Meta.Match pat (Meta.NormalB body) [] standaloneLambdaUnmatchedCase :: Meta.MatchQ standaloneLambdaUnmatchedCase = do let pattern = Meta.WildP body <- [e|- pure . Left . Runtime.StandaloneLambdaError . encodeObj $ ("Handler " <> $(expressionName "functionHandler") <> " does not exist on project")+ pure . Left . Runtime.StandaloneLambdaError . toStandaloneLambdaResponse $ ("Handler " <> $(expressionName "functionHandler") <> " does not exist on project" :: String) |] pure $ Meta.Match pattern (Meta.NormalB body) [] @@ -93,25 +82,23 @@ body <- [e|do let returnErr statusCode = pure . Left . Runtime.ApiGatewayLambdaError . ApiGatewayInfo.mkApiGatewayResponse statusCode case decodeObj $(expressionName "eventObject") of- Right eventObject -> case decodeObj $(expressionName "contextObject") of- Right context -> do- resultE <- Unchecked.try $ $(expressionName (qualifiedHandlerName lambdaHandler)) eventObject context- case resultE of- Right result ->- either (pure . Left . Runtime.ApiGatewayLambdaError . fmap toJSON) (pure . Right . Runtime.ApiGatewayResult . fmap toJSON) result- Left (handlerError :: Unchecked.SomeException) ->- if (Runtime.propagateImpureExceptions . Runtime.apiGatewayDispatcherOptions $ options)- then returnErr 500 . toJSON . show $ handlerError- else returnErr 500 . toJSON $ "Something went wrong."- Left err -> returnErr 500 . toJSON $ err- Left err -> returnErr 400 . toJSON $ err|]+ Right eventObject -> do+ resultE <- Unchecked.try $ $(expressionName (qualifiedHandlerName lambdaHandler)) eventObject contextObject+ case resultE of+ Right result ->+ either (pure . Left . Runtime.ApiGatewayLambdaError . fmap toApiGatewayResponseBody) (pure . Right . Runtime.ApiGatewayResult . fmap toApiGatewayResponseBody) result+ Left (handlerError :: Unchecked.SomeException) ->+ if (Runtime.propagateImpureExceptions . Runtime.apiGatewayDispatcherOptions $ options)+ then returnErr 500 . toApiGatewayResponseBody . show $ handlerError+ else returnErr 500 . toApiGatewayResponseBody . Text.pack $ "Something went wrong."+ Left err -> returnErr 400 . toApiGatewayResponseBody . show $ err|] pure $ Meta.Match pat (Meta.NormalB body) [] apiGatewayUnmatchedCase :: Meta.MatchQ apiGatewayUnmatchedCase = do let pattern = Meta.WildP body <- [e|- pure . Left . Runtime.ApiGatewayLambdaError . ApiGatewayInfo.mkApiGatewayResponse 500 . toJSON $ ("Handler " <> $(expressionName "functionHandler") <> " does not exist on project")+ pure . Left . Runtime.ApiGatewayLambdaError . ApiGatewayInfo.mkApiGatewayResponse 500 . toApiGatewayResponseBody $ ("Handler " <> $(expressionName "functionHandler") <> " does not exist on project") |] pure $ Meta.Match pattern (Meta.NormalB body) []
src/Aws/Lambda/Meta/Main.hs view
@@ -21,5 +21,5 @@ where directCallBody = [e|- runLambda run+ runLambda initializeContext run |]
src/Aws/Lambda/Runtime.hs view
@@ -1,3 +1,6 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+ module Aws.Lambda.Runtime ( runLambda , Runtime.LambdaResult(..)@@ -15,7 +18,7 @@ import qualified Network.HTTP.Client as Http import Data.Aeson-import qualified Data.ByteString.Lazy.Char8 as LazyByteString+import Data.IORef import qualified Aws.Lambda.Runtime.ApiInfo as ApiInfo import qualified Aws.Lambda.Runtime.Common as Runtime@@ -27,13 +30,15 @@ -- | Runs the user @haskell_lambda@ executable and posts back the -- results. This is called from the layer's @main@ function.-runLambda :: Runtime.RunCallback -> IO ()-runLambda callback = do+runLambda :: forall context. IO context -> Runtime.RunCallback context -> IO ()+runLambda initializeCustomContext callback = do manager <- Http.newManager httpManagerSettings+ customContext <- initializeCustomContext+ customContextRef <- newIORef customContext forever $ do lambdaApi <- Environment.apiEndpoint `catch` variableNotSet event <- ApiInfo.fetchEvent manager lambdaApi `catch` errorParsing- context <- Context.initialize event `catch` errorParsing `catch` variableNotSet+ context <- Context.initialize @context customContextRef event `catch` errorParsing `catch` variableNotSet (((invokeAndRun callback manager lambdaApi event context `Checked.catch` \err -> Publish.parsingError err lambdaApi context manager)@@ -51,11 +56,11 @@ invokeAndRun :: Throws Error.Invocation => Throws Error.EnvironmentVariableNotSet- => Runtime.RunCallback+ => Runtime.RunCallback context -> Http.Manager -> String -> ApiInfo.Event- -> Context.Context+ -> Context.Context context -> IO () invokeAndRun callback manager lambdaApi event context = do result <- invokeWithCallback callback event context@@ -66,17 +71,17 @@ invokeWithCallback :: Throws Error.Invocation => Throws Error.EnvironmentVariableNotSet- => Runtime.RunCallback+ => Runtime.RunCallback context -> ApiInfo.Event- -> Context.Context+ -> Context.Context context -> IO Runtime.LambdaResult invokeWithCallback callback event context = do handlerName <- Environment.handlerName let lambdaOptions = Runtime.LambdaOptions- { eventObject = LazyByteString.unpack $ ApiInfo.event event- , contextObject = LazyByteString.unpack . encode $ context+ { eventObject = ApiInfo.event event , functionHandler = handlerName , executionUuid = "" -- DirectCall doesnt use UUID+ , contextObject = context } result <- callback lambdaOptions -- Flush output to insure output goes into CloudWatch logs
src/Aws/Lambda/Runtime/ApiGatewayInfo.hs view
@@ -1,23 +1,30 @@-{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GeneralisedNewtypeDeriving #-}+{-# LANGUAGE UndecidableInstances #-} module Aws.Lambda.Runtime.ApiGatewayInfo ( ApiGatewayRequest(..) , ApiGatewayRequestContext(..) , ApiGatewayRequestContextIdentity(..) , ApiGatewayResponse(..)+ , ApiGatewayResponseBody(..)+ , ToApiGatewayResponseBody(..) , mkApiGatewayResponse ) where +import Aws.Lambda.Utilities import Data.Aeson+import Data.Aeson.Types (Parser)+import qualified Data.Aeson.Types as T+import qualified Data.CaseInsensitive as CI import Data.HashMap.Strict (HashMap) import Data.Text (Text) import qualified Data.Text as T import qualified Data.Text.Encoding as T import GHC.Generics (Generic) import Network.HTTP.Types-import qualified Data.CaseInsensitive as CI-import qualified Data.Aeson.Types as T-import qualified Data.ByteString.Lazy.Char8 as LazyByteString-import Data.Aeson.Types (Parser) data ApiGatewayRequest body = ApiGatewayRequest { apiGatewayRequestResource :: !Text@@ -32,20 +39,43 @@ , apiGatewayRequestBody :: !(Maybe body) } deriving (Show) +-- We special case String and Text in order+-- to avoid unneeded encoding which will wrap them in quotes and break parsing+instance {-# OVERLAPPING #-} FromJSON (ApiGatewayRequest Text) where+ parseJSON = parseApiGatewayRequest (.:)++instance {-# OVERLAPPING #-} FromJSON (ApiGatewayRequest String) where+ parseJSON = parseApiGatewayRequest (.:)+ instance FromJSON body => FromJSON (ApiGatewayRequest body) where- parseJSON (Object v) = ApiGatewayRequest <$>- v .: "resource" <*>- v .: "path" <*>- v .: "httpMethod" <*>- v .: "headers" <*>- v .: "queryStringParameters" <*>- v .: "pathParameters" <*>- v .: "stageVariables" <*>- v .: "isBase64Encoded" <*>- v .: "requestContext" <*>- v `parseObjectFromStringField` "body"- parseJSON _ = fail "Expected ApiGatewayRequest to be an object."+ parseJSON = parseApiGatewayRequest parseObjectFromStringField +-- We need this because API Gateway is going to send us the payload as a JSON string+parseObjectFromStringField :: FromJSON a => Object -> Text -> Parser (Maybe a)+parseObjectFromStringField obj fieldName = do+ fieldContents <- obj .: fieldName+ case fieldContents of+ String stringContents ->+ case eitherDecodeStrict (T.encodeUtf8 stringContents) of+ Right success -> pure success+ Left err -> fail err+ Null -> pure Nothing+ other -> T.typeMismatch "String or Null" other++parseApiGatewayRequest :: (Object -> Text -> Parser (Maybe body)) -> Value -> Parser (ApiGatewayRequest body)+parseApiGatewayRequest bodyParser (Object v) = ApiGatewayRequest <$>+ v .: "resource" <*>+ v .: "path" <*>+ v .: "httpMethod" <*>+ v .: "headers" <*>+ v .: "queryStringParameters" <*>+ v .: "pathParameters" <*>+ v .: "stageVariables" <*>+ v .: "isBase64Encoded" <*>+ v .: "requestContext" <*>+ v `bodyParser` "body"+parseApiGatewayRequest _ _ = fail "Expected ApiGatewayRequest to be an object."+ data ApiGatewayRequestContext = ApiGatewayRequestContext { apiGatewayRequestContextResourceId :: !Text , apiGatewayRequestContextResourcePath :: !Text@@ -112,18 +142,23 @@ v .: "user" parseJSON _ = fail "Expected ApiGatewayRequestContextIdentity to be an object." --- We need this because API Gateway is going to send us the payload as a JSON string-parseObjectFromStringField :: FromJSON a => Object -> Text -> Parser (Maybe a)-parseObjectFromStringField obj fieldName = do- fieldContents <- obj .: fieldName- case fieldContents of- String stringContents ->- case eitherDecodeStrict (T.encodeUtf8 stringContents) of- Right success -> pure success- Left err -> fail err- Null -> pure Nothing- other -> T.typeMismatch "String or Null" other+newtype ApiGatewayResponseBody =+ ApiGatewayResponseBody Text+ deriving newtype (ToJSON, FromJSON) +class ToApiGatewayResponseBody a where+ toApiGatewayResponseBody :: a -> ApiGatewayResponseBody++-- We special case Text and String to avoid unneeded encoding which will wrap them in quotes+instance {-# OVERLAPPING #-} ToApiGatewayResponseBody Text where+ toApiGatewayResponseBody = ApiGatewayResponseBody++instance {-# OVERLAPPING #-} ToApiGatewayResponseBody String where+ toApiGatewayResponseBody = ApiGatewayResponseBody . T.pack++instance ToJSON a => ToApiGatewayResponseBody a where+ toApiGatewayResponseBody = ApiGatewayResponseBody . toJSONText+ data ApiGatewayResponse body = ApiGatewayResponse { apiGatewayResponseStatusCode :: !Int , apiGatewayResponseHeaders :: !ResponseHeaders@@ -135,12 +170,15 @@ fmap f v = v { apiGatewayResponseBody = f (apiGatewayResponseBody v) } instance ToJSON body => ToJSON (ApiGatewayResponse body) where- toJSON ApiGatewayResponse {..} = object- [ "statusCode" .= apiGatewayResponseStatusCode- , "body" .= (String . T.pack . LazyByteString.unpack . encode @body $ apiGatewayResponseBody)- , "headers" .= object (map headerToPair apiGatewayResponseHeaders)- , "isBase64Encoded" .= apiGatewayResponseIsBase64Encoded- ]+ toJSON = apiGatewayResponseToJSON toJSON++apiGatewayResponseToJSON :: (body -> Value) -> ApiGatewayResponse body -> Value+apiGatewayResponseToJSON bodyTransformer ApiGatewayResponse {..} = object+ [ "statusCode" .= apiGatewayResponseStatusCode+ , "body" .= bodyTransformer apiGatewayResponseBody+ , "headers" .= object (map headerToPair apiGatewayResponseHeaders)+ , "isBase64Encoded" .= apiGatewayResponseIsBase64Encoded+ ] mkApiGatewayResponse :: Int -> payload -> ApiGatewayResponse payload mkApiGatewayResponse code payload =
src/Aws/Lambda/Runtime/Common.hs view
@@ -1,4 +1,8 @@-{-# LANGUAGE DeriveLift #-}+{-# LANGUAGE DeriveLift #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE UndecidableInstances #-} module Aws.Lambda.Runtime.Common ( RunCallback@@ -8,11 +12,18 @@ , DispatcherOptions(..) , ApiGatewayDispatcherOptions(..) , DispatcherStrategy(..)+ , ToLambdaResponseBody(..)+ , unLambdaResponseBody , defaultDispatcherOptions ) where import Aws.Lambda.Runtime.ApiGatewayInfo-import Data.Aeson (Value)+import Aws.Lambda.Runtime.Context (Context)+import Aws.Lambda.Utilities+import Data.Aeson (FromJSON, ToJSON)+import qualified Data.ByteString.Lazy as Lazy+import Data.Text (Text)+import qualified Data.Text as Text import GHC.Generics (Generic) import Language.Haskell.TH.Syntax (Lift) @@ -38,23 +49,42 @@ deriving (Lift) -- | Callback that we pass to the dispatcher function-type RunCallback =- LambdaOptions -> IO (Either LambdaError LambdaResult)+type RunCallback context =+ LambdaOptions context -> IO (Either LambdaError LambdaResult) +-- | Wrapper type for lambda response body+newtype LambdaResponseBody =+ LambdaResponseBody { unLambdaResponseBody :: Text }+ deriving newtype (ToJSON, FromJSON)++class ToLambdaResponseBody a where+ toStandaloneLambdaResponse :: a -> LambdaResponseBody++-- We need to special case String and Text to avoid unneeded encoding+-- which results in extra quotes put around plain text responses+instance {-# OVERLAPPING #-} ToLambdaResponseBody String where+ toStandaloneLambdaResponse = LambdaResponseBody . Text.pack++instance {-# OVERLAPPING #-} ToLambdaResponseBody Text where+ toStandaloneLambdaResponse = LambdaResponseBody++instance ToJSON a => ToLambdaResponseBody a where+ toStandaloneLambdaResponse = LambdaResponseBody . toJSONText+ -- | Wrapper type for lambda execution results data LambdaError =- StandaloneLambdaError String |- ApiGatewayLambdaError (ApiGatewayResponse Value)+ StandaloneLambdaError LambdaResponseBody |+ ApiGatewayLambdaError (ApiGatewayResponse ApiGatewayResponseBody) -- | Wrapper type to handle the result of the user data LambdaResult =- StandaloneLambdaResult String |- ApiGatewayResult (ApiGatewayResponse Value)+ StandaloneLambdaResult LambdaResponseBody |+ ApiGatewayResult (ApiGatewayResponse ApiGatewayResponseBody) -- | Options that the generated main expects-data LambdaOptions = LambdaOptions- { eventObject :: !String- , contextObject :: !String+data LambdaOptions context = LambdaOptions+ { eventObject :: !Lazy.ByteString , functionHandler :: !String , executionUuid :: !String+ , contextObject :: !(Context context) } deriving (Generic)
src/Aws/Lambda/Runtime/Context.hs view
@@ -4,15 +4,14 @@ ) where import Control.Exception.Safe.Checked-import Data.Aeson (FromJSON (..), ToJSON (..))-import GHC.Generics (Generic)+import Data.IORef import qualified Aws.Lambda.Runtime.ApiInfo as ApiInfo import qualified Aws.Lambda.Runtime.Environment as Environment import qualified Aws.Lambda.Runtime.Error as Error -- | Context that is passed to all the handlers-data Context = Context+data Context context = Context { memoryLimitInMb :: !Int , functionName :: !String , functionVersion :: !String@@ -22,16 +21,23 @@ , logStreamName :: !String , logGroupName :: !String , deadline :: !Int- } deriving (Generic, FromJSON, ToJSON)+ , customContext :: !(IORef context)+ } -- | Initializes the context out of the environment-initialize :: Throws Error.Parsing => Throws Error.EnvironmentVariableNotSet => ApiInfo.Event -> IO Context-initialize ApiInfo.Event{..} = do+initialize+ :: Throws Error.Parsing+ => Throws Error.EnvironmentVariableNotSet+ => IORef context+ -> ApiInfo.Event+ -> IO (Context context)+initialize customContextRef ApiInfo.Event{..} = do functionName <- Environment.functionName version <- Environment.functionVersion logStream <- Environment.logStreamName logGroup <- Environment.logGroupName memoryLimitInMb <- Environment.functionMemory+ Environment.setXRayTrace traceId pure Context { functionName = functionName@@ -43,4 +49,5 @@ , xrayTraceId = traceId , awsRequestId = awsRequestId , deadline = deadlineMs+ , customContext = customContextRef }
src/Aws/Lambda/Runtime/Publish.hs view
@@ -9,7 +9,7 @@ import Control.Monad (void) import Data.Aeson-import qualified Data.ByteString.Char8 as ByteString+import qualified Data.Text.Encoding as T import qualified Network.HTTP.Client as Http import qualified Aws.Lambda.Runtime.API.Endpoints as Endpoints@@ -18,14 +18,14 @@ import qualified Aws.Lambda.Runtime.Error as Error -- | Publishes the result back to AWS Lambda-result :: LambdaResult -> String -> Context -> Http.Manager -> IO ()+result :: LambdaResult -> String -> Context context -> Http.Manager -> IO () result lambdaResult lambdaApi context manager = do let Endpoints.Endpoint endpoint = Endpoints.response lambdaApi (awsRequestId context) rawRequest <- Http.parseRequest endpoint let requestBody = case lambdaResult of- (StandaloneLambdaResult res) -> Http.RequestBodyBS (ByteString.pack res)- (ApiGatewayResult res) -> Http.RequestBodyLBS (encode res)+ (StandaloneLambdaResult res) -> Http.RequestBodyBS (T.encodeUtf8 . unLambdaResponseBody $ res)+ (ApiGatewayResult res) -> Http.RequestBodyLBS (encode res) request = rawRequest { Http.method = "POST" , Http.requestBody = requestBody@@ -34,22 +34,22 @@ void $ Http.httpNoBody request manager -- | Publishes an invocation error back to AWS Lambda-invocationError :: Error.Invocation -> String -> Context -> Http.Manager -> IO ()+invocationError :: Error.Invocation -> String -> Context context -> Http.Manager -> IO () invocationError err lambdaApi context = publish err (Endpoints.invocationError lambdaApi $ awsRequestId context) context -- | Publishes a parsing error back to AWS Lambda-parsingError :: Error.Parsing -> String -> Context -> Http.Manager -> IO ()+parsingError :: Error.Parsing -> String -> Context context -> Http.Manager -> IO () parsingError err lambdaApi context = publish err (Endpoints.invocationError lambdaApi $ awsRequestId context) context -- | Publishes a runtime initialization error back to AWS Lambda-runtimeInitError :: ToJSON err => err -> String -> Context -> Http.Manager -> IO ()+runtimeInitError :: ToJSON err => err -> String -> Context context -> Http.Manager -> IO () runtimeInitError err lambdaApi = publish err (Endpoints.runtimeInitError lambdaApi) -publish :: ToJSON err => err -> Endpoints.Endpoint -> Context -> Http.Manager -> IO ()+publish :: ToJSON err => err -> Endpoints.Endpoint -> Context context -> Http.Manager -> IO () publish err (Endpoints.Endpoint endpoint) Context{..} manager = do rawRequest <- Http.parseRequest endpoint
+ src/Aws/Lambda/Utilities.hs view
@@ -0,0 +1,9 @@+module Aws.Lambda.Utilities (toJSONText) where++import Data.Aeson+import qualified Data.ByteString.Lazy.Char8 as LazyByteString+import Data.Text+import qualified Data.Text as T++toJSONText :: ToJSON a => a -> Text+toJSONText = T.pack . LazyByteString.unpack . encode