Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(amplify-alpha): support custom response headers in monorepo structures #31771

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
28 changes: 21 additions & 7 deletions packages/@aws-cdk/aws-amplify-alpha/lib/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,12 @@ export class CustomRule {
* Custom response header of an Amplify App.
*/
export interface CustomResponseHeader {
/**
* If the app uses a monorepo structure, the appRoot from the build spec to apply the custom headers to.
* @default - The appRoot is omitted in the custom headers output.
*/
readonly appRoot?: string;

/**
* These custom headers will be applied to all URL file paths that match this pattern.
*/
Expand All @@ -531,16 +537,24 @@ export interface CustomResponseHeader {
}

function renderCustomResponseHeaders(customHeaders: CustomResponseHeader[]): string {
const yaml = [
'customHeaders:',
];
const hasAppRoot = customHeaders[0].appRoot !== undefined;
const yaml = [hasAppRoot ? 'applications' : 'customHeaders:'];

for (const customHeader of customHeaders) {
yaml.push(` - pattern: "${customHeader.pattern}"`);
yaml.push(' headers:');
if ((customHeader.appRoot !== undefined) !== hasAppRoot) {
throw new Error('appRoot must be either be present or absent across all custom response headers');
}

const baseIndentation = ' '.repeat(customHeader.appRoot ? 6 : 2);
if (hasAppRoot) {
yaml.push(` - appRoot: ${customHeader.appRoot}`);
yaml.push(' customHeaders:');
}
yaml.push(`${baseIndentation}- pattern: "${customHeader.pattern}"`);
yaml.push(`${baseIndentation} headers:`);
for (const [key, value] of Object.entries(customHeader.headers)) {
yaml.push(` - key: "${key}"`);
yaml.push(` value: "${value}"`);
yaml.push(`${baseIndentation} - key: "${key}"`);
yaml.push(`${baseIndentation} value: "${value}"`);
}
}

Expand Down
80 changes: 80 additions & 0 deletions packages/@aws-cdk/aws-amplify-alpha/test/app.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,86 @@ test('with custom headers', () => {
});
});

test('with custom headers in a monorepo structure', () => {
// WHEN
new amplify.App(stack, 'App', {
sourceCodeProvider: new amplify.GitHubSourceCodeProvider({
owner: 'aws',
repository: 'aws-cdk',
oauthToken: SecretValue.unsafePlainText('secret'),
}),
customResponseHeaders: [
{
appRoot: 'frontend',
pattern: '*.json',
headers: {
'custom-header-name-1': 'custom-header-value-1',
'custom-header-name-2': 'custom-header-value-2',
},
},
{
appRoot: 'backend',
pattern: '/path/*',
headers: {
'custom-header-name-1': 'custom-header-value-2',
},
},
{
appRoot: 'other',
pattern: '/with-tokens/*',
headers: {
'x-custom': `${'hello'.repeat(10)}${Stack.of(stack).urlSuffix} `,
},
},
],
});

// THEN
Template.fromStack(stack).hasResourceProperties('AWS::Amplify::App', {
CustomHeaders: {
'Fn::Join': [
'',
[
'applications\n - appRoot: frontend\n customHeaders:\n - pattern: \"*.json\"\n headers:\n - key: \"custom-header-name-1\"\n value: \"custom-header-value-1\"\n - key: \"custom-header-name-2\"\n value: \"custom-header-value-2\"\n - appRoot: backend\n customHeaders:\n - pattern: \"/path/*\"\n headers:\n - key: \"custom-header-name-1\"\n value: \"custom-header-value-2\"\n - appRoot: other\n customHeaders:\n - pattern: \"/with-tokens/*\"\n headers:\n - key: \"x-custom\"\n value: \"hellohellohellohellohellohellohellohellohellohello',
{
Ref: 'AWS::URLSuffix',
},
' "\n',
],
],
},
});
});

test('error with inconsistent appRoot in custom headers', () => {
// WHEN
expect(() => {
new amplify.App(stack, 'App', {
sourceCodeProvider: new amplify.GitHubSourceCodeProvider({
owner: 'aws',
repository: 'aws-cdk',
oauthToken: SecretValue.unsafePlainText('secret'),
}),
customResponseHeaders: [
{
pattern: '*.json',
headers: {
'custom-header-name-1': 'custom-header-value-1',
'custom-header-name-2': 'custom-header-value-2',
},
},
{
appRoot: 'backend',
pattern: '/path/*',
headers: {
'custom-header-name-1': 'custom-header-value-2',
},
},
],
});
}).toThrow('appRoot must be either be present or absent across all custom response headers');
});

test('create a statically hosted app by default', () => {
// WHEN
new amplify.App(stack, 'App', {});
Expand Down
Loading