Skip to content

Commit 9af5b4d

Browse files
authoredDec 13, 2021
feat(apigateway): add option to set the base path when adding a domain name to a Rest API (#17915)
If a domain name has an empty base path mapping, API Gateway does not allow the creation of additional base path mappings. The problem is that `addDomainName` always creates an empty base path mapping, preventing users to add their own afterwards. Add a property to define a base path mapping at the same time as adding the domain name. Fixes #9581. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent afcaede commit 9af5b4d

File tree

2 files changed

+91
-1
lines changed

2 files changed

+91
-1
lines changed
 

‎packages/@aws-cdk/aws-apigateway/lib/domain-name.ts

+18-1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,16 @@ export interface DomainNameOptions {
4848
* @default - mTLS is not configured.
4949
*/
5050
readonly mtls?: MTLSConfig;
51+
52+
/**
53+
* The base path name that callers of the API must provide in the URL after
54+
* the domain name (e.g. `example.com/base-path`). If you specify this
55+
* property, it can't be an empty string.
56+
*
57+
* @default - map requests from the domain root (e.g. `example.com`). If this
58+
* is undefined, no additional mappings will be allowed on this domain name.
59+
*/
60+
readonly basePath?: string;
5161
}
5262

5363
export interface DomainNameProps extends DomainNameOptions {
@@ -104,6 +114,7 @@ export class DomainName extends Resource implements IDomainName {
104114
public readonly domainName: string;
105115
public readonly domainNameAliasDomainName: string;
106116
public readonly domainNameAliasHostedZoneId: string;
117+
private readonly basePaths = new Set<string | undefined>();
107118

108119
constructor(scope: Construct, id: string, props: DomainNameProps) {
109120
super(scope, id);
@@ -136,7 +147,9 @@ export class DomainName extends Resource implements IDomainName {
136147
: resource.attrRegionalHostedZoneId;
137148

138149
if (props.mapping) {
139-
this.addBasePathMapping(props.mapping);
150+
this.addBasePathMapping(props.mapping, {
151+
basePath: props.basePath,
152+
});
140153
}
141154
}
142155

@@ -146,6 +159,10 @@ export class DomainName extends Resource implements IDomainName {
146159
* @param options Options for mapping to base path with or without a stage
147160
*/
148161
public addBasePathMapping(targetApi: IRestApi, options: BasePathMappingOptions = { }) {
162+
if (this.basePaths.has(undefined)) {
163+
throw new Error('This domain name already has an empty base path. No additional base paths are allowed.');
164+
}
165+
this.basePaths.add(options.basePath);
149166
const basePath = options.basePath || '/';
150167
const id = `Map:${basePath}=>${Names.nodeUniqueId(targetApi.node)}`;
151168
return new BasePathMapping(this, id, {

‎packages/@aws-cdk/aws-apigateway/test/domains.test.ts

+73
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,79 @@ describe('domains', () => {
259259
});
260260
});
261261

262+
test('a base path can be defined when adding a domain name', () => {
263+
// GIVEN
264+
const domainName = 'my.domain.com';
265+
const basePath = 'users';
266+
const stack = new Stack();
267+
const certificate = new acm.Certificate(stack, 'cert', { domainName: 'my.domain.com' });
268+
269+
// WHEN
270+
const api = new apigw.RestApi(stack, 'api', {});
271+
272+
api.root.addMethod('GET');
273+
274+
api.addDomainName('domainId', { domainName, certificate, basePath });
275+
276+
// THEN
277+
expect(stack).toHaveResource('AWS::ApiGateway::BasePathMapping', {
278+
'BasePath': 'users',
279+
'RestApiId': {
280+
'Ref': 'apiC8550315',
281+
},
282+
});
283+
});
284+
285+
test('additional base paths can added if addDomainName was called with a non-empty base path', () => {
286+
// GIVEN
287+
const domainName = 'my.domain.com';
288+
const basePath = 'users';
289+
const stack = new Stack();
290+
const certificate = new acm.Certificate(stack, 'cert', { domainName: 'my.domain.com' });
291+
292+
// WHEN
293+
const api = new apigw.RestApi(stack, 'api', {});
294+
295+
api.root.addMethod('GET');
296+
297+
const dn = api.addDomainName('domainId', { domainName, certificate, basePath });
298+
dn.addBasePathMapping(api, {
299+
basePath: 'books',
300+
});
301+
302+
// THEN
303+
expect(stack).toHaveResource('AWS::ApiGateway::BasePathMapping', {
304+
'BasePath': 'users',
305+
'RestApiId': {
306+
'Ref': 'apiC8550315',
307+
},
308+
});
309+
expect(stack).toHaveResource('AWS::ApiGateway::BasePathMapping', {
310+
'BasePath': 'books',
311+
'RestApiId': {
312+
'Ref': 'apiC8550315',
313+
},
314+
});
315+
});
316+
317+
test('no additional base paths can added if addDomainName was called without a base path', () => {
318+
// GIVEN
319+
const domainName = 'my.domain.com';
320+
const stack = new Stack();
321+
const certificate = new acm.Certificate(stack, 'cert', { domainName: 'my.domain.com' });
322+
323+
// WHEN
324+
const api = new apigw.RestApi(stack, 'api', {});
325+
326+
api.root.addMethod('GET');
327+
328+
const dn = api.addDomainName('domainId', { domainName, certificate });
329+
330+
expect(() => dn.addBasePathMapping(api, { basePath: 'books' }))
331+
.toThrow(/No additional base paths are allowed/);
332+
});
333+
334+
262335
test('domain name cannot contain uppercase letters', () => {
263336
// GIVEN
264337
const stack = new Stack();

0 commit comments

Comments
 (0)
Please sign in to comment.