swift-server / swift-aws-lambda-runtime

Swift implementation of AWS Lambda Runtime
Apache License 2.0
1.12k stars 101 forks source link

Improves Developer Ergonomics for LambdaHandler Conformances #272

Closed hectormatos2011 closed 1 year ago

hectormatos2011 commented 1 year ago

This PR aims to improve developer ergonomics for simple LambdaHandler conformances when trying to quickly put together a local server to test against.

Motivation:

Swift 5.7 added primary associated types for protocols where you can start using generic bracket syntax for protocols. An issue for this was opened not too long ago in this repo (#266) with the primary motivation of improving developer ergonomics around types conforming to LambdaHander. However, swift's type inference system should be able to handle the aforementioned issue just fine without using primary associated types (although support for that could still be useful when defining properties conforming to LambdaHandler when you want to constrain the types).

Swift's type inference system does not pick up the Event and Output types for objects conforming to LambdaHandler because those types are defined in the covariant protocol EventLoopLambdaHandler. This means that you need to add type aliases for Event and Output when conforming to LambdaHandler - resulting in less than ideal developer ergonomics when trying to spin up a quick little local server.

Additionally, the initializer for LambdaHandler is currently a required function in the protocol. This is super useful for setup logic for your Handlers but degrades the developer ergonomics of the most simple/minimal use-case for LambdaHandlers. Developers should be able to continue having the capability of writing simple lambda handlers like they could do in 0.5.2:

import AWSLambdaRuntime
import Foundation

Lambda.run { (context, input: Request, callback: @escaping (Result<String, Error>) -> Void) in
    callback(.success(...))
}

The current state of affairs in comparison is to explicitly define the Event and Output associated types of LambdaHandler when writing a simple lambda as well as being forced to include an init that isn't necessarily always required to successfully run a simple lambda:

import AWSLambdaRuntime
import Foundation

@main
struct EntryHandler: LambdaHandler {
    typealias Event = SomeCodableEventType
    typealias Output = SomeCodableOutputType

    init(context: AWSLambdaRuntimeCore.LambdaInitializationContext) async throws {
        // The body of this could be blank and the lambda would still work
    }

    func handle(_ event: Event, context: LambdaContext) async throws -> Output {
        // lambda logic
    }
}

With the changes on main, a developer loses the ease of writing a three-line lambda that they could do in 0.5.2.

On top of all of this, when needing to run a server locally in Xcode, a developer would need to add an environment variable to their local scheme. This isn't a much used feature in Xcode for developers coming from iOS who are looking to maybe start writing swift on the server. This isn't too big of a deal, but could be a bit of pain to do when trying to set yourself up with Lambda for the first time. It also introduces the possibility of having to manage two different environment variables if you're switching between debugging in Xcode or running the server locally in your Terminal. It would be nice to have the capability of defining this in code so a developer wouldn't have to open a separate window to toggle a server running locally.

I may be wrong about this (not a lot of experience writing swift on the server), but if a developer is running a local server in Xcode, it should be safe to assume that the server isn't running on an environment like AWS Lambda or Docker. I think that if a server is running their Lambda in Xcode, LOCAL_LAMBDA_SERVER_ENABLED should be enabled by default. Doing so would enable developers to package ready-to-go example local servers with their example mobile apps (maybe they want to demonstrate the usage of an SDK or something).

Currently, developers in this situation would have to instruct their users to set up this LOCAL_LAMBDA_SERVER_ENABLED environment variable. If a user is a swift developer already, they might have the urge to open that Package in Xcode and just hit run without knowing they need to set that variable up.

With the support of a variable for enabling running as a local server in Lambda directly, a developer could package a ready-to-go local server package with their example apps that would only require opening the package and running in Xcode with no extra set up.

Modifications:

Result:

With all of the changes in this PR, a developer could package a local lambda handler Swift Package with an example app that could look like this:

@main
final class EntryHandler: LambdaHandler {
    func handle(request: YourDecodableRequest, context: LambdaContext) -> YourEncodableResponse {
        // lambda logic
    }
}

All previous logic is still retained but the optional code needed is now opt-in with sensible defaults.

swift-server-bot commented 1 year ago

Can one of the admins verify this patch?

swift-server-bot commented 1 year ago

Can one of the admins verify this patch?

swift-server-bot commented 1 year ago

Can one of the admins verify this patch?

swift-server-bot commented 1 year ago

Can one of the admins verify this patch?

swift-server-bot commented 1 year ago

Can one of the admins verify this patch?

swift-server-bot commented 1 year ago

Can one of the admins verify this patch?

swift-server-bot commented 1 year ago

Can one of the admins verify this patch?

swift-server-bot commented 1 year ago

Can one of the admins verify this patch?

swift-server-bot commented 1 year ago

Can one of the admins verify this patch?

swift-server-bot commented 1 year ago

Can one of the admins verify this patch?

swift-server-bot commented 1 year ago

Can one of the admins verify this patch?

swift-server-bot commented 1 year ago

Can one of the admins verify this patch?

swift-server-bot commented 1 year ago

Can one of the admins verify this patch?

swift-server-bot commented 1 year ago

Can one of the admins verify this patch?

swift-server-bot commented 1 year ago

Can one of the admins verify this patch?

tomerd commented 1 year ago

thanks @hectormatos2011, @fabianfett and myself have been discussing some API changes to the main branch that should help address some of the points you bring up. should be able to put up a PR soon and then we can maybe see what else is missing and you can help get it over the finish line. wdyt?

hectormatos2011 commented 1 year ago

@tomerd I'd love to contribute! Thanks for taking a look. Would you like me to close this one? There's some good nuggets of code in here that should at least help with the type inference issue

tomerd commented 1 year ago

lets keep it open and focus on landing https://github.com/swift-server/swift-aws-lambda-runtime/pull/273. then we can see what else we need to bring over

tomerd commented 1 year ago

hi @hectormatos2011 would you like to revisit this now that we have the 1.0 API in place?

hectormatos2011 commented 1 year ago

Let me take a look at 1.0 and close the PR if need be

hectormatos2011 commented 1 year ago

Closing this PR since most of the improvements have been implemented in the 1.0 release!

@tomerd Is it currently possible to have code in the Lambda that makes it always run with LOCAL_LAMBDA_SERVER_ENABLED or do we still have to put that in the target itself? I'd like to be able to deploy example documentation that a developer could just copy and paste into Xcode without having to finagle with Edit Schemes or anything like that

tomerd commented 1 year ago

@tomerd Is it currently possible to have code in the Lambda that makes it always run with LOCAL_LAMBDA_SERVER_ENABLED or do we still have to put that in the target itself? I'd like to be able to deploy example documentation that a developer could just copy and paste into Xcode without having to finagle with Edit Schemes or anything like that

that is not possible right now, to protect users from accidentally deploying the mock / debug server