Skip to content
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

feat: add api gateway emulator skeleton #1902

Open
wants to merge 6 commits into
base: feature/lambdatesttool-v2
Choose a base branch
from

Conversation

philasmar
Copy link
Contributor

Issue #, if available:
DOTNET-7837

Description of changes:

  • Added an API Gateway Emulator process
  • Added new command line arguments for the emulator
  • Added a service to process Lambda configuration through environment variables
  • Added the ability to match incoming HTTP requests with existing Lambda configurations
  • Added a catch-all HTTP endpoint
  • Updated base Spectre Command to support Cancellation tokens in order to facilitate unit tests

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@philasmar philasmar added the Release Not Needed Add this label if a PR does not need to be released. label Dec 10, 2024
@gcbeattyAWS
Copy link

can you double check the line file endings. i was getting warnings in my ide that they were not set as CRLF

@philasmar
Copy link
Contributor Author

can you double check the line file endings. i was getting warnings in my ide that they were not set as CRLF

Since we are working on different platforms we're bound to run into some line ending issues. I think what we did with the deploy tool was update our git config to retrieve files as LF. (something like that)

@philasmar philasmar requested a review from normj December 11, 2024 21:57

var runTask = app.RunAsync(cancellationToken);

return new ApiGatewayEmulatorProcess
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point do a LogInformation that the API Gateway emulator is available at the serviceUrl endpoint. Imagine this is what non-Aspire users will learn where to send requests to.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit redundant since the dotnet process will print the following to the console:

info: Microsoft.Hosting.Lifetime[14]
      Now listening on: **http://localhost:5051**
dbug: Microsoft.AspNetCore.Hosting.Diagnostics[13]
      Loaded hosting startup assembly Amazon.Lambda.TestTool
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /Users/asmarp/CodeBase/aws-lambda-dotnet/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool
dbug: Microsoft.Extensions.Hosting.Internal.Host[2]
      Hosting started

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, at this point in time, the process may not successfully start. So if I was to print the service URL and then the task failed, it would be kind of weird. I'd prefer if we rely on the default .NET logging for this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ASP.NET Core log line below doesn't give users context that this is the API Gateway emulator versus Lambda runtime API.

info: Microsoft.Hosting.Lifetime[14]
      Now listening on: **http://localhost:5051**

I believe in the published version of the tool we will default all of the Microsoft logging default level to Error so that our console window is focused on giving logging messages focused on our tool. When users see the console of our tool that should be thinking this is a log message for a lambda emulator tool not a web server.

So we need somewhere in the output that says basically the API Gateway Emulator endpoint is here. If this isn't that right spot that is fine but needs to be somewhere.

Imagine a user installing who just does dotnet install lambda-test-tool and dotnet lambda-test-tool. There mind set should only be how to I test my Lambda function and what is informative to me as a Lambda developer debugging. Not how to a debug some webserver, that is our implementation detail.

foreach (var routeConfig in _routeConfigs)
{
_logger.LogDebug("Checking if '{Path}' matches '{Template}'.", path, routeConfig.Path);
var template = TemplateParser.Parse(routeConfig.Path);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see any tests for handling API Gateway's style of using {proxy+} to indicate wild card character. I really want to know if Microsoft's TemplateParser is handling that or if we need to roll our own solution. Have you done any side by side comparisons with API Gateway and this library to see if they resolve the same.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TemplateParser supports a catch-all variable similar to the greedy variable in API gateway. I have updated the implementation to account for it as well as add sorting based on the route priority logic from API Gateway. I have added comments to explain everything in the code.

return null;
}

private RouteValueDictionary GetDefaults(RouteTemplate parsedTemplate)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are defaults even a think in API Gateway routing? I thought with API Gateway routing you can just have the name of the variable. I could be wrong but be sure we are not just implementing a feature of the Microsoft library and not API Gateway.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right. The function was not doing anything for our use case. I removed it.


namespace Amazon.Lambda.TestTool.UnitTests.Services;

public class ApiGatewayRouteConfigServiceTests
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need tests with {proxy+} especially when there are other routes. And you need tests with some overlap in the routes. For example a test with routeA -> /foo/{value} and routeB -> /foo/bar and you test with requests to /foo, /foo/bar and /foo/fred. Similar idea with {proxy+} and make sure we mimic API Gateway's behavior when choosing to use the proxy endpoint versus a more direct path. Another example routeA /{proxy+} and routeB /phil. Requests going to /norm and /phil and /phil/dotnet. Don't expect the Microsoft template library to match API Gateway's behavior.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have updated the implementation to account for it as well as add sorting based on the route priority logic from API Gateway. I have added comments to explain everything in the code.
I also added 1 big test that lists a bunch of different routes with overlap and tests which function was matched. This should cover everything.

@philasmar philasmar requested a review from normj December 12, 2024 17:42

var runTask = app.RunAsync(cancellationToken);

return new ApiGatewayEmulatorProcess
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ASP.NET Core log line below doesn't give users context that this is the API Gateway emulator versus Lambda runtime API.

info: Microsoft.Hosting.Lifetime[14]
      Now listening on: **http://localhost:5051**

I believe in the published version of the tool we will default all of the Microsoft logging default level to Error so that our console window is focused on giving logging messages focused on our tool. When users see the console of our tool that should be thinking this is a log message for a lambda emulator tool not a web server.

So we need somewhere in the output that says basically the API Gateway Emulator endpoint is here. If this isn't that right spot that is fine but needs to be somewhere.

Imagine a user installing who just does dotnet install lambda-test-tool and dotnet lambda-test-tool. There mind set should only be how to I test my Lambda function and what is informative to me as a Lambda developer debugging. Not how to a debug some webserver, that is our implementation detail.

_logger.LogDebug("Updating the metadata needed to properly sort the Lambda config");
foreach (var routeConfig in _routeConfigs)
{
if (routeConfig.Path.Contains("{proxy+}"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if you have a resource path like /resource/{id}/subsegment/{proxy+} so you have both a proxy and a variable?

}

[Fact]
public void ProperlySortRouteConfigs()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you verify with an API Gateway deployed with routes like this that returns behaves the same?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes the values I have in the test have been verified in API Gateway

/// <summary>
/// The type of API Gateway Route. This is used to determine the priority of the route when there is route overlap.
/// </summary>
public enum ApiGatewayRouteType
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this can be deleted now.

/// <returns>true if route is valid, false if not</returns>
private bool IsRouteConfigValid(ApiGatewayRouteConfig routeConfig)
{
var occurrences = routeConfig.Path.Split("{proxy+}").Length - 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Validate that path, httpmethod and Lambda name are set.

}
}

// If there are leftover route segments
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain what would be an example route and request path that would go into this section. It would be good to add examples in the comment block to help readers. I'm struggling to read this and understand in what scenario would the route ever be a matched if there are more route segments then were in the request path.

}

// If request has leftover segments that aren't matched
if (matched && requestPathIndex < requestSegments.Length)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the variableCount doesn't match the variables found in the request path should that be an false match.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Release Not Needed Add this label if a PR does not need to be released.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants