SaturnFramework / Saturn

Opinionated, web development framework for F# which implements the server-side, functional MVC pattern
https://saturnframework.org
MIT License
708 stars 108 forks source link

AWS Lambda support #178

Closed willsam100 closed 2 years ago

willsam100 commented 5 years ago

Has Saturn been used with AWS Lambda?

At a high-level, this seems like it should be possible. Using Giraffe with AWS' templates creates the following snippet (and more)

let configureApp (app : IApplicationBuilder) =
    let env = app.ApplicationServices.GetService<IHostingEnvironment>()
    (match env.IsDevelopment() with
    | true  -> app.UseDeveloperExceptionPage()
    | false -> app.UseGiraffeErrorHandler AppHandlers.errorHandler)
        .UseStaticFiles()
        .UseGiraffe(AppHandlers.webApp) // <----- webApp is an HttpHandler from Giraffe

type LambdaEntryPoint() =
    inherit Amazon.Lambda.AspNetCoreServer.APIGatewayProxyFunction()

    override this.Init(builder : IWebHostBuilder) =
        let contentRoot = Directory.GetCurrentDirectory()

        builder
            .UseContentRoot(contentRoot) 
            .Configure(Action<IApplicationBuilder> configureApp)
            .ConfigureServices(configureServices) // <----- important part
            |> ignore

I would guess that a function that can translate the router or application computation expressions into an HttpHandler would be all that is required. Does this exist?

isaacabraham commented 5 years ago

@bruinbrown has been working on this very thing.

Krzysztof-Cieslak commented 5 years ago

@isaacabraham Have you've done anything with that in the end?

isaacabraham commented 5 years ago

@bruinbrown this was your thing dude :-)

bruinbrown commented 5 years ago

@Krzysztof-Cieslak I ended up getting the code changes in place to make it run on lambda but I never got as far as actually invoking that lambda. Then main change that I made was to change the signature of ApplicationBuilder to take in an optional IWebHostBuilder which is then provided by the AWS Lambda runtime

Rajivhost commented 4 years ago

Hi @bruinbrown, any update?

dsshep commented 4 years ago

I'm also interested in this. It seems, perhaps naively on my behalf, that we should be able to pass in an instance of IWebHostBuilder to be used here.

We would then need an IWebHostBuilder option on ApplicationState and a custom operation use_builder (or similar) to add it to the state.

I may have a look into this today and see what I come up with...

Edit:

On second thoughts, this may be much more simple than it seems.

It should be possible to use the existing host_config operation to do the same thing, provided it is the first to be executed.

e.g.

let app (builder: IWebHostBuilder option) = application {
    host_config (fun c -> match builder with | Some b -> b | None -> c)
    // the rest of the application ce...
}

Then lambda entry would be:

type LambdaEntryPoint() =
    inherit Amazon.Lambda.AspNetCoreServer.APIGatewayProxyFunction()

    override __.Init(builder : IWebHostBuilder) =
        app (Some builder) |> ignore

Edit 2:

This does indeed work. It's worth noting the lambda class must be placed in a namespace and NOT in a module. Otherwise the lambda startup will fail to find it.

namespace YourNamespace

type LambdaEntryPoint () =
    inherit Amazon.Lambda.AspNetCoreServer.APIGatewayProxyFunction()

    override __.Init(builder : IWebHostBuilder) = app builder

With that, everything seems to work as expected. This issue can probably be closed.

cartermp commented 2 years ago

I'll close this out, since there's a standard way to do this that fits within the idioms of AWS Lambda.

I'm hesitant to add docs or a template here, since platforms like Lambda tend to be moving targets that change their model for how things work every year or so (at least that was my experience with Azure Functions).