API Gateway (v1): Cannot provide RestApi as parent for Resource
- 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:

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
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