Skip to content

Commit 307d047

Browse files
authored
Use S3 bucket for swagger UI and json (#200)
1 parent 63aa7dd commit 307d047

File tree

8 files changed

+242
-177
lines changed

8 files changed

+242
-177
lines changed

Makefile

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ common_params = --no-confirm-changeset \
2828

2929
s3_bucket_prefix = "$(current_aws_account)-$(region)-$(application_key)"
3030
ui_s3_bucket = "$(s3_bucket_prefix)-ui"
31+
docs_s3_bucket = "$(s3_bucket_prefix)-docs"
32+
3133

3234
GIT_HASH := $(shell git rev-parse --short HEAD)
3335

@@ -66,19 +68,21 @@ build: src/ cloudformation/
6668
local:
6769
VITE_BUILD_HASH=$(GIT_HASH) yarn run dev
6870

71+
72+
postdeploy:
73+
@echo "Syncing S3 UI bucket..."
74+
aws s3 sync $(dist_ui_directory_root) s3://$(ui_s3_bucket)/ --delete
75+
make invalidate_cloudfront
76+
6977
deploy_prod: check_account_prod
7078
@echo "Deploying CloudFormation stack..."
7179
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
80+
make postdeploy
7581

7682
deploy_dev: check_account_dev
7783
@echo "Deploying CloudFormation stack..."
7884
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
85+
make postdeploy
8286

8387
invalidate_cloudfront:
8488
@echo "Creating CloudFront invalidation..."

cloudformation/main.yml

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -608,14 +608,15 @@ Resources:
608608
Type: AWS::S3::Bucket
609609
Properties:
610610
BucketName: !Sub ${S3BucketPrefix}-ui
611-
WebsiteConfiguration:
612-
IndexDocument: index.html
613611

614-
CloudFrontOriginAccessIdentity:
615-
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
612+
AppCloudfrontS3OAC:
613+
Type: AWS::CloudFront::OriginAccessControl
616614
Properties:
617-
CloudFrontOriginAccessIdentityConfig:
618-
Comment: !Sub "Access identity for ${AppFrontendS3Bucket}"
615+
OriginAccessControlConfig:
616+
Name: InfraCoreApi OAC
617+
OriginAccessControlOriginType: s3
618+
SigningBehavior: always
619+
SigningProtocol: sigv4
619620

620621
AppFrontendCloudfrontDistribution:
621622
Type: AWS::CloudFront::Distribution
@@ -626,7 +627,8 @@ Resources:
626627
- Id: S3WebsiteOrigin
627628
DomainName: !GetAtt AppFrontendS3Bucket.RegionalDomainName
628629
S3OriginConfig:
629-
OriginAccessIdentity: !Sub "origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}"
630+
OriginAccessIdentity: ''
631+
OriginAccessControlId: !GetAtt AppCloudfrontS3OAC.Id
630632
- Id: LambdaOrigin
631633
DomainName: !Select [0, !Split ['/', !Select [1, !Split ['https://', !GetAtt AppLambdaUrl.FunctionUrl]]]]
632634
CustomOriginConfig:
@@ -697,23 +699,6 @@ Resources:
697699
CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6"
698700
OriginRequestPolicyId: b689b0a8-53d0-40ab-baf2-68738e2966ac
699701
Compress: true
700-
- PathPattern: "/api/documentation*"
701-
TargetOriginId: LambdaOrigin
702-
ViewerProtocolPolicy: redirect-to-https
703-
AllowedMethods:
704-
- GET
705-
- HEAD
706-
- OPTIONS
707-
- PUT
708-
- POST
709-
- DELETE
710-
- PATCH
711-
CachedMethods:
712-
- GET
713-
- HEAD
714-
CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6"
715-
OriginRequestPolicyId: b689b0a8-53d0-40ab-baf2-68738e2966ac
716-
Compress: true
717702
- PathPattern: "/api/*"
718703
TargetOriginId: LambdaOrigin
719704
ViewerProtocolPolicy: redirect-to-https
@@ -750,9 +735,12 @@ Resources:
750735
Statement:
751736
- Effect: Allow
752737
Principal:
753-
CanonicalUser: !GetAtt CloudFrontOriginAccessIdentity.S3CanonicalUserId
738+
Service: cloudfront.amazonaws.com
754739
Action: s3:GetObject
755740
Resource: !Sub "${AppFrontendS3Bucket.Arn}/*"
741+
Condition:
742+
StringEquals:
743+
AWS:SourceArn: !Sub "arn:aws:cloudfront::${AWS::AccountId}:distribution/${AppFrontendCloudfrontDistribution}"
756744

757745
CloudfrontNoCachePolicy:
758746
Type: AWS::CloudFront::CachePolicy
@@ -812,6 +800,9 @@ Resources:
812800
exports.handler = async (event) => {
813801
const request = event.Records[0].cf.request;
814802
const uri = request.uri;
803+
if (uri === '/docs') {
804+
request.uri = "/docs/index.html";
805+
}
815806
if (!uri.startsWith('/api') && !uri.match(/\.\w+$/)) {
816807
request.uri = "/index.html";
817808
}

src/api/build.js

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,6 @@ const commonParams = {
3434
`.trim(),
3535
}, // Banner for compatibility with CommonJS
3636
plugins: [
37-
copy({
38-
resolveFrom: "cwd",
39-
assets: {
40-
from: ["../../node_modules/@fastify/swagger-ui/static/*"],
41-
to: ["../../dist/lambda/static"],
42-
},
43-
}),
4437
copy({
4538
resolveFrom: "cwd",
4639
assets: {

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/swagger-ui-dist@5.11.0/swagger-ui.css" />
15+
</head>
16+
<body>
17+
<div id="swagger-ui"></div>
18+
<script src="https://unpkg.com/swagger-ui-dist@5.11.0/swagger-ui-bundle.js" crossorigin></script>
19+
<script>
20+
window.onload = () => {
21+
window.ui = SwaggerUIBundle({
22+
url: '/docs/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_ui", "docs");
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)