serverless-haskell 0.6.0 → 0.6.1
raw patch · 5 files changed
+85/−44 lines, 5 files
Files
- README.md +12/−1
- serverless-haskell.cabal +2/−2
- src/AWSLambda.hs +12/−1
- src/AWSLambda/Events/APIGateway.hs +43/−30
- src/AWSLambda/Handler.hs +16/−10
README.md view
@@ -83,10 +83,20 @@ You can test the function and see the invocation results with `sls invoke myfunc`. + To invoke the function locally, use `sls invoke local -f myfunc`.++### API Gateway++This plugin supports handling API Gateway requests. Declare the HTTP events+normally in `serverless.yml` and use+[AWSLambda.Events.APIGateway](https://hackage.haskell.org/package/serverless-haskell/docs/AWSLambda-Events-APIGateway.html)+in the handler to process them.++[Serverless Offline] can be used for local testing of API Gateway requests.+ ### Notes * `sls deploy function` is [not supported yet](https://github.com/seek-oss/serverless-haskell/issues/20).-* `sls invoke local` is [not supported yet](https://github.com/seek-oss/serverless-haskell/issues/32). * Only AWS Lambda is supported at the moment. Other cloud providers would require different JavaScript wrappers to be implemented. @@ -128,4 +138,5 @@ [jq]: https://stedolan.github.io/jq/ [NPM]: https://www.npmjs.com/ [Serverless]: https://serverless.com/framework/+[Serverless Offline]: https://github.com/dherault/serverless-offline [Stack]: https://haskellstack.org
serverless-haskell.cabal view
@@ -2,10 +2,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: a288b7dc8892f8e7cdb3d9e4d980ac5efaf104fe9c7a57a274c93d42991a2145+-- hash: 0fa49464ad722f9e904826775d750cd559324657f0fb63fff4212c4e818e7ba8 name: serverless-haskell-version: 0.6.0+version: 0.6.1 synopsis: Deploying Haskell code onto AWS Lambda using Serverless description: Utilities to help process the events from AWS Lambda when deployed with the serverless-haskell plugin. category: AWS, Cloud, Network
src/AWSLambda.hs view
@@ -1,5 +1,5 @@ {-|-Module : AWSLambda.Handler+Module : AWSLambda Stability : experimental Portability : POSIX @@ -44,6 +44,17 @@ You can test the function and see the invocation results with @sls invoke myfunc@.++ To invoke the function locally, use @sls invoke local -f myfunc@.++= API Gateway++This plugin supports handling API Gateway requests. Declare the HTTP events+normally in @serverless.yml@ and use 'AWSLambda.Events.APIGateway' in the+handler to process them.++<https://github.com/dherault/serverless-offline Serverless Offline> can be used+for local testing of API Gateway requests. = Additional features
src/AWSLambda/Events/APIGateway.hs view
@@ -8,6 +8,19 @@ Description: Types for APIGateway Lambda requests and responses Based on https://github.com/aws/aws-lambda-dotnet/tree/master/Libraries/src/Amazon.Lambda.APIGatewayEvents++To enable processing of API Gateway events, use the @events@ key in+@serverless.yml@ as usual:++> functions:+> myapifunc:+> handler: mypackage.mypackage-exe+> events:+> - http:+> path: hello/{name}+> method: get++Then use 'apiGatewayMain' in the handler to process the requests. -} module AWSLambda.Events.APIGateway where @@ -200,36 +213,36 @@ responseBodyBinary :: Setter' (APIGatewayProxyResponse Base64) (Maybe ByteString) responseBodyBinary = responseBody . mapping _Base64 --- | Process incoming events from @serverless-haskell@ using a provided--- function.------ This is a specialisation of lambdaMain for API Gateway.------ The handler receives the input event given to the AWS Lambda function, and--- its return value is returned from the function.------ This is intended to be used as @main@, for example:------ > import AWSLambda.Events.APIGateway--- > import Control.Lens--- > import Data.Aeson--- > import Data.Aeson.Embedded--- >--- > main = apiGatewayMain handler--- >--- > handler :: APIGatewayProxyRequest (Embedded Value) -> IO (APIGatewayProxyResponse (Embedded [Int]))--- > handler request = do--- > putStrLn "This should go to logs"--- > print $ request ^. requestBody--- > pure $ responseOK & responseBodyEmbedded ?~ [1, 2, 3]------ The type parameters @reqBody@ and @resBody@ represent the types of request and response body, respectively.--- The @FromText@ and @ToText@ contraints are required because these values come from string fields--- in the request and response JSON objects.--- To get direct access to the body string, use @Text@ as the parameter type.--- To treat the body as a stringified embedded JSON value, use @Embedded a@, where @a@ has the--- appropriate @FromJSON@ or @ToJSON@ instances.--- To treat the body as base 64 encoded binary use @Base64@.+{-| Process incoming events from @serverless-haskell@ using a provided function.++This is a specialisation of 'lambdaMain' for API Gateway.++The handler receives the input event given to the AWS Lambda function, and+its return value is returned from the function.++This is intended to be used as @main@, for example:++> import AWSLambda.Events.APIGateway+> import Control.Lens+> import Data.Aeson+> import Data.Aeson.Embedded+>+> main = apiGatewayMain handler+>+> handler :: APIGatewayProxyRequest (Embedded Value) -> IO (APIGatewayProxyResponse (Embedded [Int]))+> handler request = do+> putStrLn "This should go to logs"+> print $ request ^. requestBody+> pure $ responseOK & responseBodyEmbedded ?~ [1, 2, 3]++The type parameters @reqBody@ and @resBody@ represent the types of request and response body, respectively.+The @FromText@ and @ToText@ contraints are required because these values come from string fields+in the request and response JSON objects.+To get direct access to the body string, use @Text@ as the parameter type.+To treat the body as a stringified embedded JSON value, use @Embedded a@, where @a@ has the+appropriate @FromJSON@ or @ToJSON@ instances.+To treat the body as base 64 encoded binary use @Base64@.+-} apiGatewayMain :: (FromText reqBody, ToText resBody) => (APIGatewayProxyRequest reqBody -> IO (APIGatewayProxyResponse resBody)) -- ^ Function to process the event
src/AWSLambda/Handler.hs view
@@ -5,11 +5,13 @@ Entry point for AWS Lambda handlers deployed with @serverless-haskell@ plugin. -}+{-# LANGUAGE TypeApplications #-}+ module AWSLambda.Handler ( lambdaMain ) where -import Control.Exception (bracket)+import Control.Exception (bracket, try) import qualified Data.Aeson as Aeson import qualified Data.Aeson.Text as Aeson@@ -18,10 +20,11 @@ import qualified Data.Text.Lazy.IO as Text -import GHC.IO.Handle (Handle, hClose)+import GHC.IO.Handle+ (BufferMode(..), Handle, hClose, hSetBuffering) -import System.Environment (lookupEnv) import System.IO (stdout)+import System.Posix.Files (getFdStatus) import System.Posix.IO (fdToHandle) import System.Posix.Types (Fd(..)) @@ -88,15 +91,18 @@ Text.hPutStrLn resultChannel $ Aeson.encodeToLazyText result pure () --- | Invoke an action with the handle to write the results to. On AWS Lambda,--- use the channel opened by the JavaScript wrapper, otherwise use standard--- output.+-- | Invoke an action with the handle to write the results to. If called by the+-- JavaScript wrapper, use the channel opened by it, otherwise use standard+-- output. Also set line buffering on standard output for AWS Lambda so the logs+-- are output in a timely manner. withResultChannel :: (Handle -> IO r) -> IO r withResultChannel act = do- lambdaFunctionName <- lookupEnv "AWS_LAMBDA_FUNCTION_NAME"- case lambdaFunctionName of- Just _ -> bracket (fdToHandle communicationFd) hClose act- Nothing -> act stdout+ commStatus <- try @IOError $ getFdStatus communicationFd+ case commStatus of+ Right _ -> do+ hSetBuffering stdout LineBuffering+ bracket (fdToHandle communicationFd) hClose act+ Left _ -> act stdout -- | File descriptor opened by the JavaScript wrapper to listen for the results communicationFd :: Fd