swift-aws-lambda-runtime
swift-aws-lambda-runtime copied to clipboard
Make local lambda server configurable
Motivation
We want to be able to mock different aws service behaviors with the Lambda.LocalServer
.
Changes
- The
Lambda.LocalServer
now opens two ports: One for incoming requests (InvokeHandler
) and one for the control plane API (ControlPlaneHandler
) - The
ServerState
(please hand me ideas for better names) encapsulates all the "business" logic: Queueing incoming requests, ensuring control plane state, ... - The user can implement the
LocalLambdaInvocationProxy
protocol to mock the behavior of different aws services - a default
InvokeProxy
is included - The server has been moved to the
AWSLambdaTesting
target, since we want to be able to access AWSLambdaEvents, if we implement anAPIGatewayV2Proxy
what is the status of this PR? It would be useful to have it...
@pokryfka the work on this pr has stopped, since we chose to go a different route with configuring the LocalServer. Since the LocalServer is now automatically started if the ENV variable is set, we need to find a different way. One idea is to provide a bootstrap method like in swift-logging to configure the LocalServer before actual startup. Does this make sense?
@pokryfka the work on this pr has stopped, since we chose to go a different route with configuring the LocalServer. Since the LocalServer is now automatically started if the ENV variable is set, we need to find a different way. One idea is to provide a bootstrap method like in swift-logging to configure the LocalServer before actual startup. Does this make sense?
So the bootstrap function (static method) and LocalLambdaInvocationProxy
protocol would be public and remain in AWSLambdaRuntimeCore
, something like:
public protocol LocalLambdaInvocationProxy {
// ...
}
public enum LocalLambda {
public static func bootstrap(_ proxyType: LocalLambdaInvocationProxy.Type) {
// ...
}
}
Now APIGatewayV2Proxy
depends on AWSLambdaEvents
and needs JSON encoder and decoder. It would be defined in AWSLambdaTesting
.
Then if user wants to mock API Gateway he would need to import AWSLambdaTesting
(?):
#if DEBUG
import AWSLambdaTesting
LocalLambda.bootstrap(APIGatewayV2Proxy.self)
#endif
// this will run LocalLambda.Server if DEBUG and LOCAL_LAMBDA_SERVER_ENABLED is "true"
Lambda.run(APIGatewayProxyLambda())
@fabianfett is that what you had in mind?
on top of that, it would probably be convenient to have a few proxies (API Gateway V1 and V2) defined (in AWSLambdaRuntime
?) and configurable using env variable:
LOCAL_LAMBDA_SERVER_PROXY_TYPE=invoke // or api, api2
I just noticed MockLambdaServer
and HTTPHandler
in LambdaRuntimeClientTest
look very much the same as the LocalLambda:Server
and LocalLambdaInvocationProxy
is almost the same as LambdaServerBehavior
(with one using NIO
future and the other Result
).
Perhaps one more advantage of the approach in the PR could be (a possibility of) an implementation of a MockProxy
used in tests instead of MockLambdaServer
which in turn would make the local lambda server better tested.
public protocol LocalLambdaInvocationProxy {
init(eventLoop: EventLoop)
/// throws HTTPError
func invocation(from request: HTTPRequest) -> EventLoopFuture<ByteBuffer>
func processResult(_ result: ByteBuffer?) -> EventLoopFuture<HTTPResponse>
func processError(_ error: ByteBuffer?) -> EventLoopFuture<HTTPResponse>
}
internal protocol LambdaServerBehavior {
func getInvocation() -> GetInvocationResult
func processResponse(requestId: String, response: String?) -> Result<Void, ProcessResponseError>
func processError(requestId: String, error: ErrorResponse) -> Result<Void, ProcessErrorError>
func processInitError(error: ErrorResponse) -> Result<Void, ProcessErrorError>
}
Perhaps one more advantage of the approach in the PR could be (a possibility of) an implementation of a MockProxy used in tests instead of MockLambdaServer which in turn would make the local lambda server better tested.
I really like this approach. imo the priority is:
- come up with a good system to inject middleware for
LocalLambda:Server
to more easily test scenarios like API Gateway. - refactor the testing the facilities to use
LocalLambda:Server
instead ofMockLambdaServer
(and removeMockLambdaServer
if possible)
@pokryfka @fabianfett wdyt?
@fabianfett what are your thoughts on that?
I could help with that and:
- sync the branch with master,
- create static
LocalLambda.bootstrap
function as described above - implement
APIGatewayProxyLambda
usingAPIGatewayMapping
from https://github.com/swift-server/swift-aws-lambda-runtime/pull/138
@pokryfka I'd be excited if you could help out here. Go ahead! Maybe we should try to split the changes in small prs so we don't end up with such a big one like the one we have here.
@fabianfett @tomerd please check the change on https://github.com/swift-server/swift-aws-lambda-runtime/pull/138
(I dont think I could push to feature/ff-local-invoke-configurable
and It would probably not make sense to make a PR to a branch which is not in sync with master
?)
@fabianfett could you please update this PR to be against the main
branch so we can delete the old master
branch
closing in inactive PRs, feel free to re-open if still relevant