Zaid-Ajaj / Fable.Remoting

Type-safe communication layer (RPC-style) for F# featuring Fable and .NET Apps
https://zaid-ajaj.github.io/Fable.Remoting/
MIT License
274 stars 57 forks source link

Add aws lambda support #359

Closed blair55 closed 10 months ago

blair55 commented 10 months ago

Adds a Fable.Remoting.AwsLambda project that allows Fable.Remoting to work on AWS Lambda.

Fable.Remoting.AwsLambda/FableLambdaAdapter.fs is just a clone of Fable.Remoting.AzureFunctions.Worker/FableAzureFunctionsAdapter.fs with adaptations and dependencies required to work with the APIGatewayHttpApiV2ProxyRequest & APIGatewayHttpApiV2ProxyResponse types from the Amazon.Lambda.APIGatewayEvents package.

This code runs in a project I have on lambda, so while there are no tests I have evidence of it working :-)

I have also omitted any changes to the build project to publish a nuget package - I wanted your feedback before going any further 🙏

blair55 commented 10 months ago

hi @Zaid-Ajaj 👋

I can't assign reviewers.. so just a heads up!

Zaid-Ajaj commented 10 months ago

Hi there @blair55 thanks a lot for the contribution! This looks like a very nice addition to the remoting packages. I will try to merge and publish it as soon as possible

Zaid-Ajaj commented 10 months ago

Merged and published an initial version of Fable.Remoting.AwsLambda v1.0.0 🚀

I am curious though, it targets net5.0 now and fails to build when changing to net6.0, did you see a similar problem? 🤔

blair55 commented 10 months ago

I am targeting net6.0 in the repo that hosts the code with no build problems, and have only the 6.0.4 runtime installed.

So while the Fable.Remoting.AwsLambda project in this repo builds locally, I wasn't building faithfully with net5.0 😬

victoradan commented 9 months ago

@blair55 , thank you for adding this! I'm interested in using Fable.Remoting with AWS Lambda. However, this implementation is specifically and exclusively targeting the request/response types of AWS's HTTP API v2. However, AWS has a different pair or request/response types for its REST API, which I'm currently using. It would be great to add support for this.

@Zaid-Ajaj , @blair55 , what is your recommended approach to adding this support? A new module under the same Fable.Remoting.AwsLambda project seems reasonable to me, but would like to get your thoughts and recommendations to add this. Thanks.

Please refer to the following AWS docs:

blair55 commented 9 months ago

Hi @victoradan!

First thought is that there is a lot of overlap between the old & new types They are not identical, but they do share a lot of root properties.

The types are just DTO classes used to bind the event json to. So you can expect many of the APIGatewayHttpApiV2ProxyRequest properties to be populated just as they would be on the APIGatewayProxyRequest type because the json payload is similar across both HTTP API or REST API events.

So you might get pretty far using the package as-is, and might not need the v1 types at all? Worth a try! 🤞

v1 APIGatewayProxyRequest

{
    "Body": null,
    "Headers": null,
    "HttpMethod": null,
    "IsBase64Encoded": false,
    "MultiValueHeaders": null,
    "MultiValueQueryStringParameters": null,
    "Path": null,
    "PathParameters": null,
    "QueryStringParameters": null,
    "RequestContext": null,
    "Resource": null,
    "StageVariables": null
}

v2 APIGatewayHttpApiV2ProxyRequest

{
    "Body": null,
    "Cookies": null,
    "Headers": null,
    "IsBase64Encoded": false,
    "PathParameters": null,
    "QueryStringParameters": null,
    "RawPath": null,
    "RawQueryString": null,
    "RequestContext": null,
    "RouteKey": null,
    "StageVariables": null,
    "Version": null
}
victoradan commented 9 months ago

Hello Nick,

Yes there is a lot of overlap, and yes, I did give it a try but, unfortunately, the differences, while small, are of enough significance. In particular claims from authentication are in different places / structure and don't come through correctly in the deserialization.

On Tue, Feb 27, 2024 at 5:58 AM Nick @.***> wrote:

Hi @victoradan https://github.com/victoradan!

First thought is that there is a lot of overlap between the old & new types They are not identical, but they do share a lot of root properties.

The types are just DTO classes used to bind the event json to. So you can expect many of the APIGatewayHttpApiV2ProxyRequest properties to be populated just as they would be on the APIGatewayProxyRequest type because the json payload is similar across both HTTP API or REST API events.

So you might get pretty far using the package as-is, and might not need the v1 types at all? Worth a try! 🤞

v1 APIGatewayProxyRequest

{ "Body": null, "Headers": null, "HttpMethod": null, "IsBase64Encoded": false, "MultiValueHeaders": null, "MultiValueQueryStringParameters": null, "Path": null, "PathParameters": null, "QueryStringParameters": null, "RequestContext": null, "Resource": null, "StageVariables": null }

v2 APIGatewayHttpApiV2ProxyRequest

{ "Body": null, "Cookies": null, "Headers": null, "IsBase64Encoded": false, "PathParameters": null, "QueryStringParameters": null, "RawPath": null, "RawQueryString": null, "RequestContext": null, "RouteKey": null, "StageVariables": null, "Version": null }

— Reply to this email directly, view it on GitHub https://github.com/Zaid-Ajaj/Fable.Remoting/pull/359#issuecomment-1966388653, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAV52CCTP5HXOKPUIYABNPTYVXC5RAVCNFSM6AAAAABBYPNHE6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSNRWGM4DQNRVGM . You are receiving this because you were mentioned.Message ID: @.***>

blair55 commented 8 months ago

To make a start (if this is still of interest!)... install the Fable.Remoting package but use custom code for the adapter. That's how I developed and tested the changes in this PR. e.g.

[<LambdaSerializer(typeof<Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer>)>]
let Handler (request: APIGatewayProxyRequest) =
  Remoting.createApi ()
  |> Remoting.withErrorHandler errorHandler
  |> Remoting.fromValue (api request)
  |> Remoting.buildRequestHandler
  |> HttpResponseData.fromRequestHandler request

Where HttpResponseData.fromRequestHandler is a function that you own in your own project. Just copy the contents of Fable.Remoting.AwsLambda/FableLambdaAdapter.fs. Then switch the V2 types for the V1 types: that's just two lines to change given how they are aliased. Then adapt the function to work with the different property names etc.

If this is successful then perhaps it could be introduced as a new project.

victoradan commented 8 months ago

Hello Nick.

Thanks. I just opened an MR https://github.com/Zaid-Ajaj/Fable.Remoting/pull/364 I kept both adapters in the same project... I think that makes sense (let me know what you think).

There's a lot of duplication, but since the types are different, with small differences, generalization is not as straightforward (not to me at least).

Feedback most welcome.

Thanks,

Victor

On Wed, Mar 27, 2024 at 12:21 AM Nick @.***> wrote:

To make a start (if this is still of interest!)... install the Fable.Remoting package but use custom code for the adapter. That's how I developed and tested the changes in this PR. e.g.

[<LambdaSerializer(typeof)>]let Handler (request: APIGatewayProxyRequest) = Remoting.createApi () |> Remoting.withErrorHandler errorHandler |> Remoting.fromValue (api request) |> Remoting.buildRequestHandler |> HttpResponseData.fromRequestHandler request

Where HttpResponseData.fromRequestHandler is a function that you own in your own project. Just copy the contents of Fable.Remoting.AwsLambda/FableLambdaAdapter.fs. Then switch the V2 types for the V1 types: that's just two lines to change given how they are aliased https://github.com/Zaid-Ajaj/Fable.Remoting/pull/359/files#r1452200288. Then adapt the function to work with the different property names etc.

If this is successful then perhaps it could be introduced as a new project.

— Reply to this email directly, view it on GitHub https://github.com/Zaid-Ajaj/Fable.Remoting/pull/359#issuecomment-2021962407, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAV52CHWBMYLNL6FLLHKC6LY2JCLVAVCNFSM6AAAAABBYPNHE6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDAMRRHE3DENBQG4 . You are receiving this because you were mentioned.Message ID: @.***>

blair55 commented 8 months ago

Yep, I agree with the approach. No need for another project, just a separate file in the existing lambda project. Good stuff! 🚀