Skip to content

lambda_http should not include stage in the generated http request url #450

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
bnusunny opened this issue Mar 21, 2022 · 11 comments
Closed

Comments

@bnusunny
Copy link
Contributor

bnusunny commented Mar 21, 2022

In lambda_http v0.5.0 and v0.5.1, stage is added to http request url. This is a breaking change from v0.4.

Stage should not be included in the generated http request url. Including the stage in the url will couple the lambda function to the API GW deployment stage. The orginal behavior allows one lambda function to be deployed in different stages and works pertfectly fine. I think this is one of the benefit to seperate stage and path in API Gateway.

@calavera could we revert this behavior?

@bnusunny bnusunny changed the title http request url should not include stage in lambda_http lambda_httpshould not include stage in the generated http request url Mar 21, 2022
@bnusunny bnusunny changed the title lambda_httpshould not include stage in the generated http request url lambda_http should not include stage in the generated http request url Mar 21, 2022
@calavera
Copy link
Contributor

Stage should not be included in the generated http request url.

As far as I understand the API GW docs, the stage is part of the URL, before the path. It makes sense to me that the URL that the lambda function receives is exactly the same that requests are sent to through API GW.

Including the stage in the url will couple the lambda function to the API GW deployment stage

I don't think this is correct. The URL is generated when requests come in, so if you have the same lambda deployed in two different stages, when requests come in, the lambda function will get different URLs, which is expected.

This issue has more information about this breaking change: #107

@bnusunny
Copy link
Contributor Author

Yes, the stage is in the frontend URL called by clients. But API Gateway does the work to parse the request and send the
proxy integration request to lambda in this format. In this format, path and stage are seperated properties.

The lambda functions can do routing based on path without stage. This allows developers to deploy the same code to different stages (e.g. dev, test, staging, prod). Serverless Express and Serverless Java Container projects are working this way. Here is an example from Serverless Express project.

If developers want to get stage, she can access it from request context.

@calavera
Copy link
Contributor

calavera commented Mar 22, 2022

Here is an example from Serverless Express project.

The reason why serverless-express works as you describe it is because they access the raw event coming from API GW, or ALB, they are not using an abstraction like lambda_http. In their case, they are using the basic javascript runtime, it's the equivalent of using the lambda_runtime directly, without the http abstraction on top.

I think #453 solves your usecase without reverting the behavior that API GW users would expect from an http layer.

@bnusunny
Copy link
Contributor Author

bnusunny commented Mar 22, 2022

Sorry, #453 expose the RawPath, but the URL still contains the stage.

Let's look at the custom domain name case. I have a demo here:

Rest API: https://4ifijz53d0.execute-api.us-west-2.amazonaws.com/Prod/
Custom Domain Name: https://express-zip.awsguru.dev/

Inside the Lambda function, with v0.5.1 lambda_http crate, the path received is '/Prod'. This is not the real path requested by end customer.

With v0.4.1 lambda_http crate, the path received is '/'. This is the right one.

@bnusunny
Copy link
Contributor Author

bnusunny commented Mar 22, 2022

Lambda_http crate is indeed the Rust equalant of serverless-express and serverless-java-container. Thanks to you and other maintainers, it is much easier to develop Serverless HTTP APIs with Rust.

But seperating stage and path is the right approach for this problem. It makes API development much easier. Let's take the pet store application as an example. It has 3 API routes:

GET /pets -> return all pets
POST /pets -> create a new pet
GET /pets/{petid} -> return the pet with ID = petid

If we don't include stage in the URL, it is easy to create routes to match these paths. The same lambda function can be deployed on any stage without changes. It also works with custom domain names, and can be used with API GW REST API, API GW HTTP API and Application Load Balancer.

If we do include stage in the URL, the paths received by lambda function change. And the API routes become the following:

GET /{stage}/pets
POST /{stage}/pets
GET /{stage}/pets/{petid}

To promot this application through 3 API stages: dev, test, and prod, we have to modify the lambda for each stage.

We also lost the flexibility to change from API Gateway REST API to HTTP API (default stage) or ALB. Because HTTP API or ALB does not add stage, and the lambda function won't work.

Could we use a configuration to control this behavior? Like serverless-java-container's useStageAsServletContext?

@calavera
Copy link
Contributor

Besides your use case, which can be solved by using #453 to create the path that you want, I'd like to see more customer use cases where they set stages in their request paths, but don't want them in the path when they process the request in the Lambda function. So far, the only other customer use case we've heard from, indicates the opposite #107

@nmoutschen
Copy link
Contributor

nmoutschen commented Mar 23, 2022

Sorry, #453 expose the RawPath, but the URL still contains the stage.

Let's look at the custom domain name case. I have a demo here:

Rest API: https://4ifijz53d0.execute-api.us-west-2.amazonaws.com/Prod/ Custom Domain Name: https://express-zip.awsguru.dev/

Inside the Lambda function, with v0.5.1 lambda_http crate, the path received is '/Prod'. This is not the real path requested by end customer.

With v0.4.1 lambda_http crate, the path received is '/'. This is the right one.

Do you mean that when someone uses a custom domain, the path is no longer correct?

If so, I don't think the problem comes with the runtime exposing the stage in the path, but is a bit more subtle than that. Basically, we should be able to show the right URL that the end-users requests - whether it includes the stage or not. However, I'm unsure what we get from the raw event in case of a custom domain, and there can be some tricky situations due to base path mapping on the API Gateway side. We'd need to do more exploration.

Other than that, I agree with @calavera that exposing the raw path with #453 could be good for situations that needs it.

@bnusunny
Copy link
Contributor Author

bnusunny commented Mar 23, 2022

Yes, for custom domain name, the path is not correct with v0.5.1. I agree API Gateway base path mapping is another thing to consider. Looking at serverless java container, users can provide custom domain names and base path so that it can be handled properly.

Check out the two configurations variables 'serviceBasePath' and 'addCustomDomainName' here.

serviceBasePath - The value of this propety tells the library whether the application is running under a base path. For example, you could have configured your API Gateway to have a /orders/{proxy+} and a /catalog/{proxy+} resource. Each resource is handled by a separate Lambda functions. For this reason, the application inside Lambda may not be aware of the fact that the /orders path exists. Use the serviceBasePath property in conjuction with the stripBasePath property to remove the /orders prefix when routing requests inside the application. Defaults to null.

addCustomDomainName - Adds a supported custom domain name. Domain names need to be explicitly enabled for the getServerName() method to return the correct address.

Exposing rawpath is workable solution for the stage problem. But i still think providing a configuration switch like what serverless java container does is an even better solution.

useStageAsServletContext - Tells the framework to include the API Gateway stage path in the HttpServletRequest context path property. Defaults to false.

@bnusunny
Copy link
Contributor Author

bnusunny commented Mar 23, 2022

Another use case is CloudFront with custom domain name -> API GW regional endpoint as origin. This has the same problem like using custom domain name with API GW.

If users add one CloudFront function to pass the custom domain name in header like X-Forwarded-Host, we could know the real custom domain name being accessed.

@calavera
Copy link
Contributor

Given that there are no web frameworks that work out of the box with lambda_runtime, or lambda_http, people are going to always need to write an adapter for requests, or to use something like your lambda-adapter, which provides the request handling for them. #453 makes that possible in a way that doesn't make it harder to use lambda functions by default.

If you want to discuss more configuration options, please, open an RFC ticket, like #396 with use cases and design ideas so we can discuss more specific cases.

@bnusunny
Copy link
Contributor Author

Thanks for the reminder. I will implement some of the ideas in Lambda Adapter. When it is mature, I will open a RFC.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants