Create Lambda proxy integration inside a non-root resource in API Gateway using AWS SDK with C#

0

I am trying to create a proxy integration for Lambda invocation from API Gateway for a specific route (example.com/auth/{proxy+}, example.com/user/{proxy+}, etc..).

I am creating a script for automated infrastructure initialization and deployment (without using CloudFormation, Terraform, etc.) directly from the .NET script that is planned to be available as an API.

The predefined infrastructure contains Route53 config, created API Gateway with custom domain. The dynamic infrastructure contains S3 and Lambda together with API Gateway modifications and deployment.

Once the bucket for a new service is created and the built app is pushed to the bucket, a new Lambda function is created, configured and published. The last thing that is left is to create a new resource (route) that will invoke the underlying Lambda function and its underlying routes (e.g. example.com/auth/register).

The issue is that when I create an integration on a non-root resource, the Lambda function cannot be found or the Uri is not specified as it should be (this is something I am trying to figure out).

Here is the simplified code that I wrote to accomplish this (I will exclude the Lambda function and S3 bucket created and show only API gateway and Lambda resource policy updates as they are relevant here). Important to note is that this code produces the same results as if it were done via the AWS console. Also, this code creates a working solution if the route is not specified (e.g. example.com/register)

var functionArn = await Lambda.GetFunctionArn(accessKey, secretKey, region, lambdaFunction);
var pathResponse = await c.CreateResourceAsync(new CreateResourceRequest
{
    ParentId = rootId,
    PathPart = path,
    RestApiId = apiId
});
await c.PutMethodAsync(new PutMethodRequest
{
    AuthorizationType = "NONE",
    HttpMethod = "ANY",
    ResourceId = pathResponse.Id,
    RestApiId = apiId
});
var proxyResponse = await c.CreateResourceAsync(new CreateResourceRequest
{
    ParentId = pathResponse.Id,
    PathPart = "{proxy+}",
    RestApiId = apiId
});
await c.PutMethodAsync(new PutMethodRequest
{
    AuthorizationType = "NONE",
    HttpMethod = "ANY",
    ResourceId = proxyResponse.Id,
    RestApiId = apiId
});
await Lambda.AddPermissions(account, accessKey, secretKey, region, lambdaFunction, apiId, path);
await c.PutIntegrationAsync(new PutIntegrationRequest
{
    HttpMethod = "ANY",
    IntegrationHttpMethod = "POST",
    ResourceId = pathResponse.Id,
    RestApiId = apiId,
    PassthroughBehavior = "WHEN_NO_MATCH",
    Type = IntegrationType.AWS_PROXY,
    Uri = $"arn:aws:apigateway:{region}:lambda:path/2015-03-31/functions/{functionArn}/invocations"
});
await c.PutIntegrationAsync(new PutIntegrationRequest
{
    HttpMethod = "ANY",
    IntegrationHttpMethod = "POST",
    ResourceId = proxyResponse.Id,
    RestApiId = apiId,
    PassthroughBehavior = "WHEN_NO_MATCH",
    Type = IntegrationType.AWS_PROXY,
    Uri = $"arn:aws:apigateway:{region}:lambda:path/2015-03-31/functions/{functionArn}/invocations"
});
var deployment = await c.CreateDeploymentAsync(new CreateDeploymentRequest
{
    Description = $"API deployment to {environment}",
    RestApiId = apiId,
    StageName = environment
});
            
return deployment.Id;

where Lambda.AddPermissions is as follows:

var basePermission = await c.AddPermissionAsync(new AddPermissionRequest
{
    Action = "lambda:InvokeFunction",
    FunctionName = name,
    Principal = "apigateway.amazonaws.com",
    SourceArn = $"arn:aws:execute-api:{region}:{account}:{apiId}/*/*/{path}/*",
    StatementId = Guid.NewGuid().ToString()
});
var proxyPermission = await c.AddPermissionAsync(new AddPermissionRequest
{
    Action = "lambda:InvokeFunction",
    FunctionName = name,
    Principal = "apigateway.amazonaws.com",
    SourceArn = $"arn:aws:execute-api:{region}:{account}:{apiId}/*/*/{path}",
    StatementId = Guid.NewGuid().ToString()
});
                
return new List<string>
{
    basePermission.Statement,
    proxyPermission.Statement
};

Is there an issue with SourceArn specifications? I first created them through the AWS console (they are automatically created when the integration is created for Lambda) and they are the same.

Again, this all works when there is no path (non-root resource).

1 Answer
0

Hi, @hcerim.

Is your Backend Lambda function also .NET?
When integrating .NET Lambda and API Gateway, you may integrate with the "/{proxy+}" path and use Amazon.Lambda.AspNetCoreServer to run ASP.NET Core MVC. what is your function using?

https://dev.classmethod.jp/articles/api-gateway-lambda-net-6-minimal-api/ (for Japanese sorry, pls translate.)

profile picture
EXPERT
iwasa
answered a year ago
  • Hi, that is exactly what I am doing. Again, there is no issue with the setup on a root resource. It only occurs when I create the integration on a non-root resource (e.g. /somePath/{proxy+})

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions