From 0cc469f58853fc06f06167d3a024481979782999 Mon Sep 17 00:00:00 2001 From: Yummy-Yums Date: Thu, 12 Mar 2026 19:20:18 +0000 Subject: [PATCH 01/11] feature: Added APIGatewayAuthorizerEvent & results --- .../APIGatewayCustomAuthorizerEvent.scala | 207 ++++++++++++++++++ .../APIGatewayCustomAuthorizerResult.scala | 94 ++++++++ .../scala/feral/lambda/events/codecs.scala | 11 + ...ewayCustomAuthorizerEventResultSuite.scala | 48 ++++ ...ApiGatewayCustomAuthorizerEventSuite.scala | 122 +++++++++++ 5 files changed, 482 insertions(+) create mode 100644 lambda/shared/src/main/scala/feral/lambda/events/APIGatewayCustomAuthorizerEvent.scala create mode 100644 lambda/shared/src/main/scala/feral/lambda/events/APIGatewayCustomAuthorizerResult.scala create mode 100644 lambda/shared/src/test/scala/feral/lambda/events/APIGatewayCustomAuthorizerEventResultSuite.scala create mode 100644 lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventSuite.scala diff --git a/lambda/shared/src/main/scala/feral/lambda/events/APIGatewayCustomAuthorizerEvent.scala b/lambda/shared/src/main/scala/feral/lambda/events/APIGatewayCustomAuthorizerEvent.scala new file mode 100644 index 00000000..f8557c56 --- /dev/null +++ b/lambda/shared/src/main/scala/feral/lambda/events/APIGatewayCustomAuthorizerEvent.scala @@ -0,0 +1,207 @@ +/* + * Copyright 2021 Typelevel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package feral.lambda.events +package events + +import com.comcast.ip4s.Hostname +import org.typelevel.ci.CIString +import feral.lambda.KernelSource +import natchez.Kernel +import io.circe.Decoder +import codecs.decodeHostname +import codecs.decodeKeyCIString + +sealed abstract class RequestContext { + def resourceId: String + def resourcePath: String + def httpMethod: String + def extendedRequestId: String + def requestTime: String + def path: String + def accountId: String + def protocol: String + def stage: String + def domainPrefix: String + def requestTimeEpoch: Long + def requestId: String + def identity: Map[String, Option[String]] + def domainName: Hostname + def deploymentId: String + def apiId: String +} + +object RequestContext { + + def apply( + resourceId: String, + resourcePath: String, + httpMethod: String, + extendedRequestId: String, + requestTime: String, + path: String, + accountId: String, + protocol: String, + stage: String, + domainPrefix: String, + requestTimeEpoch: Long, + requestId: String, + identity: Map[String, Option[String]], + domainName: Hostname, + deploymentId: String, + apiId: String + ): RequestContext = + new Impl( + resourceId, + resourcePath, + httpMethod, + extendedRequestId, + requestTime, + path, + accountId, + protocol, + stage, + domainPrefix, + requestTimeEpoch, + requestId, + identity, + domainName, + deploymentId, + apiId + ) + + implicit def decoder: Decoder[RequestContext] = Decoder.forProduct16( + "resourceId", + "resourcePath", + "httpMethod", + "extendedRequestId", + "requestTime", + "path", + "accountId", + "protocol", + "stage", + "domainPrefix", + "requestTimeEpoch", + "requestId", + "identity", + "domainName", + "deploymentId", + "apiId" + )(RequestContext.apply) + + private case class Impl( + resourceId: String, + resourcePath: String, + httpMethod: String, + extendedRequestId: String, + requestTime: String, + path: String, + accountId: String, + protocol: String, + stage: String, + domainPrefix: String, + requestTimeEpoch: Long, + requestId: String, + identity: Map[String, Option[String]], + domainName: Hostname, + deploymentId: String, + apiId: String + ) extends RequestContext { + override def productPrefix = "RequestContext" + } +} + +sealed abstract class APIGatewayCustomAuthorizerEvent { + def `type`: String + def methodArn: String + def resource: String + def path: String + def httpMethod: String + def headers: Option[Map[CIString, String]] + def multiValueHeaders: Map[CIString, List[String]] + def queryStringParameters: Map[CIString, Option[String]] + def multiValueQueryStringParameters: Map[CIString, Option[List[String]]] + def pathParameters: Map[CIString, String] + def stageVariables: Map[CIString, String] + def requestContext: RequestContext +} + +object APIGatewayCustomAuthorizerEvent { + + def apply( + `type`: String, + methodArn: String, + resource: String, + path: String, + httpMethod: String, + headers: Option[Map[CIString, String]], + multiValueHeaders: Map[CIString, List[String]], + queryStringParameters: Map[CIString, Option[String]], + multiValueQueryStringParameters: Map[CIString, Option[List[String]]], + pathParameters: Map[CIString, String], + stageVariables: Map[CIString, String], + requestContext: RequestContext + ): APIGatewayCustomAuthorizerEvent = + new Impl( + `type`, + methodArn, + resource, + path, + httpMethod, + headers, + multiValueHeaders, + queryStringParameters, + multiValueQueryStringParameters, + pathParameters, + stageVariables, + requestContext + ) + + implicit def kernelSource: KernelSource[APIGatewayCustomAuthorizerEvent] = + e => Kernel(e.headers.getOrElse(Map.empty)) + + implicit def decoder: Decoder[APIGatewayCustomAuthorizerEvent] = Decoder.forProduct12( + "type", + "methodArn", + "resource", + "path", + "httpMethod", + "headers", + "multiValueHeaders", + "queryStringParameters", + "multiValueQueryStringParameters", + "pathParameters", + "stageVariables", + "requestContext" + )(APIGatewayCustomAuthorizerEvent.apply) + + private case class Impl( + `type`: String, + methodArn: String, + resource: String, + path: String, + httpMethod: String, + headers: Option[Map[CIString, String]], + multiValueHeaders: Map[CIString, List[String]], + queryStringParameters: Map[CIString, Option[String]], + multiValueQueryStringParameters: Map[CIString, Option[List[String]]], + pathParameters: Map[CIString, String], + stageVariables: Map[CIString, String], + requestContext: RequestContext + ) extends APIGatewayCustomAuthorizerEvent { + override def productPrefix = "APIGatewayCustomAuthorizerEvent" + } +} diff --git a/lambda/shared/src/main/scala/feral/lambda/events/APIGatewayCustomAuthorizerResult.scala b/lambda/shared/src/main/scala/feral/lambda/events/APIGatewayCustomAuthorizerResult.scala new file mode 100644 index 00000000..80081a9c --- /dev/null +++ b/lambda/shared/src/main/scala/feral/lambda/events/APIGatewayCustomAuthorizerResult.scala @@ -0,0 +1,94 @@ +/* + * Copyright 2021 Typelevel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package feral.lambda.events +package events + +import java.time.LocalDate +import io.circe.Decoder +import codecs.decodeDate + +sealed abstract class APIGatewayCustomAuthorizerEventResult { + def principalId: String + def policyDocument: PolicyDocument +} + +object APIGatewayCustomAuthorizerEventResult { + + def apply(principalId: String, policyDocument: PolicyDocument): APIGatewayCustomAuthorizerEventResult = + Impl(principalId, policyDocument) + + implicit def decoder: Decoder[APIGatewayCustomAuthorizerEventResult] = Decoder.forProduct2( + "principalId", + "policyDocument" + )(Impl.apply) + + private case class Impl( + principalId: String, + policyDocument: PolicyDocument + ) extends APIGatewayCustomAuthorizerEventResult { + override def productPrefix = "APIGatewayCustomAuthorizerEventResult" + } +} + +sealed abstract class PolicyDocument { + def version:LocalDate + def statement: List[Statement] +} + +object PolicyDocument { + def apply(version:LocalDate, statement: List[Statement]): PolicyDocument = + Impl(version, statement) + + implicit def decoder: Decoder[PolicyDocument] = Decoder.forProduct2( + "Version", + "Statement" + )(Impl.apply) + + private case class Impl( + version:LocalDate, + statement: List[Statement] + ) extends PolicyDocument { + override def productPrefix = "PolicyDocument" + } +} + +sealed abstract class Statement { + def action: String + def effect: String + def resource: String +} + +object Statement { + def apply(action: String, effect: String, resource: String): Statement = + Impl(action, effect, resource) + + implicit def decoder: Decoder[Statement] = Decoder.forProduct3( + "Action", + "Effect", + "Resource" + )(Impl.apply) + + private case class Impl( + action: String, + effect: String, + resource: String + ) extends Statement { + override def productPrefix = "Statement" + } +} + + diff --git a/lambda/shared/src/main/scala/feral/lambda/events/codecs.scala b/lambda/shared/src/main/scala/feral/lambda/events/codecs.scala index 44713caf..3d6a7900 100644 --- a/lambda/shared/src/main/scala/feral/lambda/events/codecs.scala +++ b/lambda/shared/src/main/scala/feral/lambda/events/codecs.scala @@ -25,6 +25,8 @@ import org.typelevel.ci.CIString import java.time.Instant import scala.util.Try +import java.time.format.DateTimeFormatter +import java.time.LocalDate private object codecs { @@ -38,6 +40,15 @@ private object codecs { } } + implicit def decodeDate: Decoder[java.time.LocalDate] = + Decoder.decodeString.emapTry { str => + val dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd") + + Try { + LocalDate.parse(str, dateFormatter) + } + } + implicit def decodeIpAddress: Decoder[IpAddress] = Decoder.decodeString.emap(IpAddress.fromString(_).toRight("Cannot parse IP address")) diff --git a/lambda/shared/src/test/scala/feral/lambda/events/APIGatewayCustomAuthorizerEventResultSuite.scala b/lambda/shared/src/test/scala/feral/lambda/events/APIGatewayCustomAuthorizerEventResultSuite.scala new file mode 100644 index 00000000..a51a176f --- /dev/null +++ b/lambda/shared/src/test/scala/feral/lambda/events/APIGatewayCustomAuthorizerEventResultSuite.scala @@ -0,0 +1,48 @@ +/* + * Copyright 2021 Typelevel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package feral.lambda.events + +import io.circe.literal._ +import munit.FunSuite +import feral.lambda.events.events.APIGatewayCustomAuthorizerEventResult + +class APIGatewayCustomAuthorizerEventResultSuite extends FunSuite { + + import APIGatewayCustomAuthorizerEventResultSuite._ + + test("decoder") { + event.as[APIGatewayCustomAuthorizerEventResult].toTry.get + } +} + +object APIGatewayCustomAuthorizerEventResultSuite { + def event = json""" + { + "principalId": "me", + "policyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "execute-api:Invoke", + "Effect": "Allow", + "Resource": "arn:aws:execute-api:us-east-1:677276103099:or71kuogm2/test/GET/" + } + ] + } + } + """ +} \ No newline at end of file diff --git a/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventSuite.scala b/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventSuite.scala new file mode 100644 index 00000000..a7550cea --- /dev/null +++ b/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventSuite.scala @@ -0,0 +1,122 @@ +/* + * Copyright 2021 Typelevel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package feral.lambda.events + +import io.circe.literal._ +import munit.FunSuite +import feral.lambda.events.events.APIGatewayCustomAuthorizerEvent + +class ApiGatewayCustomAuthorizerEventSuite extends FunSuite { + + import ApiGatewayCustomAuthorizerEventSuite._ + + test("decoder") { + event.as[APIGatewayCustomAuthorizerEvent].toTry.get + } +} + +object ApiGatewayCustomAuthorizerEventSuite { + def event = json""" + { + "type": "REQUEST", + "methodArn": "arn:aws:execute-api:us-east-1:677276103099:or71kuogm2/test/GET/", + "resource": "/", + "path": "/", + "httpMethod": "ANY", + "headers": { + "accept": "*/*", + "headerauth1": "headerValue1", + "Host": "or71kuogm2.execute-api.us-east-1.amazonaws.com", + "user-agent": "curl/7.81.0", + "X-Amzn-Trace-Id": "Root=1-69b199a4-2c09a07109124da13b8ff7b0", + "X-Forwarded-For": "102.176.65.68", + "X-Forwarded-Port": "443", + "X-Forwarded-Proto": "https" + }, + "multiValueHeaders": { + "accept": [ + "*/*" + ], + "headerauth1": [ + "headerValue1" + ], + "Host": [ + "or71kuogm2.execute-api.us-east-1.amazonaws.com" + ], + "user-agent": [ + "curl/7.81.0" + ], + "X-Amzn-Trace-Id": [ + "Root=1-69b199a4-2c09a07109124da13b8ff7b0" + ], + "X-Forwarded-For": [ + "102.176.65.68" + ], + "X-Forwarded-Port": [ + "443" + ], + "X-Forwarded-Proto": [ + "https" + ] + }, + "queryStringParameters": { + "QueryString1": "queryValue1" + }, + "multiValueQueryStringParameters": { + "QueryString1": [ + "queryValue1" + ] + }, + "pathParameters": {}, + "stageVariables": { + "StageVar1": "stageValue1" + }, + "requestContext": { + "resourceId": "8qkclnaedk", + "resourcePath": "/", + "httpMethod": "GET", + "extendedRequestId": "aETx1HJcIAMEGdw=", + "requestTime": "11/Mar/2026:16:34:44 +0000", + "path": "/test", + "accountId": "677276103099", + "protocol": "HTTP/1.1", + "stage": "test", + "domainPrefix": "or71kuogm2", + "requestTimeEpoch": 1773246884924, + "requestId": "b20e5103-7f01-4bef-9fa2-682889187b5b", + "identity": { + "cognitoIdentityPoolId": null, + "accountId": null, + "cognitoIdentityId": null, + "caller": null, + "sourceIp": "102.176.65.68", + "principalOrgId": null, + "accessKey": null, + "cognitoAuthenticationType": null, + "cognitoAuthenticationProvider": null, + "userArn": null, + "userAgent": "curl/7.81.0", + "user": null + }, + "domainName": "or71kuogm2.execute-api.us-east-1.amazonaws.com", + "deploymentId": "ltoy3m", + "apiId": "or71kuogm2" + } + } + + """ +} From 095daffb61be48b35d97753df54c115a1326cc4a Mon Sep 17 00:00:00 2001 From: Yummy-Yums Date: Thu, 12 Mar 2026 19:32:06 +0000 Subject: [PATCH 02/11] fix: fixed formatting errors --- .../APIGatewayCustomAuthorizerEvent.scala | 324 +++++++++--------- .../APIGatewayCustomAuthorizerResult.scala | 106 +++--- 2 files changed, 215 insertions(+), 215 deletions(-) diff --git a/lambda/shared/src/main/scala/feral/lambda/events/APIGatewayCustomAuthorizerEvent.scala b/lambda/shared/src/main/scala/feral/lambda/events/APIGatewayCustomAuthorizerEvent.scala index f8557c56..6de35795 100644 --- a/lambda/shared/src/main/scala/feral/lambda/events/APIGatewayCustomAuthorizerEvent.scala +++ b/lambda/shared/src/main/scala/feral/lambda/events/APIGatewayCustomAuthorizerEvent.scala @@ -15,7 +15,7 @@ */ package feral.lambda.events -package events +package events import com.comcast.ip4s.Hostname import org.typelevel.ci.CIString @@ -26,182 +26,182 @@ import codecs.decodeHostname import codecs.decodeKeyCIString sealed abstract class RequestContext { - def resourceId: String - def resourcePath: String - def httpMethod: String - def extendedRequestId: String - def requestTime: String - def path: String - def accountId: String - def protocol: String - def stage: String - def domainPrefix: String - def requestTimeEpoch: Long - def requestId: String - def identity: Map[String, Option[String]] - def domainName: Hostname - def deploymentId: String - def apiId: String + def resourceId: String + def resourcePath: String + def httpMethod: String + def extendedRequestId: String + def requestTime: String + def path: String + def accountId: String + def protocol: String + def stage: String + def domainPrefix: String + def requestTimeEpoch: Long + def requestId: String + def identity: Map[String, Option[String]] + def domainName: Hostname + def deploymentId: String + def apiId: String } object RequestContext { - def apply( - resourceId: String, - resourcePath: String, - httpMethod: String, - extendedRequestId: String, - requestTime: String, - path: String, - accountId: String, - protocol: String, - stage: String, - domainPrefix: String, - requestTimeEpoch: Long, - requestId: String, - identity: Map[String, Option[String]], - domainName: Hostname, - deploymentId: String, - apiId: String - ): RequestContext = - new Impl( - resourceId, - resourcePath, - httpMethod, - extendedRequestId, - requestTime, - path, - accountId, - protocol, - stage, - domainPrefix, - requestTimeEpoch, - requestId, - identity, - domainName, - deploymentId, - apiId - ) + def apply( + resourceId: String, + resourcePath: String, + httpMethod: String, + extendedRequestId: String, + requestTime: String, + path: String, + accountId: String, + protocol: String, + stage: String, + domainPrefix: String, + requestTimeEpoch: Long, + requestId: String, + identity: Map[String, Option[String]], + domainName: Hostname, + deploymentId: String, + apiId: String + ): RequestContext = + new Impl( + resourceId, + resourcePath, + httpMethod, + extendedRequestId, + requestTime, + path, + accountId, + protocol, + stage, + domainPrefix, + requestTimeEpoch, + requestId, + identity, + domainName, + deploymentId, + apiId + ) - implicit def decoder: Decoder[RequestContext] = Decoder.forProduct16( - "resourceId", - "resourcePath", - "httpMethod", - "extendedRequestId", - "requestTime", - "path", - "accountId", - "protocol", - "stage", - "domainPrefix", - "requestTimeEpoch", - "requestId", - "identity", - "domainName", - "deploymentId", - "apiId" - )(RequestContext.apply) + implicit def decoder: Decoder[RequestContext] = Decoder.forProduct16( + "resourceId", + "resourcePath", + "httpMethod", + "extendedRequestId", + "requestTime", + "path", + "accountId", + "protocol", + "stage", + "domainPrefix", + "requestTimeEpoch", + "requestId", + "identity", + "domainName", + "deploymentId", + "apiId" + )(RequestContext.apply) - private case class Impl( - resourceId: String, - resourcePath: String, - httpMethod: String, - extendedRequestId: String, - requestTime: String, - path: String, - accountId: String, - protocol: String, - stage: String, - domainPrefix: String, - requestTimeEpoch: Long, - requestId: String, - identity: Map[String, Option[String]], - domainName: Hostname, - deploymentId: String, - apiId: String - ) extends RequestContext { - override def productPrefix = "RequestContext" - } + private case class Impl( + resourceId: String, + resourcePath: String, + httpMethod: String, + extendedRequestId: String, + requestTime: String, + path: String, + accountId: String, + protocol: String, + stage: String, + domainPrefix: String, + requestTimeEpoch: Long, + requestId: String, + identity: Map[String, Option[String]], + domainName: Hostname, + deploymentId: String, + apiId: String + ) extends RequestContext { + override def productPrefix = "RequestContext" + } } sealed abstract class APIGatewayCustomAuthorizerEvent { - def `type`: String - def methodArn: String - def resource: String - def path: String - def httpMethod: String - def headers: Option[Map[CIString, String]] - def multiValueHeaders: Map[CIString, List[String]] - def queryStringParameters: Map[CIString, Option[String]] - def multiValueQueryStringParameters: Map[CIString, Option[List[String]]] - def pathParameters: Map[CIString, String] - def stageVariables: Map[CIString, String] - def requestContext: RequestContext + def `type`: String + def methodArn: String + def resource: String + def path: String + def httpMethod: String + def headers: Option[Map[CIString, String]] + def multiValueHeaders: Map[CIString, List[String]] + def queryStringParameters: Map[CIString, Option[String]] + def multiValueQueryStringParameters: Map[CIString, Option[List[String]]] + def pathParameters: Map[CIString, String] + def stageVariables: Map[CIString, String] + def requestContext: RequestContext } object APIGatewayCustomAuthorizerEvent { - def apply( - `type`: String, - methodArn: String, - resource: String, - path: String, - httpMethod: String, - headers: Option[Map[CIString, String]], - multiValueHeaders: Map[CIString, List[String]], - queryStringParameters: Map[CIString, Option[String]], - multiValueQueryStringParameters: Map[CIString, Option[List[String]]], - pathParameters: Map[CIString, String], - stageVariables: Map[CIString, String], - requestContext: RequestContext - ): APIGatewayCustomAuthorizerEvent = - new Impl( - `type`, - methodArn, - resource, - path, - httpMethod, - headers, - multiValueHeaders, - queryStringParameters, - multiValueQueryStringParameters, - pathParameters, - stageVariables, - requestContext - ) + def apply( + `type`: String, + methodArn: String, + resource: String, + path: String, + httpMethod: String, + headers: Option[Map[CIString, String]], + multiValueHeaders: Map[CIString, List[String]], + queryStringParameters: Map[CIString, Option[String]], + multiValueQueryStringParameters: Map[CIString, Option[List[String]]], + pathParameters: Map[CIString, String], + stageVariables: Map[CIString, String], + requestContext: RequestContext + ): APIGatewayCustomAuthorizerEvent = + new Impl( + `type`, + methodArn, + resource, + path, + httpMethod, + headers, + multiValueHeaders, + queryStringParameters, + multiValueQueryStringParameters, + pathParameters, + stageVariables, + requestContext + ) - implicit def kernelSource: KernelSource[APIGatewayCustomAuthorizerEvent] = + implicit def kernelSource: KernelSource[APIGatewayCustomAuthorizerEvent] = e => Kernel(e.headers.getOrElse(Map.empty)) - implicit def decoder: Decoder[APIGatewayCustomAuthorizerEvent] = Decoder.forProduct12( - "type", - "methodArn", - "resource", - "path", - "httpMethod", - "headers", - "multiValueHeaders", - "queryStringParameters", - "multiValueQueryStringParameters", - "pathParameters", - "stageVariables", - "requestContext" - )(APIGatewayCustomAuthorizerEvent.apply) + implicit def decoder: Decoder[APIGatewayCustomAuthorizerEvent] = Decoder.forProduct12( + "type", + "methodArn", + "resource", + "path", + "httpMethod", + "headers", + "multiValueHeaders", + "queryStringParameters", + "multiValueQueryStringParameters", + "pathParameters", + "stageVariables", + "requestContext" + )(APIGatewayCustomAuthorizerEvent.apply) - private case class Impl( - `type`: String, - methodArn: String, - resource: String, - path: String, - httpMethod: String, - headers: Option[Map[CIString, String]], - multiValueHeaders: Map[CIString, List[String]], - queryStringParameters: Map[CIString, Option[String]], - multiValueQueryStringParameters: Map[CIString, Option[List[String]]], - pathParameters: Map[CIString, String], - stageVariables: Map[CIString, String], - requestContext: RequestContext - ) extends APIGatewayCustomAuthorizerEvent { - override def productPrefix = "APIGatewayCustomAuthorizerEvent" - } + private case class Impl( + `type`: String, + methodArn: String, + resource: String, + path: String, + httpMethod: String, + headers: Option[Map[CIString, String]], + multiValueHeaders: Map[CIString, List[String]], + queryStringParameters: Map[CIString, Option[String]], + multiValueQueryStringParameters: Map[CIString, Option[List[String]]], + pathParameters: Map[CIString, String], + stageVariables: Map[CIString, String], + requestContext: RequestContext + ) extends APIGatewayCustomAuthorizerEvent { + override def productPrefix = "APIGatewayCustomAuthorizerEvent" + } } diff --git a/lambda/shared/src/main/scala/feral/lambda/events/APIGatewayCustomAuthorizerResult.scala b/lambda/shared/src/main/scala/feral/lambda/events/APIGatewayCustomAuthorizerResult.scala index 80081a9c..b970b98a 100644 --- a/lambda/shared/src/main/scala/feral/lambda/events/APIGatewayCustomAuthorizerResult.scala +++ b/lambda/shared/src/main/scala/feral/lambda/events/APIGatewayCustomAuthorizerResult.scala @@ -22,73 +22,73 @@ import io.circe.Decoder import codecs.decodeDate sealed abstract class APIGatewayCustomAuthorizerEventResult { - def principalId: String - def policyDocument: PolicyDocument + def principalId: String + def policyDocument: PolicyDocument } object APIGatewayCustomAuthorizerEventResult { - def apply(principalId: String, policyDocument: PolicyDocument): APIGatewayCustomAuthorizerEventResult = - Impl(principalId, policyDocument) - - implicit def decoder: Decoder[APIGatewayCustomAuthorizerEventResult] = Decoder.forProduct2( - "principalId", - "policyDocument" - )(Impl.apply) - - private case class Impl( - principalId: String, - policyDocument: PolicyDocument - ) extends APIGatewayCustomAuthorizerEventResult { - override def productPrefix = "APIGatewayCustomAuthorizerEventResult" - } + def apply( + principalId: String, + policyDocument: PolicyDocument): APIGatewayCustomAuthorizerEventResult = + Impl(principalId, policyDocument) + + implicit def decoder: Decoder[APIGatewayCustomAuthorizerEventResult] = Decoder.forProduct2( + "principalId", + "policyDocument" + )(Impl.apply) + + private case class Impl( + principalId: String, + policyDocument: PolicyDocument + ) extends APIGatewayCustomAuthorizerEventResult { + override def productPrefix = "APIGatewayCustomAuthorizerEventResult" + } } sealed abstract class PolicyDocument { - def version:LocalDate - def statement: List[Statement] + def version: LocalDate + def statement: List[Statement] } object PolicyDocument { - def apply(version:LocalDate, statement: List[Statement]): PolicyDocument = - Impl(version, statement) - - implicit def decoder: Decoder[PolicyDocument] = Decoder.forProduct2( - "Version", - "Statement" - )(Impl.apply) - - private case class Impl( - version:LocalDate, - statement: List[Statement] - ) extends PolicyDocument { - override def productPrefix = "PolicyDocument" - } + def apply(version: LocalDate, statement: List[Statement]): PolicyDocument = + Impl(version, statement) + + implicit def decoder: Decoder[PolicyDocument] = Decoder.forProduct2( + "Version", + "Statement" + )(Impl.apply) + + private case class Impl( + version: LocalDate, + statement: List[Statement] + ) extends PolicyDocument { + override def productPrefix = "PolicyDocument" + } } sealed abstract class Statement { - def action: String - def effect: String - def resource: String + def action: String + def effect: String + def resource: String } object Statement { - def apply(action: String, effect: String, resource: String): Statement = - Impl(action, effect, resource) - - implicit def decoder: Decoder[Statement] = Decoder.forProduct3( - "Action", - "Effect", - "Resource" - )(Impl.apply) - - private case class Impl( - action: String, - effect: String, - resource: String - ) extends Statement { - override def productPrefix = "Statement" - } + def apply(action: String, effect: String, resource: String): Statement = + Impl(action, effect, resource) + + implicit def decoder: Decoder[Statement] = Decoder.forProduct3( + "Action", + "Effect", + "Resource" + )(Impl.apply) + + private case class Impl( + action: String, + effect: String, + resource: String + ) extends Statement { + override def productPrefix = "Statement" + } } - - From f50b8a2fb19025694456e9d11130bface6917ddf Mon Sep 17 00:00:00 2001 From: Yummy-Yums Date: Thu, 12 Mar 2026 19:41:15 +0000 Subject: [PATCH 03/11] fix: fixed formatting errors for test fils --- .../events/APIGatewayCustomAuthorizerEventResultSuite.scala | 6 +++--- .../events/ApiGatewayCustomAuthorizerEventSuite.scala | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lambda/shared/src/test/scala/feral/lambda/events/APIGatewayCustomAuthorizerEventResultSuite.scala b/lambda/shared/src/test/scala/feral/lambda/events/APIGatewayCustomAuthorizerEventResultSuite.scala index a51a176f..db24c2c6 100644 --- a/lambda/shared/src/test/scala/feral/lambda/events/APIGatewayCustomAuthorizerEventResultSuite.scala +++ b/lambda/shared/src/test/scala/feral/lambda/events/APIGatewayCustomAuthorizerEventResultSuite.scala @@ -21,7 +21,7 @@ import munit.FunSuite import feral.lambda.events.events.APIGatewayCustomAuthorizerEventResult class APIGatewayCustomAuthorizerEventResultSuite extends FunSuite { - + import APIGatewayCustomAuthorizerEventResultSuite._ test("decoder") { @@ -30,7 +30,7 @@ class APIGatewayCustomAuthorizerEventResultSuite extends FunSuite { } object APIGatewayCustomAuthorizerEventResultSuite { - def event = json""" + def event = json""" { "principalId": "me", "policyDocument": { @@ -45,4 +45,4 @@ object APIGatewayCustomAuthorizerEventResultSuite { } } """ -} \ No newline at end of file +} diff --git a/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventSuite.scala b/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventSuite.scala index a7550cea..83374291 100644 --- a/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventSuite.scala +++ b/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventSuite.scala @@ -21,7 +21,7 @@ import munit.FunSuite import feral.lambda.events.events.APIGatewayCustomAuthorizerEvent class ApiGatewayCustomAuthorizerEventSuite extends FunSuite { - + import ApiGatewayCustomAuthorizerEventSuite._ test("decoder") { @@ -30,7 +30,7 @@ class ApiGatewayCustomAuthorizerEventSuite extends FunSuite { } object ApiGatewayCustomAuthorizerEventSuite { - def event = json""" + def event = json""" { "type": "REQUEST", "methodArn": "arn:aws:execute-api:us-east-1:677276103099:or71kuogm2/test/GET/", From 1129e135665b1f3ae48448ebe6c0e25d31e1d958 Mon Sep 17 00:00:00 2001 From: Yummy-Yums Date: Thu, 12 Mar 2026 19:51:22 +0000 Subject: [PATCH 04/11] fix: fixed linting errors for test fils --- .../lambda/events/APIGatewayCustomAuthorizerEvent.scala | 5 +++-- .../lambda/events/APIGatewayCustomAuthorizerResult.scala | 4 +++- .../shared/src/main/scala/feral/lambda/events/codecs.scala | 4 ++-- .../events/APIGatewayCustomAuthorizerEventResultSuite.scala | 2 +- .../lambda/events/ApiGatewayCustomAuthorizerEventSuite.scala | 2 +- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/lambda/shared/src/main/scala/feral/lambda/events/APIGatewayCustomAuthorizerEvent.scala b/lambda/shared/src/main/scala/feral/lambda/events/APIGatewayCustomAuthorizerEvent.scala index 6de35795..c4974495 100644 --- a/lambda/shared/src/main/scala/feral/lambda/events/APIGatewayCustomAuthorizerEvent.scala +++ b/lambda/shared/src/main/scala/feral/lambda/events/APIGatewayCustomAuthorizerEvent.scala @@ -18,10 +18,11 @@ package feral.lambda.events package events import com.comcast.ip4s.Hostname -import org.typelevel.ci.CIString import feral.lambda.KernelSource -import natchez.Kernel import io.circe.Decoder +import natchez.Kernel +import org.typelevel.ci.CIString + import codecs.decodeHostname import codecs.decodeKeyCIString diff --git a/lambda/shared/src/main/scala/feral/lambda/events/APIGatewayCustomAuthorizerResult.scala b/lambda/shared/src/main/scala/feral/lambda/events/APIGatewayCustomAuthorizerResult.scala index b970b98a..16f183dd 100644 --- a/lambda/shared/src/main/scala/feral/lambda/events/APIGatewayCustomAuthorizerResult.scala +++ b/lambda/shared/src/main/scala/feral/lambda/events/APIGatewayCustomAuthorizerResult.scala @@ -17,8 +17,10 @@ package feral.lambda.events package events -import java.time.LocalDate import io.circe.Decoder + +import java.time.LocalDate + import codecs.decodeDate sealed abstract class APIGatewayCustomAuthorizerEventResult { diff --git a/lambda/shared/src/main/scala/feral/lambda/events/codecs.scala b/lambda/shared/src/main/scala/feral/lambda/events/codecs.scala index 3d6a7900..b983e1fe 100644 --- a/lambda/shared/src/main/scala/feral/lambda/events/codecs.scala +++ b/lambda/shared/src/main/scala/feral/lambda/events/codecs.scala @@ -24,9 +24,9 @@ import io.circe.KeyEncoder import org.typelevel.ci.CIString import java.time.Instant -import scala.util.Try -import java.time.format.DateTimeFormatter import java.time.LocalDate +import java.time.format.DateTimeFormatter +import scala.util.Try private object codecs { diff --git a/lambda/shared/src/test/scala/feral/lambda/events/APIGatewayCustomAuthorizerEventResultSuite.scala b/lambda/shared/src/test/scala/feral/lambda/events/APIGatewayCustomAuthorizerEventResultSuite.scala index db24c2c6..908f0cf6 100644 --- a/lambda/shared/src/test/scala/feral/lambda/events/APIGatewayCustomAuthorizerEventResultSuite.scala +++ b/lambda/shared/src/test/scala/feral/lambda/events/APIGatewayCustomAuthorizerEventResultSuite.scala @@ -16,9 +16,9 @@ package feral.lambda.events +import feral.lambda.events.events.APIGatewayCustomAuthorizerEventResult import io.circe.literal._ import munit.FunSuite -import feral.lambda.events.events.APIGatewayCustomAuthorizerEventResult class APIGatewayCustomAuthorizerEventResultSuite extends FunSuite { diff --git a/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventSuite.scala b/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventSuite.scala index 83374291..c985cd98 100644 --- a/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventSuite.scala +++ b/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventSuite.scala @@ -16,9 +16,9 @@ package feral.lambda.events +import feral.lambda.events.events.APIGatewayCustomAuthorizerEvent import io.circe.literal._ import munit.FunSuite -import feral.lambda.events.events.APIGatewayCustomAuthorizerEvent class ApiGatewayCustomAuthorizerEventSuite extends FunSuite { From adde434c3ed23781a25057dca25684d91ad21190 Mon Sep 17 00:00:00 2001 From: Yummy-Yums Date: Sat, 14 Mar 2026 11:31:30 +0000 Subject: [PATCH 05/11] fix: changed results suite to use encoder --- ... => ApiGatewayCustomAuthorizerEvent.scala} | 26 +++++++------- ...=> ApiGatewayCustomAuthorizerResult.scala} | 26 +++++++------- .../scala/feral/lambda/events/codecs.scala | 11 +++--- ...wayCustomAuthorizerEventResultSuite.scala} | 34 ++++++++++++++----- ...ApiGatewayCustomAuthorizerEventSuite.scala | 4 +-- 5 files changed, 58 insertions(+), 43 deletions(-) rename lambda/shared/src/main/scala/feral/lambda/events/{APIGatewayCustomAuthorizerEvent.scala => ApiGatewayCustomAuthorizerEvent.scala} (90%) rename lambda/shared/src/main/scala/feral/lambda/events/{APIGatewayCustomAuthorizerResult.scala => ApiGatewayCustomAuthorizerResult.scala} (73%) rename lambda/shared/src/test/scala/feral/lambda/events/{APIGatewayCustomAuthorizerEventResultSuite.scala => ApiGatewayCustomAuthorizerEventResultSuite.scala} (51%) diff --git a/lambda/shared/src/main/scala/feral/lambda/events/APIGatewayCustomAuthorizerEvent.scala b/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEvent.scala similarity index 90% rename from lambda/shared/src/main/scala/feral/lambda/events/APIGatewayCustomAuthorizerEvent.scala rename to lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEvent.scala index c4974495..0f713a6b 100644 --- a/lambda/shared/src/main/scala/feral/lambda/events/APIGatewayCustomAuthorizerEvent.scala +++ b/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEvent.scala @@ -42,7 +42,7 @@ sealed abstract class RequestContext { def identity: Map[String, Option[String]] def domainName: Hostname def deploymentId: String - def apiId: String + def ApiId: String } object RequestContext { @@ -63,7 +63,7 @@ object RequestContext { identity: Map[String, Option[String]], domainName: Hostname, deploymentId: String, - apiId: String + ApiId: String ): RequestContext = new Impl( resourceId, @@ -81,7 +81,7 @@ object RequestContext { identity, domainName, deploymentId, - apiId + ApiId ) implicit def decoder: Decoder[RequestContext] = Decoder.forProduct16( @@ -100,7 +100,7 @@ object RequestContext { "identity", "domainName", "deploymentId", - "apiId" + "ApiId" )(RequestContext.apply) private case class Impl( @@ -119,13 +119,13 @@ object RequestContext { identity: Map[String, Option[String]], domainName: Hostname, deploymentId: String, - apiId: String + ApiId: String ) extends RequestContext { override def productPrefix = "RequestContext" } } -sealed abstract class APIGatewayCustomAuthorizerEvent { +sealed abstract class ApiGatewayCustomAuthorizerEvent { def `type`: String def methodArn: String def resource: String @@ -140,7 +140,7 @@ sealed abstract class APIGatewayCustomAuthorizerEvent { def requestContext: RequestContext } -object APIGatewayCustomAuthorizerEvent { +object ApiGatewayCustomAuthorizerEvent { def apply( `type`: String, @@ -155,7 +155,7 @@ object APIGatewayCustomAuthorizerEvent { pathParameters: Map[CIString, String], stageVariables: Map[CIString, String], requestContext: RequestContext - ): APIGatewayCustomAuthorizerEvent = + ): ApiGatewayCustomAuthorizerEvent = new Impl( `type`, methodArn, @@ -171,10 +171,10 @@ object APIGatewayCustomAuthorizerEvent { requestContext ) - implicit def kernelSource: KernelSource[APIGatewayCustomAuthorizerEvent] = + implicit def kernelSource: KernelSource[ApiGatewayCustomAuthorizerEvent] = e => Kernel(e.headers.getOrElse(Map.empty)) - implicit def decoder: Decoder[APIGatewayCustomAuthorizerEvent] = Decoder.forProduct12( + implicit def decoder: Decoder[ApiGatewayCustomAuthorizerEvent] = Decoder.forProduct12( "type", "methodArn", "resource", @@ -187,7 +187,7 @@ object APIGatewayCustomAuthorizerEvent { "pathParameters", "stageVariables", "requestContext" - )(APIGatewayCustomAuthorizerEvent.apply) + )(ApiGatewayCustomAuthorizerEvent.apply) private case class Impl( `type`: String, @@ -202,7 +202,7 @@ object APIGatewayCustomAuthorizerEvent { pathParameters: Map[CIString, String], stageVariables: Map[CIString, String], requestContext: RequestContext - ) extends APIGatewayCustomAuthorizerEvent { - override def productPrefix = "APIGatewayCustomAuthorizerEvent" + ) extends ApiGatewayCustomAuthorizerEvent { + override def productPrefix = "ApiGatewayCustomAuthorizerEvent" } } diff --git a/lambda/shared/src/main/scala/feral/lambda/events/APIGatewayCustomAuthorizerResult.scala b/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayCustomAuthorizerResult.scala similarity index 73% rename from lambda/shared/src/main/scala/feral/lambda/events/APIGatewayCustomAuthorizerResult.scala rename to lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayCustomAuthorizerResult.scala index 16f183dd..17644a0f 100644 --- a/lambda/shared/src/main/scala/feral/lambda/events/APIGatewayCustomAuthorizerResult.scala +++ b/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayCustomAuthorizerResult.scala @@ -17,34 +17,34 @@ package feral.lambda.events package events -import io.circe.Decoder +import io.circe.Encoder import java.time.LocalDate -import codecs.decodeDate +import codecs.encodeDate -sealed abstract class APIGatewayCustomAuthorizerEventResult { +sealed abstract class ApiGatewayCustomAuthorizerEventResult { def principalId: String def policyDocument: PolicyDocument } -object APIGatewayCustomAuthorizerEventResult { +object ApiGatewayCustomAuthorizerEventResult { def apply( principalId: String, - policyDocument: PolicyDocument): APIGatewayCustomAuthorizerEventResult = + policyDocument: PolicyDocument): ApiGatewayCustomAuthorizerEventResult = Impl(principalId, policyDocument) - implicit def decoder: Decoder[APIGatewayCustomAuthorizerEventResult] = Decoder.forProduct2( + implicit def encoder: Encoder[ApiGatewayCustomAuthorizerEventResult] = Encoder.forProduct2( "principalId", "policyDocument" - )(Impl.apply) + )(r => (r.principalId, r.policyDocument)) private case class Impl( principalId: String, policyDocument: PolicyDocument - ) extends APIGatewayCustomAuthorizerEventResult { - override def productPrefix = "APIGatewayCustomAuthorizerEventResult" + ) extends ApiGatewayCustomAuthorizerEventResult { + override def productPrefix = "ApiGatewayCustomAuthorizerEventResult" } } @@ -57,10 +57,10 @@ object PolicyDocument { def apply(version: LocalDate, statement: List[Statement]): PolicyDocument = Impl(version, statement) - implicit def decoder: Decoder[PolicyDocument] = Decoder.forProduct2( + implicit def encoder: Encoder[PolicyDocument] = Encoder.forProduct2( "Version", "Statement" - )(Impl.apply) + )(r => (r.version, r.statement)) private case class Impl( version: LocalDate, @@ -80,11 +80,11 @@ object Statement { def apply(action: String, effect: String, resource: String): Statement = Impl(action, effect, resource) - implicit def decoder: Decoder[Statement] = Decoder.forProduct3( + implicit def encoder: Encoder[Statement] = Encoder.forProduct3( "Action", "Effect", "Resource" - )(Impl.apply) + )(r => (r.action, r.effect, r.resource)) private case class Impl( action: String, diff --git a/lambda/shared/src/main/scala/feral/lambda/events/codecs.scala b/lambda/shared/src/main/scala/feral/lambda/events/codecs.scala index b983e1fe..6b64dad2 100644 --- a/lambda/shared/src/main/scala/feral/lambda/events/codecs.scala +++ b/lambda/shared/src/main/scala/feral/lambda/events/codecs.scala @@ -19,12 +19,12 @@ package feral.lambda.events import com.comcast.ip4s.Hostname import com.comcast.ip4s.IpAddress import io.circe.Decoder +import io.circe.Encoder import io.circe.KeyDecoder import io.circe.KeyEncoder import org.typelevel.ci.CIString import java.time.Instant -import java.time.LocalDate import java.time.format.DateTimeFormatter import scala.util.Try @@ -40,13 +40,10 @@ private object codecs { } } - implicit def decodeDate: Decoder[java.time.LocalDate] = - Decoder.decodeString.emapTry { str => + implicit def encodeDate: Encoder[java.time.LocalDate] = + Encoder.encodeString.contramap { str => val dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd") - - Try { - LocalDate.parse(str, dateFormatter) - } + str.format(dateFormatter) } implicit def decodeIpAddress: Decoder[IpAddress] = diff --git a/lambda/shared/src/test/scala/feral/lambda/events/APIGatewayCustomAuthorizerEventResultSuite.scala b/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventResultSuite.scala similarity index 51% rename from lambda/shared/src/test/scala/feral/lambda/events/APIGatewayCustomAuthorizerEventResultSuite.scala rename to lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventResultSuite.scala index 908f0cf6..3a014eed 100644 --- a/lambda/shared/src/test/scala/feral/lambda/events/APIGatewayCustomAuthorizerEventResultSuite.scala +++ b/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventResultSuite.scala @@ -16,20 +16,38 @@ package feral.lambda.events -import feral.lambda.events.events.APIGatewayCustomAuthorizerEventResult +import feral.lambda.events.events.ApiGatewayCustomAuthorizerEventResult +import feral.lambda.events.events.PolicyDocument +import feral.lambda.events.events.Statement import io.circe.literal._ +import io.circe.syntax._ import munit.FunSuite -class APIGatewayCustomAuthorizerEventResultSuite extends FunSuite { +class ApiGatewayCustomAuthorizerEventResultSuite extends FunSuite { - import APIGatewayCustomAuthorizerEventResultSuite._ + import ApiGatewayCustomAuthorizerEventResultSuite._ + val policyDocument = PolicyDocument( + version = java.time.LocalDate.parse("2012-10-17"), + statement = List( + Statement( + action = "execute-Api:Invoke", + effect = "Allow", + resource = "arn:aws:execute-Api:us-east-1:677276103099:or71kuogm2/test/GET/" + ) + ) + ) - test("decoder") { - event.as[APIGatewayCustomAuthorizerEventResult].toTry.get + val result = ApiGatewayCustomAuthorizerEventResult( + principalId = "me", + policyDocument = policyDocument + ) + + test("encoder") { + assertEquals(event, result.asJson) } } -object APIGatewayCustomAuthorizerEventResultSuite { +object ApiGatewayCustomAuthorizerEventResultSuite { def event = json""" { "principalId": "me", @@ -37,9 +55,9 @@ object APIGatewayCustomAuthorizerEventResultSuite { "Version": "2012-10-17", "Statement": [ { - "Action": "execute-api:Invoke", + "Action": "execute-Api:Invoke", "Effect": "Allow", - "Resource": "arn:aws:execute-api:us-east-1:677276103099:or71kuogm2/test/GET/" + "Resource": "arn:aws:execute-Api:us-east-1:677276103099:or71kuogm2/test/GET/" } ] } diff --git a/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventSuite.scala b/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventSuite.scala index c985cd98..fd0fb9d1 100644 --- a/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventSuite.scala +++ b/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventSuite.scala @@ -16,7 +16,7 @@ package feral.lambda.events -import feral.lambda.events.events.APIGatewayCustomAuthorizerEvent +import feral.lambda.events.events.ApiGatewayCustomAuthorizerEvent import io.circe.literal._ import munit.FunSuite @@ -25,7 +25,7 @@ class ApiGatewayCustomAuthorizerEventSuite extends FunSuite { import ApiGatewayCustomAuthorizerEventSuite._ test("decoder") { - event.as[APIGatewayCustomAuthorizerEvent].toTry.get + event.as[ApiGatewayCustomAuthorizerEvent].toTry.get } } From 1e45212fb91be8ef05aca8b24d594ba6f20af570 Mon Sep 17 00:00:00 2001 From: Yummy-Yums Date: Sat, 14 Mar 2026 12:02:10 +0000 Subject: [PATCH 06/11] resolved CI errors --- .../events/ApiGatewayCustomAuthorizerEvent.scala | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEvent.scala b/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEvent.scala index 0f713a6b..5579ab66 100644 --- a/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEvent.scala +++ b/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEvent.scala @@ -42,7 +42,7 @@ sealed abstract class RequestContext { def identity: Map[String, Option[String]] def domainName: Hostname def deploymentId: String - def ApiId: String + def apiId: String } object RequestContext { @@ -63,7 +63,7 @@ object RequestContext { identity: Map[String, Option[String]], domainName: Hostname, deploymentId: String, - ApiId: String + apiId: String ): RequestContext = new Impl( resourceId, @@ -81,7 +81,7 @@ object RequestContext { identity, domainName, deploymentId, - ApiId + apiId ) implicit def decoder: Decoder[RequestContext] = Decoder.forProduct16( @@ -100,7 +100,7 @@ object RequestContext { "identity", "domainName", "deploymentId", - "ApiId" + "apiId" )(RequestContext.apply) private case class Impl( @@ -119,7 +119,7 @@ object RequestContext { identity: Map[String, Option[String]], domainName: Hostname, deploymentId: String, - ApiId: String + apiId: String ) extends RequestContext { override def productPrefix = "RequestContext" } From 50bf1aeaaea162b93d33e015d603f1bade7698d1 Mon Sep 17 00:00:00 2001 From: Yummy-Yums Date: Sat, 14 Mar 2026 12:27:09 +0000 Subject: [PATCH 07/11] renamed requext context to avoid confusion --- .../ApiGatewayCustomAuthorizerEvent.scala | 22 +++++++++---------- .../ApiGatewayCustomAuthorizerResult.scala | 2 +- ...ewayCustomAuthorizerEventResultSuite.scala | 4 +--- ...ApiGatewayCustomAuthorizerEventSuite.scala | 2 +- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEvent.scala b/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEvent.scala index 5579ab66..07a18e99 100644 --- a/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEvent.scala +++ b/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEvent.scala @@ -14,7 +14,7 @@ * limitations under the License. */ -package feral.lambda.events +package feral.lambda package events import com.comcast.ip4s.Hostname @@ -26,7 +26,7 @@ import org.typelevel.ci.CIString import codecs.decodeHostname import codecs.decodeKeyCIString -sealed abstract class RequestContext { +sealed abstract class AuthorizerRequestContext { def resourceId: String def resourcePath: String def httpMethod: String @@ -45,7 +45,7 @@ sealed abstract class RequestContext { def apiId: String } -object RequestContext { +object AuthorizerRequestContext { def apply( resourceId: String, @@ -64,7 +64,7 @@ object RequestContext { domainName: Hostname, deploymentId: String, apiId: String - ): RequestContext = + ): AuthorizerRequestContext = new Impl( resourceId, resourcePath, @@ -84,7 +84,7 @@ object RequestContext { apiId ) - implicit def decoder: Decoder[RequestContext] = Decoder.forProduct16( + implicit def decoder: Decoder[AuthorizerRequestContext] = Decoder.forProduct16( "resourceId", "resourcePath", "httpMethod", @@ -101,7 +101,7 @@ object RequestContext { "domainName", "deploymentId", "apiId" - )(RequestContext.apply) + )(AuthorizerRequestContext.apply) private case class Impl( resourceId: String, @@ -120,8 +120,8 @@ object RequestContext { domainName: Hostname, deploymentId: String, apiId: String - ) extends RequestContext { - override def productPrefix = "RequestContext" + ) extends AuthorizerRequestContext { + override def productPrefix = "AuthorizerRequestContext" } } @@ -137,7 +137,7 @@ sealed abstract class ApiGatewayCustomAuthorizerEvent { def multiValueQueryStringParameters: Map[CIString, Option[List[String]]] def pathParameters: Map[CIString, String] def stageVariables: Map[CIString, String] - def requestContext: RequestContext + def requestContext: AuthorizerRequestContext } object ApiGatewayCustomAuthorizerEvent { @@ -154,7 +154,7 @@ object ApiGatewayCustomAuthorizerEvent { multiValueQueryStringParameters: Map[CIString, Option[List[String]]], pathParameters: Map[CIString, String], stageVariables: Map[CIString, String], - requestContext: RequestContext + requestContext: AuthorizerRequestContext ): ApiGatewayCustomAuthorizerEvent = new Impl( `type`, @@ -201,7 +201,7 @@ object ApiGatewayCustomAuthorizerEvent { multiValueQueryStringParameters: Map[CIString, Option[List[String]]], pathParameters: Map[CIString, String], stageVariables: Map[CIString, String], - requestContext: RequestContext + requestContext: AuthorizerRequestContext ) extends ApiGatewayCustomAuthorizerEvent { override def productPrefix = "ApiGatewayCustomAuthorizerEvent" } diff --git a/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayCustomAuthorizerResult.scala b/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayCustomAuthorizerResult.scala index 17644a0f..7b684b61 100644 --- a/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayCustomAuthorizerResult.scala +++ b/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayCustomAuthorizerResult.scala @@ -14,7 +14,7 @@ * limitations under the License. */ -package feral.lambda.events +package feral.lambda package events import io.circe.Encoder diff --git a/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventResultSuite.scala b/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventResultSuite.scala index 3a014eed..8b5f3bdc 100644 --- a/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventResultSuite.scala +++ b/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventResultSuite.scala @@ -14,11 +14,9 @@ * limitations under the License. */ + package feral.lambda.events -import feral.lambda.events.events.ApiGatewayCustomAuthorizerEventResult -import feral.lambda.events.events.PolicyDocument -import feral.lambda.events.events.Statement import io.circe.literal._ import io.circe.syntax._ import munit.FunSuite diff --git a/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventSuite.scala b/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventSuite.scala index fd0fb9d1..4103aa7c 100644 --- a/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventSuite.scala +++ b/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventSuite.scala @@ -16,7 +16,7 @@ package feral.lambda.events -import feral.lambda.events.events.ApiGatewayCustomAuthorizerEvent +import feral.lambda.events.ApiGatewayCustomAuthorizerEvent import io.circe.literal._ import munit.FunSuite From c56c8cef1085a357b621cdc5d5259f9ff9d93d14 Mon Sep 17 00:00:00 2001 From: Yummy-Yums Date: Sat, 14 Mar 2026 12:34:16 +0000 Subject: [PATCH 08/11] fix: header checks --- .../events/ApiGatewayCustomAuthorizerEventResultSuite.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventResultSuite.scala b/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventResultSuite.scala index 8b5f3bdc..be6ce716 100644 --- a/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventResultSuite.scala +++ b/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventResultSuite.scala @@ -14,7 +14,6 @@ * limitations under the License. */ - package feral.lambda.events import io.circe.literal._ From 4bf57ad702f6fcdad886ef7380ffccd77d3836de Mon Sep 17 00:00:00 2001 From: Yummy-Yums Date: Sat, 14 Mar 2026 12:37:53 +0000 Subject: [PATCH 09/11] resolved CI error --- .../events/ApiGatewayCustomAuthorizerEventResultSuite.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventResultSuite.scala b/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventResultSuite.scala index be6ce716..6ce2861f 100644 --- a/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventResultSuite.scala +++ b/lambda/shared/src/test/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventResultSuite.scala @@ -40,7 +40,7 @@ class ApiGatewayCustomAuthorizerEventResultSuite extends FunSuite { ) test("encoder") { - assertEquals(event, result.asJson) + assertEquals(event, result.asJson) } } From 80d98e8496d490be5a7346b59645a5c45be53dcc Mon Sep 17 00:00:00 2001 From: Yummy-Yums Date: Fri, 19 Jun 2026 13:18:11 +0000 Subject: [PATCH 10/11] change type to custom object --- .../ApiGatewayCustomAuthorizerEvent.scala | 21 +++- .../ApiGatewayCustomAuthorizerResult.scala | 96 ------------------- 2 files changed, 17 insertions(+), 100 deletions(-) delete mode 100644 lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayCustomAuthorizerResult.scala diff --git a/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEvent.scala b/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEvent.scala index 07a18e99..5faa9592 100644 --- a/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEvent.scala +++ b/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEvent.scala @@ -126,7 +126,7 @@ object AuthorizerRequestContext { } sealed abstract class ApiGatewayCustomAuthorizerEvent { - def `type`: String + def eventType: CustomAuthorizerEventType def methodArn: String def resource: String def path: String @@ -143,7 +143,7 @@ sealed abstract class ApiGatewayCustomAuthorizerEvent { object ApiGatewayCustomAuthorizerEvent { def apply( - `type`: String, + eventType: CustomAuthorizerEventType, methodArn: String, resource: String, path: String, @@ -157,7 +157,7 @@ object ApiGatewayCustomAuthorizerEvent { requestContext: AuthorizerRequestContext ): ApiGatewayCustomAuthorizerEvent = new Impl( - `type`, + eventType, methodArn, resource, path, @@ -190,7 +190,7 @@ object ApiGatewayCustomAuthorizerEvent { )(ApiGatewayCustomAuthorizerEvent.apply) private case class Impl( - `type`: String, + eventType: CustomAuthorizerEventType, methodArn: String, resource: String, path: String, @@ -206,3 +206,16 @@ object ApiGatewayCustomAuthorizerEvent { override def productPrefix = "ApiGatewayCustomAuthorizerEvent" } } + +sealed abstract class CustomAuthorizerEventType + +object CustomAuthorizerEventType { + case object Token extends CustomAuthorizerEventType + case object Request extends CustomAuthorizerEventType + + private[events] implicit val decoder: Decoder[CustomAuthorizerEventType] = + Decoder.decodeString.map { + case "TOKEN" => Token + case "REQUEST" => Request + } +} diff --git a/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayCustomAuthorizerResult.scala b/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayCustomAuthorizerResult.scala deleted file mode 100644 index 7b684b61..00000000 --- a/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayCustomAuthorizerResult.scala +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2021 Typelevel - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package feral.lambda -package events - -import io.circe.Encoder - -import java.time.LocalDate - -import codecs.encodeDate - -sealed abstract class ApiGatewayCustomAuthorizerEventResult { - def principalId: String - def policyDocument: PolicyDocument -} - -object ApiGatewayCustomAuthorizerEventResult { - - def apply( - principalId: String, - policyDocument: PolicyDocument): ApiGatewayCustomAuthorizerEventResult = - Impl(principalId, policyDocument) - - implicit def encoder: Encoder[ApiGatewayCustomAuthorizerEventResult] = Encoder.forProduct2( - "principalId", - "policyDocument" - )(r => (r.principalId, r.policyDocument)) - - private case class Impl( - principalId: String, - policyDocument: PolicyDocument - ) extends ApiGatewayCustomAuthorizerEventResult { - override def productPrefix = "ApiGatewayCustomAuthorizerEventResult" - } -} - -sealed abstract class PolicyDocument { - def version: LocalDate - def statement: List[Statement] -} - -object PolicyDocument { - def apply(version: LocalDate, statement: List[Statement]): PolicyDocument = - Impl(version, statement) - - implicit def encoder: Encoder[PolicyDocument] = Encoder.forProduct2( - "Version", - "Statement" - )(r => (r.version, r.statement)) - - private case class Impl( - version: LocalDate, - statement: List[Statement] - ) extends PolicyDocument { - override def productPrefix = "PolicyDocument" - } -} - -sealed abstract class Statement { - def action: String - def effect: String - def resource: String -} - -object Statement { - def apply(action: String, effect: String, resource: String): Statement = - Impl(action, effect, resource) - - implicit def encoder: Encoder[Statement] = Encoder.forProduct3( - "Action", - "Effect", - "Resource" - )(r => (r.action, r.effect, r.resource)) - - private case class Impl( - action: String, - effect: String, - resource: String - ) extends Statement { - override def productPrefix = "Statement" - } -} From 2aed831f8ba188de4bae9192fbf183b4398e3fa7 Mon Sep 17 00:00:00 2001 From: Yummy-Yums Date: Fri, 19 Jun 2026 13:35:54 +0000 Subject: [PATCH 11/11] resolve CI error --- ...piGatewayCustomAuthorizerEventResult.scala | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventResult.scala diff --git a/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventResult.scala b/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventResult.scala new file mode 100644 index 00000000..7b684b61 --- /dev/null +++ b/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayCustomAuthorizerEventResult.scala @@ -0,0 +1,96 @@ +/* + * Copyright 2021 Typelevel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package feral.lambda +package events + +import io.circe.Encoder + +import java.time.LocalDate + +import codecs.encodeDate + +sealed abstract class ApiGatewayCustomAuthorizerEventResult { + def principalId: String + def policyDocument: PolicyDocument +} + +object ApiGatewayCustomAuthorizerEventResult { + + def apply( + principalId: String, + policyDocument: PolicyDocument): ApiGatewayCustomAuthorizerEventResult = + Impl(principalId, policyDocument) + + implicit def encoder: Encoder[ApiGatewayCustomAuthorizerEventResult] = Encoder.forProduct2( + "principalId", + "policyDocument" + )(r => (r.principalId, r.policyDocument)) + + private case class Impl( + principalId: String, + policyDocument: PolicyDocument + ) extends ApiGatewayCustomAuthorizerEventResult { + override def productPrefix = "ApiGatewayCustomAuthorizerEventResult" + } +} + +sealed abstract class PolicyDocument { + def version: LocalDate + def statement: List[Statement] +} + +object PolicyDocument { + def apply(version: LocalDate, statement: List[Statement]): PolicyDocument = + Impl(version, statement) + + implicit def encoder: Encoder[PolicyDocument] = Encoder.forProduct2( + "Version", + "Statement" + )(r => (r.version, r.statement)) + + private case class Impl( + version: LocalDate, + statement: List[Statement] + ) extends PolicyDocument { + override def productPrefix = "PolicyDocument" + } +} + +sealed abstract class Statement { + def action: String + def effect: String + def resource: String +} + +object Statement { + def apply(action: String, effect: String, resource: String): Statement = + Impl(action, effect, resource) + + implicit def encoder: Encoder[Statement] = Encoder.forProduct3( + "Action", + "Effect", + "Resource" + )(r => (r.action, r.effect, r.resource)) + + private case class Impl( + action: String, + effect: String, + resource: String + ) extends Statement { + override def productPrefix = "Statement" + } +}