aws / aws/aws-cdk

API Gateway (v1): Cannot provide RestApi as parent for Resource

Open
#24,684 2 comments 3 reactions 0 assignees View on GitHub
@aws-cdk/aws-apigateway feature-request p2
Dominant language
TypeScript
Stars
12.9k
Forks
4.6k
Avg merge
2d 3h
Merged PRs (30d)
83

Description

### Describe the bug

When defining a `Resource` separately from a `RestApi` I am unable to provide the `RestApi` as the parent for the `Resource` despite documentation suggesting otherwise:
![image](https://user-images.githubusercontent.com/50264604/226142127-d4cfa34b-4053-42fe-b2ff-82ef83797aed.png)

This appears that it may have a flow-on effect when attempting to add a `CognitoUserPoolsAuthorizer` to the created resource, as it needs to be "attached to a `RestApi`".

### Expected Behavior

To be able to provide a `RestApi` as the parent of a `Resource` and subsequently be able to attach a `CognitoUserPoolsAuthorizer` to the resource.

### Current Behavior

When providing the `RestApi` as the parent the project cannot compile/synth.

When providing the `RestApi`'s root resource as the parent, or creating a wrapper for `RestApi` that implements `Amazon.CDK.AWS.APIGateway.IResource` the project can compile, but fails synth with the following error:
```
Unhandled exception. System.Exception: Error: Resolution error: Resolution error: Resolution error: Authorizer ([REDACTED]-InfrastructureStage-dev/InfrastructureStack/Api/ApiAuthorizer) must be attached to a RestApi.
Object creation stack:
at Function.string (C:\[REDACTED]\AppData\Local\Temp\jsii-kernel-hxXIJv\node_modules\aws-cdk-lib\core\lib\lazy.js:1:766)
at CognitoUserPoolsAuthorizer.lazyRestApiId (C:\[REDACTED]\AppData\Local\Temp\jsii-kernel-hxXIJv\node_modules\aws-cdk-lib\aws-apigateway\lib\authorizers\cognito.js:1:1986)
at new CognitoUserPoolsAuthorizer (C:\[REDACTED]\AppData\Local\Temp\jsii-kernel-hxXIJv\node_modules\aws-cdk-lib\aws-apigateway\lib\authorizers\cognito.js:1:793)
at Kernel._create (C:\[REDACTED]\AppData\Local\Temp\tvnb0n21.o2d\lib\program.js:9959:29)
at Kernel.create (C:\[REDACTED]\AppData\Local\Temp\tvnb0n21.o2d\lib\program.js:9688:29)
at KernelHost.processRequest (C:\[REDACTED]\AppData\Local\Temp\tvnb0n21.o2d\lib\program.js:11539:36)
at KernelHost.run (C:\[REDACTED]\AppData\Local\Temp\tvnb0n21.o2d\lib\program.js:11499:22)
at Immediate._onImmediate (C:\[REDACTED]\AppData\Local\Temp\tvnb0n21.o2d\lib\program.js:11500:46)
at processImmediate (node:internal/timers:464:21)..
at Amazon.JSII.Runtime.Services.Client.TryDeserialize[TResponse](String responseJson)
at Amazon.JSII.Runtime.Services.Client.ReceiveResponse[TResponse]()
at Amazon.JSII.Runtime.Services.Client.Invoke(InvokeRequest request)
at Amazon.JSII.Runtime.Services.Client.Invoke(ObjectReference objectReference, String method, Object[] arguments)
at Amazon.JSII.Runtime.Deputy.DeputyBase.<>c__DisplayClass17_0`1.b__1(IClient client, Object[] args)
at Amazon.JSII.Runtime.Deputy.DeputyBase.g__GetResult|18_0[T](<>c__DisplayClass18_0`1&)
at Amazon.JSII.Runtime.Deputy.DeputyBase.InvokeMethodCore[T](JsiiMethodAttribute methodAttribute, Object[] arguments, Func`3 beginFunc, Func`3 invokeFunc)
at Amazon.JSII.Runtime.Deputy.DeputyBase.InvokeInstanceMethod[T](Type[] parameterTypes, Object[] arguments, String methodName)
at Amazon.CDK.Pipelines.PipelineBase.AddStage(Stage stage, IAddStageOpts options)
at [REDACTED].StandardPipeline.TryCreateStageForEnvironment(DeploymentEnvironment deploymentEnvironment, ShellStep synthStep, EnvironmentGenerator environmentGenerator, IReadOnlyDictionary`2 deploymentEnvironments, EnvironmentManualApprovalOutput& environmentManualApprovalOutput)
at [REDACTED].StandardPipeline..ctor(Construct scope, String id, StandardPipelineProps props)
at Infrastructure.Program.Main(String[] args) in C:\[REDACTED]\src\Infrastructure\Program.cs:line 26
```

### Reproduction Steps

Here's the constructor of a `Stage` that is used to deploy the offending resources:

```
public InfrastructureStage(Construct scope, string id, InfrastructureStageProps props) : base(scope,
id, props)
{
var stack = new Stack(this, "InfrastructureStack", new StackProps());

var api = new RestApi(stack, "Api", new RestApiProps());

api.Root
.AddResource("proxy")
.AddProxy(new ProxyResourceOptions
{
AnyMethod = true,
DefaultIntegration = new HttpIntegration([REDACTED]),
DefaultMethodOptions = new MethodOptions
{
ApiKeyRequired = true
}
});

/* Ommited for brevity */

var apiResource = new Resource(stack, "ApiResource", new ResourceProps
{
Parent = api, // Doesn't accept api as a valid input because it doesn't implement Amazon.CDK.AWS.APIGateway.IResource
PathPart = "graphql",
DefaultIntegration = new LambdaIntegration(new BaseDotNetFunction(stack, "ApiFunction",
new BaseDotNetFunctionProps
{
Environment = props.Environment,
FunctionName = "ApiFunction",
CodePath = "./src/API/",
Handler = "API",
FunctionEnvironmentVariables = new FunctionEnvironmentVariables()
}).Function),
DefaultMethodOptions = new MethodOptions
{
AuthorizationType = AuthorizationType.COGNITO,
Authorizer = new CognitoUserPoolsAuthorizer(api, "ApiAuthorizer", // Providing api or stack here as scope doesn't make a difference
new CognitoUserPoolsAuthorizerProps
{
CognitoUserPools = new IUserPool[] {auth.UserPool.UserPool}
})
}
});
apiResource.Node.AddDependency(distribution, api, auth);
}
```
As you can see this sample does use some custom constructs, especially relating to the `BaseDotNetFunction` and `auth` (which is used in the `CognitoUserPoolsAuthorizerProps` to provide a user pool).

### Possible Solution

Having `Amazon.CDK.AWS.APIGateway.IResourceProps.Parent` accept both `Amazon.CDK.AWS.APIGateway.IResource` and `Amazon.CDK.AWS.APIGateway.RestApi` or have `Amazon.CDK.AWS.APIGateway.RestApi` implement `Amazon.CDK.AWS.APIGateway.IResource`. Additionally, have `CognitoUserPoolsAuthorizer` properly recognise when it is attached to a `RestApi`.

### Additional Information/Context

Of note, I am having to create the `apiResource` like this to resolve a cyclic dependency between a CloudFront `Distribution`, a Cognito `UserPool`, and the `apiResource`.

### CDK CLI Version

2.69.0 (build 60a5b2a)

### Framework Version

.NET 7

### Node.js Version

18.15.0

### OS

Windows 11 Home (10.0.22621)

### Language

.NET

### Language Version

C# 11

### Other information

_No response_

Contributor guide

Open the contributing guide

Research direction

Start with the API Gateway Resource and RestApi parent handling, then trace how CognitoUserPoolsAuthorizer determines its attached RestApi. Reproduce the provided C# example with the AWS CDK API Gateway constructs and verify that a separately created resource can use the RestApi as parent and synthesize with the authorizer attached.

Written by the indexing model from the issue text.

Assessment

Tech stack
aws, csharp, typescript
Domain
api, cloud, infrastructure
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
32/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.