Description
Describe the bug
When 'importing' or referencing an existing Rest API Gateway using the fromRestApiAttributes
method, the referenced Gateway is missing at least the default method authorization options.
When you define default method options
const rootGateway = new api.RestApi(this, "api", {
restApiName: "api",
defaultMethodOptions: {
authorizationType: api.AuthorizationType.COGNITO,
authorizer: cognitoAuthorizer,
},
});
each route and method under that gateway, when in the same CF Stack will inherit these properties. In this example, if I wanted a public method, I would now have to explicitly make the route and method public.
But when referencing this Gateway via fromRestApiAttributes
in a different CF Stack, and new route and method I make are public by default.
const apiRoot = api.RestApi.fromRestApiAttributes(this, "RootGateway",
{
restApiId: ssm.StringParameter.valueForStringParameter(this, apiIdSsmKey),
rootResourceId: ssm.StringParameter.valueForStringParameter(this, apiRootIdSsmKey),
}
);
Any method added to apiRoot
is now public. This is different behaviour from adding a method/root in rootGateway
.
In scenarios where people are building directly against an IRestApi
it's not always obvious if it was referenced/imported or created as part of the same stack. This then requires people to specifically add an authorizer at each child set of routes. This is likely (possibly?) undesired behaviour when a Gateway team may own the central gateway and authorization logic and allow other teams to add their own routes to it.
If a team broken an existing API out into multiple stacks for any number of reasons, referencing the parent gateway would now cause a change to the authorization/authentication logic which wouldn't be desirable.
Regression Issue
- Select this option if this issue appears to be a regression.
Last Known Working CDK Version
No response
Expected Behavior
The IRestApi
returned from RestApi.fromRestApiAttributes
across stacks has the same behaviour and properties as the IRestApi
created in the same stack. All default options should be inherited by the new child providing consistent behavior regardless of where the gateway was first defined.
Current Behavior
The IRestApi
returned from RestApi.fromRestApiAttributes
is missing at least the authentication properties from the parent gateway. This results API Methods added to an IRestApi
having different behaviour depending on where the IRestApi
comes from
Reproduction Steps
Repo with repro CF Stacks https://github.com/ryancormack/cdk-api-gw-auth-bug
Current behaviour:
Method on 'child' stack
Both of these routes get created with the same code
private const IRestApi api;
this.api.addResource("should-be-private") //could be any route
.addMethod(
"ANY",
new api.MockIntegration({
integrationResponses: [{ statusCode: "200" }],
passthroughBehavior: api.PassthroughBehavior.NEVER,
requestTemplates: { "application/json": '{ "statusCode": 200 }' },
}),
{ methodResponses: [{ statusCode: "200" }] }
);
Possible Solution
I think the issue may originate from https://github.com/aws/aws-cdk/blob/main/packages/aws-cdk-lib/aws-apigateway/lib/restapi.ts#L798
/**
* Import an existing RestApi that can be configured with additional Methods and Resources.
*/
public static fromRestApiAttributes(scope: Construct, id: string, attrs: RestApiAttributes): IRestApi {
class Import extends RestApiBase {
public readonly restApiId = attrs.restApiId;
public readonly restApiName = attrs.restApiName ?? id;
public readonly restApiRootResourceId = attrs.rootResourceId;
public readonly root: IResource = new RootResource(this, {}, this.restApiRootResourceId);
}
return new Import(scope, id);
}
The second value passed to the RootResource
is the ResourceOptions
which then get used to populate things like the MethodOptions
//rest
constructor(api: RestApiBase, props: ResourceOptions, resourceId: string) {
super(api, 'Default');
this.parentResource = undefined;
this.defaultIntegration = props.defaultIntegration;
this.defaultMethodOptions = props.defaultMethodOptions;
this.defaultCorsPreflightOptions = props.defaultCorsPreflightOptions;
this.api = api;
this.resourceId = resourceId;
this.path = '/';
//rest
As a solution, fromRestApiAttributes
could be extended to be able to pass these props through, or take a value to "inherit default options" from a parent gateway
Additional Information/Context
No response
CDK CLI Version
2.173.2
Framework Version
No response
Node.js Version
22
OS
OSx latest
Language
TypeScript
Language Version
No response
Other information
No response