module AWSLambda.Events.APIGateway where
import Control.Lens
import Data.Aeson
import Data.Aeson.Casing (aesonDrop, camelCase)
import Data.Aeson.TH (deriveFromJSON)
import Data.Aeson.Embedded
import Data.Aeson.TextValue
import Data.ByteString (ByteString)
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import Data.Text (Text)
import GHC.Generics (Generic)
import Network.AWS.Data.Base64
import Network.AWS.Data.Text
import AWSLambda.Handler (lambdaMain)
type Method = Text
type HeaderName = Text
type HeaderValue = Text
type QueryParamName = Text
type QueryParamValue = Text
type PathParamName = Text
type PathParamValue = Text
type StageVarName = Text
type StageVarValue = Text
data RequestIdentity = RequestIdentity
{ _riCognitoIdentityPoolId :: !(Maybe Text)
, _riAccountId :: !(Maybe Text)
, _riCognitoIdentityId :: !(Maybe Text)
, _riCaller :: !(Maybe Text)
, _riApiKey :: !(Maybe Text)
, _riSourceIp :: !(Maybe Text)
, _riCognitoAuthenticationType :: !(Maybe Text)
, _riCognitoAuthenticationProvider :: !(Maybe Text)
, _riUserArn :: !(Maybe Text)
, _riUserAgent :: !(Maybe Text)
, _riUser :: !(Maybe Text)
} deriving (Eq, Show)
$(deriveFromJSON (aesonDrop 3 camelCase) ''RequestIdentity)
$(makeLenses ''RequestIdentity)
data ProxyRequestContext = ProxyRequestContext
{ _prcPath :: !(Maybe Text)
, _prcAccountId :: !Text
, _prcResourceId :: !Text
, _prcStage :: !Text
, _prcRequestId :: !Text
, _prcIdentity :: !RequestIdentity
, _prcResourcePath :: !Text
, _prcHttpMethod :: !Text
, _prcApiId :: !Text
} deriving (Eq, Show)
$(deriveFromJSON (aesonDrop 4 camelCase) ''ProxyRequestContext)
$(makeLenses ''ProxyRequestContext)
data APIGatewayProxyRequest body = APIGatewayProxyRequest
{ _agprqResource :: !Text
, _agprqPath :: !Text
, _agprqHttpMethod :: !Method
, _agprqHeaders :: !(HashMap HeaderName HeaderValue)
, _agprqQueryStringParameters :: !(HashMap QueryParamName QueryParamValue)
, _agprqPathParameters :: !(HashMap PathParamName PathParamValue)
, _agprqStageVariables :: !(HashMap StageVarName StageVarValue)
, _agprqRequestContext :: !ProxyRequestContext
, _agprqBody :: !(Maybe (TextValue body))
} deriving (Eq, Show, Generic)
instance FromText body => FromJSON (APIGatewayProxyRequest body) where
parseJSON = withObject "APIGatewayProxyRequest" $ \o ->
APIGatewayProxyRequest
<$> o .: "resource"
<*> o .: "path"
<*> o .: "httpMethod"
<*> o .:? "headers" .!= HashMap.empty
<*> o .:? "queryStringParameters" .!= HashMap.empty
<*> o .:? "pathParameters" .!= HashMap.empty
<*> o .:? "stageVariables" .!= HashMap.empty
<*> o .: "requestContext"
<*> o .:? "body"
$(makeLenses ''APIGatewayProxyRequest)
requestBody :: Getter (APIGatewayProxyRequest body) (Maybe body)
requestBody = agprqBody . mapping unTextValue
requestBodyEmbedded :: Getter (APIGatewayProxyRequest (Embedded v)) (Maybe v)
requestBodyEmbedded = requestBody . mapping unEmbed
requestBodyBinary :: Getter (APIGatewayProxyRequest Base64) (Maybe ByteString)
requestBodyBinary = requestBody . mapping _Base64
data APIGatewayProxyResponse body = APIGatewayProxyResponse
{ _agprsStatusCode :: !Int
, _agprsHeaders :: !(HashMap HeaderName HeaderValue)
, _agprsBody :: !(Maybe (TextValue body))
} deriving (Eq, Show, Generic)
instance ToText body => ToJSON (APIGatewayProxyResponse body) where
toJSON = genericToJSON $ aesonDrop 6 camelCase
instance FromText body => FromJSON (APIGatewayProxyResponse body) where
parseJSON = genericParseJSON $ aesonDrop 6 camelCase
$(makeLenses ''APIGatewayProxyResponse)
response :: Int -> APIGatewayProxyResponse body
response statusCode = APIGatewayProxyResponse statusCode HashMap.empty Nothing
responseOK :: APIGatewayProxyResponse body
responseOK = response 200
responseNotFound :: APIGatewayProxyResponse body
responseNotFound = response 404
responseBadRequest :: APIGatewayProxyResponse body
responseBadRequest = response 400
responseBody :: Setter' (APIGatewayProxyResponse body) (Maybe body)
responseBody = agprsBody . at () . mapping unTextValue
responseBodyEmbedded :: Setter' (APIGatewayProxyResponse (Embedded body)) (Maybe body)
responseBodyEmbedded = responseBody . mapping unEmbed
responseBodyBinary :: Setter' (APIGatewayProxyResponse Base64) (Maybe ByteString)
responseBodyBinary = responseBody . mapping _Base64
apiGatewayMain
:: (FromText reqBody, ToText resBody)
=> (APIGatewayProxyRequest reqBody -> IO (APIGatewayProxyResponse resBody))
-> IO ()
apiGatewayMain = lambdaMain