Skip to content

Commit ae34835

Browse files
committed
Fixed excess quotes put around plain text responses when using StandaloneLambda.
1 parent df0090d commit ae34835

File tree

7 files changed

+51
-23
lines changed

7 files changed

+51
-23
lines changed

aws-lambda-haskell-runtime.cabal

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ cabal-version: 1.12
44
--
55
-- see: https://github.com/sol/hpack
66
--
7-
-- hash: c27e1b0a071f3c0ebc02eac12fbefd43b148464edc8f7a6f3fada3d17051bacc
7+
-- hash: c21b3c988844f7c4bfb806aff4e307c5d5dc63a7973eff4a83eb329e7bccb1c9
88

99
name: aws-lambda-haskell-runtime
1010
version: 3.0.0
@@ -46,6 +46,7 @@ library
4646
Aws.Lambda.Runtime.Environment
4747
Aws.Lambda.Runtime.Error
4848
Aws.Lambda.Runtime.Publish
49+
Aws.Lambda.Utilities
4950
Paths_aws_lambda_haskell_runtime
5051
hs-source-dirs:
5152
src

src/Aws/Lambda/Configuration.hs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ module Aws.Lambda.Configuration
33
( Main.LambdaOptions(..)
44
, generateLambdaDispatcher
55
, Dispatch.decodeObj
6-
, Dispatch.encodeObj
76
)
87
where
98

src/Aws/Lambda/Meta/Dispatch.hs

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
module Aws.Lambda.Meta.Dispatch
55
( generate
66
, decodeObj
7-
, encodeObj
87
, Runtime.LambdaResult(..)
98
) where
109

@@ -20,6 +19,7 @@ import qualified Language.Haskell.TH as Meta
2019
import Aws.Lambda.Meta.Common
2120
import qualified Aws.Lambda.Meta.Main as Main
2221
import qualified Aws.Lambda.Runtime.ApiGatewayInfo as ApiGatewayInfo
22+
import Aws.Lambda.Runtime.Common (toStandaloneLambdaResponse)
2323
import qualified Aws.Lambda.Runtime.Common as Runtime
2424
import qualified Aws.Lambda.Runtime.Error as Error
2525
import qualified Control.Exception as Unchecked
@@ -36,13 +36,6 @@ decodeObj x =
3636
Left e -> Left $ Error.Parsing e (LazyByteString.unpack x) objName
3737
Right v -> return v
3838

39-
{-| Helper function that the dispatcher will use to
40-
decode the JSON that comes as an AWS Lambda event into the
41-
appropriate type expected by the handler.
42-
-}
43-
encodeObj :: ToJSON a => a -> String
44-
encodeObj x = LazyByteString.unpack (encode x)
45-
4639
{-| Generates the dispatcher out of a list of
4740
handler names in the form @src/Foo/Bar.handler@
4841
@@ -70,16 +63,16 @@ standaloneLambdaHandlerCase lambdaHandler = do
7063
case decodeObj $(expressionName "eventObject") of
7164
Right eventObject -> (do
7265
result <- $(expressionName (qualifiedHandlerName lambdaHandler)) eventObject contextObject
73-
either (pure . Left . Runtime.StandaloneLambdaError . encodeObj) (pure . Right . Runtime.StandaloneLambdaResult . encodeObj) result)
74-
`Unchecked.catch` \(handlerError :: Unchecked.SomeException) -> pure . Left . Runtime.StandaloneLambdaError . encodeObj . show $ handlerError
75-
Left err -> pure . Left . Runtime.StandaloneLambdaError . encodeObj $ err|]
66+
either (pure . Left . Runtime.StandaloneLambdaError . toStandaloneLambdaResponse) (pure . Right . Runtime.StandaloneLambdaResult . toStandaloneLambdaResponse) result)
67+
`Unchecked.catch` \(handlerError :: Unchecked.SomeException) -> pure . Left . Runtime.StandaloneLambdaError . toStandaloneLambdaResponse . show $ handlerError
68+
Left err -> pure . Left . Runtime.StandaloneLambdaError . toStandaloneLambdaResponse $ err|]
7669
pure $ Meta.Match pat (Meta.NormalB body) []
7770

7871
standaloneLambdaUnmatchedCase :: Meta.MatchQ
7972
standaloneLambdaUnmatchedCase = do
8073
let pattern = Meta.WildP
8174
body <- [e|
82-
pure . Left . Runtime.StandaloneLambdaError . encodeObj $ ("Handler " <> $(expressionName "functionHandler") <> " does not exist on project")
75+
pure . Left . Runtime.StandaloneLambdaError . toStandaloneLambdaResponse $ ("Handler " <> $(expressionName "functionHandler") <> " does not exist on project" :: String)
8376
|]
8477
pure $ Meta.Match pattern (Meta.NormalB body) []
8578

src/Aws/Lambda/Runtime/ApiGatewayInfo.hs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ module Aws.Lambda.Runtime.ApiGatewayInfo
1414
, ToApiGatewayResponseBody(..)
1515
, mkApiGatewayResponse ) where
1616

17+
import Aws.Lambda.Utilities
1718
import Data.Aeson
1819
import Data.Aeson.Types (Parser)
1920
import qualified Data.Aeson.Types as T
20-
import qualified Data.ByteString.Lazy.Char8 as LazyByteString
2121
import qualified Data.CaseInsensitive as CI
2222
import Data.HashMap.Strict (HashMap)
2323
import Data.Text (Text)
@@ -189,6 +189,3 @@ headerToPair (cibyte, bstr) = k .= v
189189
where
190190
k = (T.decodeUtf8 . CI.original) cibyte
191191
v = T.decodeUtf8 bstr
192-
193-
toJSONText :: ToJSON a => a -> Text
194-
toJSONText = T.pack . LazyByteString.unpack . encode

src/Aws/Lambda/Runtime/Common.hs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
{-# LANGUAGE DeriveLift #-}
1+
{-# LANGUAGE DeriveLift #-}
2+
{-# LANGUAGE DerivingStrategies #-}
3+
{-# LANGUAGE FlexibleInstances #-}
4+
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
5+
{-# LANGUAGE UndecidableInstances #-}
26

37
module Aws.Lambda.Runtime.Common
48
( RunCallback
@@ -8,12 +12,18 @@ module Aws.Lambda.Runtime.Common
812
, DispatcherOptions(..)
913
, ApiGatewayDispatcherOptions(..)
1014
, DispatcherStrategy(..)
15+
, ToLambdaResponseBody(..)
16+
, unLambdaResponseBody
1117
, defaultDispatcherOptions
1218
) where
1319

1420
import Aws.Lambda.Runtime.ApiGatewayInfo
1521
import Aws.Lambda.Runtime.Context (Context)
22+
import Aws.Lambda.Utilities
23+
import Data.Aeson (FromJSON, ToJSON)
1624
import qualified Data.ByteString.Lazy as Lazy
25+
import Data.Text (Text)
26+
import qualified Data.Text as Text
1727
import GHC.Generics (Generic)
1828
import Language.Haskell.TH.Syntax (Lift)
1929

@@ -42,14 +52,33 @@ data DispatcherStrategy =
4252
type RunCallback context =
4353
LambdaOptions context -> IO (Either LambdaError LambdaResult)
4454

55+
-- | Wrapper type for lambda response body
56+
newtype LambdaResponseBody =
57+
LambdaResponseBody { unLambdaResponseBody :: Text }
58+
deriving newtype (ToJSON, FromJSON)
59+
60+
class ToLambdaResponseBody a where
61+
toStandaloneLambdaResponse :: a -> LambdaResponseBody
62+
63+
-- We need to special case String and Text to avoid unneeded encoding
64+
-- which results in extra quotes put around plain text responses
65+
instance {-# OVERLAPPING #-} ToLambdaResponseBody String where
66+
toStandaloneLambdaResponse = LambdaResponseBody . Text.pack
67+
68+
instance {-# OVERLAPPING #-} ToLambdaResponseBody Text where
69+
toStandaloneLambdaResponse = LambdaResponseBody
70+
71+
instance ToJSON a => ToLambdaResponseBody a where
72+
toStandaloneLambdaResponse = LambdaResponseBody . toJSONText
73+
4574
-- | Wrapper type for lambda execution results
4675
data LambdaError =
47-
StandaloneLambdaError String |
76+
StandaloneLambdaError LambdaResponseBody |
4877
ApiGatewayLambdaError (ApiGatewayResponse ApiGatewayResponseBody)
4978

5079
-- | Wrapper type to handle the result of the user
5180
data LambdaResult =
52-
StandaloneLambdaResult String |
81+
StandaloneLambdaResult LambdaResponseBody |
5382
ApiGatewayResult (ApiGatewayResponse ApiGatewayResponseBody)
5483

5584
-- | Options that the generated main expects

src/Aws/Lambda/Runtime/Publish.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ module Aws.Lambda.Runtime.Publish
99

1010
import Control.Monad (void)
1111
import Data.Aeson
12-
import qualified Data.ByteString.Char8 as ByteString
12+
import qualified Data.Text.Encoding as T
1313
import qualified Network.HTTP.Client as Http
1414

1515
import qualified Aws.Lambda.Runtime.API.Endpoints as Endpoints
@@ -24,7 +24,7 @@ result lambdaResult lambdaApi context manager = do
2424
rawRequest <- Http.parseRequest endpoint
2525

2626
let requestBody = case lambdaResult of
27-
(StandaloneLambdaResult res) -> Http.RequestBodyBS (ByteString.pack res)
27+
(StandaloneLambdaResult res) -> Http.RequestBodyBS (T.encodeUtf8 . unLambdaResponseBody $ res)
2828
(ApiGatewayResult res) -> Http.RequestBodyLBS (encode res)
2929
request = rawRequest
3030
{ Http.method = "POST"

src/Aws/Lambda/Utilities.hs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module Aws.Lambda.Utilities (toJSONText) where
2+
3+
import Data.Aeson
4+
import qualified Data.ByteString.Lazy.Char8 as LazyByteString
5+
import Data.Text
6+
import qualified Data.Text as T
7+
8+
toJSONText :: ToJSON a => a -> Text
9+
toJSONText = T.pack . LazyByteString.unpack . encode

0 commit comments

Comments
 (0)