Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintrc.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 10 additions & 10 deletions .projen/tasks.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 11 additions & 15 deletions src/url-shortener/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,35 +123,31 @@ export class UrlShortener extends Construct {
});

// Redirect function
const redirectFunction = new RedirectFunction(this, 'Redirect');
const redirectFunction = new RedirectFunction(this, 'Redirect', {
environment: {
BUCKET_NAME: bucket.bucketName,
},
});
bucket.grantRead(redirectFunction);

const distribution = new cloudfront.Distribution(this, 'Distribution', {
defaultBehavior: {
origin: origins.S3BucketOrigin.withOriginAccessControl(bucket),
edgeLambdas: [
{
eventType: cloudfront.LambdaEdgeEventType.ORIGIN_REQUEST,
functionVersion: redirectFunction,
},
],
origin: origins.FunctionUrlOrigin.withOriginAccessControl(redirectFunction.addFunctionUrl()),
},
certificate: props.certificate,
domainNames: [domainName],
httpVersion: cloudfront.HttpVersion.HTTP2_AND_3,
});

// Route53 records
new route53.ARecord(this, 'ARecord', {
const aliasProps = {
zone: props.hostedZone,
target: route53.RecordTarget.fromAlias(new targets.CloudFrontTarget(distribution)),
recordName: props.recordName,
});
new route53.AaaaRecord(this, 'AaaaRecord', {
zone: props.hostedZone,
target: route53.RecordTarget.fromAlias(new targets.CloudFrontTarget(distribution)),
recordName: props.recordName,
});
};
new route53.ARecord(this, 'ARecord', aliasProps);
new route53.AaaaRecord(this, 'AaaaRecord', aliasProps);
new route53.HttpsRecord(this, 'HttpsRecord', aliasProps);

// Lambda function to increment counter and write redirect in bucket
const shortenerFunction = new ShortenerFunction(this, 'Shortener', {
Expand Down
10 changes: 5 additions & 5 deletions src/url-shortener/redirect-function.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

63 changes: 0 additions & 63 deletions src/url-shortener/redirect.edge-lambda.ts

This file was deleted.

34 changes: 34 additions & 0 deletions src/url-shortener/redirect.lambda.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { GetObjectCommand, S3Client } from '@aws-sdk/client-s3';

const s3Client = new S3Client({});

export async function handler(event: AWSLambda.LambdaFunctionURLEvent): Promise<AWSLambda.LambdaFunctionURLResult> {
try {
const key = event.rawPath.substring(1); // remove first slash

const data = await s3Client.send(new GetObjectCommand({
Bucket: process.env.BUCKET_NAME,
Key: key,
}));

if (!data.Body) {
throw new Error('No body');
}

const redirect = JSON.parse(await data.Body.transformToString());

if (!redirect.url) {
throw new Error('Redirect object in S3 is missing a `url` property.');
}

return {
statusCode: 301,
headers: {
Location: redirect.url,
},
};
} catch (err) {
console.log(err);
return { statusCode: 404 };
Comment on lines +31 to +32

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current error handling returns a 404 Not Found for any error that occurs within the try block. This can make debugging difficult, as it hides the underlying cause of the error (e.g., permissions issues, throttling, or other S3 errors). It would be better to distinguish between a 'Not Found' error (NoSuchKey) and other server-side errors. For unexpected errors, returning a 500 Internal Server Error would be more appropriate and provide better observability.

    console.log(err);
    // The AWS SDK v3 for JS surfaces `NoSuchKey` as an error with name 'NoSuchKey'.
    if (err instanceof Error && err.name === 'NoSuchKey') {
      return { statusCode: 404 };
    }
    return { statusCode: 500 };

}
}
Loading
Loading