Skip to content

Commit d429f09

Browse files
committed
Use S3 bucket for swagger UI and json
1 parent 63aa7dd commit d429f09

File tree

6 files changed

+244
-150
lines changed

6 files changed

+244
-150
lines changed

Makefile

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ current_aws_account := $(shell aws sts get-caller-identity --query Account --out
88

99
src_directory_root = src/
1010
dist_ui_directory_root = dist_ui/
11+
dist_docs_directory_root = dist/swagger/
1112
integration_test_directory_root = tests/live_integration/
1213

1314
# CHANGE ME (as needed)
@@ -28,6 +29,8 @@ common_params = --no-confirm-changeset \
2829

2930
s3_bucket_prefix = "$(current_aws_account)-$(region)-$(application_key)"
3031
ui_s3_bucket = "$(s3_bucket_prefix)-ui"
32+
docs_s3_bucket = "$(s3_bucket_prefix)-docs"
33+
3134

3235
GIT_HASH := $(shell git rev-parse --short HEAD)
3336

@@ -66,19 +69,23 @@ build: src/ cloudformation/
6669
local:
6770
VITE_BUILD_HASH=$(GIT_HASH) yarn run dev
6871

72+
73+
postdeploy:
74+
@echo "Syncing S3 UI bucket..."
75+
aws s3 sync $(dist_ui_directory_root) s3://$(ui_s3_bucket)/ --delete
76+
@echo "Syncing S3 Docs bucket..."
77+
aws s3 sync $(dist_docs_directory_root) s3://$(docs_s3_bucket)/ --delete
78+
make invalidate_cloudfront
79+
6980
deploy_prod: check_account_prod
7081
@echo "Deploying CloudFormation stack..."
7182
sam deploy $(common_params) --parameter-overrides $(run_env)=prod $(set_application_prefix)=$(application_key) $(set_application_name)="$(application_name)" S3BucketPrefix="$(s3_bucket_prefix)"
72-
@echo "Syncing S3 bucket..."
73-
aws s3 sync $(dist_ui_directory_root) s3://$(ui_s3_bucket)/ --delete
74-
make invalidate_cloudfront
83+
make postdeploy
7584

7685
deploy_dev: check_account_dev
7786
@echo "Deploying CloudFormation stack..."
7887
sam deploy $(common_params) --parameter-overrides $(run_env)=dev $(set_application_prefix)=$(application_key) $(set_application_name)="$(application_name)" S3BucketPrefix="$(s3_bucket_prefix)"
79-
@echo "Syncing S3 bucket..."
80-
aws s3 sync $(dist_ui_directory_root) s3://$(ui_s3_bucket)/ --delete
81-
make invalidate_cloudfront
88+
make postdeploy
8289

8390
invalidate_cloudfront:
8491
@echo "Creating CloudFront invalidation..."

cloudformation/main.yml

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -611,11 +611,18 @@ Resources:
611611
WebsiteConfiguration:
612612
IndexDocument: index.html
613613

614+
AppDocsS3Bucket:
615+
Type: AWS::S3::Bucket
616+
Properties:
617+
BucketName: !Sub ${S3BucketPrefix}-docs
618+
WebsiteConfiguration:
619+
IndexDocument: index.html
620+
614621
CloudFrontOriginAccessIdentity:
615622
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
616623
Properties:
617624
CloudFrontOriginAccessIdentityConfig:
618-
Comment: !Sub "Access identity for ${AppFrontendS3Bucket}"
625+
Comment: !Sub "Access identity for ${AppFrontendS3Bucket} and ${AppDocsS3Bucket}"
619626

620627
AppFrontendCloudfrontDistribution:
621628
Type: AWS::CloudFront::Distribution
@@ -627,6 +634,10 @@ Resources:
627634
DomainName: !GetAtt AppFrontendS3Bucket.RegionalDomainName
628635
S3OriginConfig:
629636
OriginAccessIdentity: !Sub "origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}"
637+
- Id: S3DocsOrigin
638+
DomainName: !GetAtt AppDocsS3Bucket.RegionalDomainName
639+
S3OriginConfig:
640+
OriginAccessIdentity: !Sub "origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}"
630641
- Id: LambdaOrigin
631642
DomainName: !Select [0, !Split ['/', !Select [1, !Split ['https://', !GetAtt AppLambdaUrl.FunctionUrl]]]]
632643
CustomOriginConfig:
@@ -698,22 +709,23 @@ Resources:
698709
OriginRequestPolicyId: b689b0a8-53d0-40ab-baf2-68738e2966ac
699710
Compress: true
700711
- PathPattern: "/api/documentation*"
701-
TargetOriginId: LambdaOrigin
712+
Compress: true
713+
TargetOriginId: S3DocsOrigin
702714
ViewerProtocolPolicy: redirect-to-https
703715
AllowedMethods:
704716
- GET
705717
- HEAD
706-
- OPTIONS
707-
- PUT
708-
- POST
709-
- DELETE
710-
- PATCH
711718
CachedMethods:
712719
- GET
713720
- HEAD
714-
CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6"
715-
OriginRequestPolicyId: b689b0a8-53d0-40ab-baf2-68738e2966ac
716-
Compress: true
721+
ForwardedValues:
722+
QueryString: true
723+
Cookies:
724+
Forward: none
725+
CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6 # caching-optimized
726+
# LambdaFunctionAssociations:
727+
# - EventType: origin-request
728+
# LambdaFunctionARN: !Ref AppFrontendEdgeLambdaVersion
717729
- PathPattern: "/api/*"
718730
TargetOriginId: LambdaOrigin
719731
ViewerProtocolPolicy: redirect-to-https
@@ -754,6 +766,19 @@ Resources:
754766
Action: s3:GetObject
755767
Resource: !Sub "${AppFrontendS3Bucket.Arn}/*"
756768

769+
AppDocsS3BucketPolicy:
770+
Type: AWS::S3::BucketPolicy
771+
Properties:
772+
Bucket: !Ref AppDocsS3Bucket
773+
PolicyDocument:
774+
Version: "2012-10-17"
775+
Statement:
776+
- Effect: Allow
777+
Principal:
778+
CanonicalUser: !GetAtt CloudFrontOriginAccessIdentity.S3CanonicalUserId
779+
Action: s3:GetObject
780+
Resource: !Sub "${AppDocsS3Bucket.Arn}/*"
781+
757782
CloudfrontNoCachePolicy:
758783
Type: AWS::CloudFront::CachePolicy
759784
Properties:

src/api/createLambdaPackage.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ export const packagesToTransfer = [
1313
"moment-timezone",
1414
"passkit-generator",
1515
"fastify",
16-
"@fastify/swagger",
17-
"@fastify/swagger-ui",
1816
"zod",
1917
"argon2",
2018
"ioredis",

src/api/createSwagger.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { fileURLToPath } from "url";
2+
import path from "node:path";
3+
import { writeFile, mkdir } from "fs/promises";
4+
import init from "./index.js"; // Assuming this is your Fastify app initializer
5+
6+
const html = `
7+
<!DOCTYPE html>
8+
<html lang="en">
9+
<head>
10+
<meta charset="utf-8" />
11+
<meta name="viewport" content="width=device-width, initial-scale=1" />
12+
<meta name="description" content="ACM @ UIUC Core API Docs" />
13+
<title>ACM @ UIUC Core API</title>
14+
<link rel="stylesheet" href="https://unpkg.com/[email protected]/swagger-ui.css" />
15+
</head>
16+
<body>
17+
<div id="swagger-ui"></div>
18+
<script src="https://unpkg.com/[email protected]/swagger-ui-bundle.js" crossorigin></script>
19+
<script>
20+
window.onload = () => {
21+
window.ui = SwaggerUIBundle({
22+
url: '/api/documentation/openapi.json',
23+
dom_id: '#swagger-ui',
24+
});
25+
};
26+
</script>
27+
</body>
28+
</html>
29+
`;
30+
/**
31+
* Generates and saves Swagger/OpenAPI specification files.
32+
*/
33+
async function createSwaggerFiles() {
34+
try {
35+
const app = await init(false, false);
36+
await app.ready();
37+
console.log("App is ready. Generating specs...");
38+
const __filename = fileURLToPath(import.meta.url);
39+
const __dirname = path.dirname(__filename);
40+
const outputDir = path.resolve(__dirname, "..", "..", "dist", "swagger");
41+
await mkdir(outputDir, { recursive: true });
42+
const jsonSpec = JSON.stringify(app.swagger(), null, 2);
43+
const yamlSpec = app.swagger({ yaml: true });
44+
await writeFile(path.join(outputDir, "openapi.json"), jsonSpec);
45+
await writeFile(path.join(outputDir, "openapi.yaml"), yamlSpec);
46+
await writeFile(path.join(outputDir, "index.html"), html);
47+
48+
console.log(`✅ Swagger files successfully generated in ${outputDir}`);
49+
await app.close();
50+
} catch (err) {
51+
console.error("❌ Failed to generate Swagger files:", err);
52+
process.exit(1);
53+
}
54+
}
55+
56+
createSwaggerFiles();

0 commit comments

Comments
 (0)