Skip to content

Use S3 bucket for swagger UI and json #200

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

Merged
merged 14 commits into from
Jul 6, 2025
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
16 changes: 10 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ common_params = --no-confirm-changeset \

s3_bucket_prefix = "$(current_aws_account)-$(region)-$(application_key)"
ui_s3_bucket = "$(s3_bucket_prefix)-ui"
docs_s3_bucket = "$(s3_bucket_prefix)-docs"


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

Expand Down Expand Up @@ -66,19 +68,21 @@ build: src/ cloudformation/
local:
VITE_BUILD_HASH=$(GIT_HASH) yarn run dev


postdeploy:
@echo "Syncing S3 UI bucket..."
aws s3 sync $(dist_ui_directory_root) s3://$(ui_s3_bucket)/ --delete
make invalidate_cloudfront

deploy_prod: check_account_prod
@echo "Deploying CloudFormation stack..."
sam deploy $(common_params) --parameter-overrides $(run_env)=prod $(set_application_prefix)=$(application_key) $(set_application_name)="$(application_name)" S3BucketPrefix="$(s3_bucket_prefix)"
@echo "Syncing S3 bucket..."
aws s3 sync $(dist_ui_directory_root) s3://$(ui_s3_bucket)/ --delete
make invalidate_cloudfront
make postdeploy

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

invalidate_cloudfront:
@echo "Creating CloudFront invalidation..."
Expand Down
41 changes: 16 additions & 25 deletions cloudformation/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -608,14 +608,15 @@ Resources:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub ${S3BucketPrefix}-ui
WebsiteConfiguration:
IndexDocument: index.html

CloudFrontOriginAccessIdentity:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
AppCloudfrontS3OAC:
Type: AWS::CloudFront::OriginAccessControl
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment: !Sub "Access identity for ${AppFrontendS3Bucket}"
OriginAccessControlConfig:
Name: InfraCoreApi OAC
OriginAccessControlOriginType: s3
SigningBehavior: always
SigningProtocol: sigv4

AppFrontendCloudfrontDistribution:
Type: AWS::CloudFront::Distribution
Expand All @@ -626,7 +627,8 @@ Resources:
- Id: S3WebsiteOrigin
DomainName: !GetAtt AppFrontendS3Bucket.RegionalDomainName
S3OriginConfig:
OriginAccessIdentity: !Sub "origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}"
OriginAccessIdentity: ''
OriginAccessControlId: !GetAtt AppCloudfrontS3OAC.Id
- Id: LambdaOrigin
DomainName: !Select [0, !Split ['/', !Select [1, !Split ['https://', !GetAtt AppLambdaUrl.FunctionUrl]]]]
CustomOriginConfig:
Expand Down Expand Up @@ -697,23 +699,6 @@ Resources:
CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6"
OriginRequestPolicyId: b689b0a8-53d0-40ab-baf2-68738e2966ac
Compress: true
- PathPattern: "/api/documentation*"
TargetOriginId: LambdaOrigin
ViewerProtocolPolicy: redirect-to-https
AllowedMethods:
- GET
- HEAD
- OPTIONS
- PUT
- POST
- DELETE
- PATCH
CachedMethods:
- GET
- HEAD
CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6"
OriginRequestPolicyId: b689b0a8-53d0-40ab-baf2-68738e2966ac
Compress: true
- PathPattern: "/api/*"
TargetOriginId: LambdaOrigin
ViewerProtocolPolicy: redirect-to-https
Expand Down Expand Up @@ -750,9 +735,12 @@ Resources:
Statement:
- Effect: Allow
Principal:
CanonicalUser: !GetAtt CloudFrontOriginAccessIdentity.S3CanonicalUserId
Service: cloudfront.amazonaws.com
Action: s3:GetObject
Resource: !Sub "${AppFrontendS3Bucket.Arn}/*"
Condition:
StringEquals:
AWS:SourceArn: !Sub "arn:aws:cloudfront::${AWS::AccountId}:distribution/${AppFrontendCloudfrontDistribution}"

CloudfrontNoCachePolicy:
Type: AWS::CloudFront::CachePolicy
Expand Down Expand Up @@ -812,6 +800,9 @@ Resources:
exports.handler = async (event) => {
const request = event.Records[0].cf.request;
const uri = request.uri;
if (uri === '/docs') {
request.uri = "/docs/index.html";
}
if (!uri.startsWith('/api') && !uri.match(/\.\w+$/)) {
request.uri = "/index.html";
}
Expand Down
7 changes: 0 additions & 7 deletions src/api/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,6 @@
`.trim(),
}, // Banner for compatibility with CommonJS
plugins: [
copy({
resolveFrom: "cwd",
assets: {
from: ["../../node_modules/@fastify/swagger-ui/static/*"],
to: ["../../dist/lambda/static"],
},
}),
copy({
resolveFrom: "cwd",
assets: {
Expand All @@ -57,9 +50,9 @@
outdir: "../../dist/lambda/",
external: [...commonParams.external, "sqs/*"],
})
.then(() => console.log("API server build completed successfully!"))

Check warning on line 53 in src/api/build.js

View workflow job for this annotation

GitHub Actions / Run Unit Tests

Unexpected console statement
.catch((error) => {
console.error("API server build failed:", error);

Check warning on line 55 in src/api/build.js

View workflow job for this annotation

GitHub Actions / Run Unit Tests

Unexpected console statement
process.exit(1);
});

Expand All @@ -69,8 +62,8 @@
entryPoints: ["api/sqs/index.js", "api/sqs/driver.js"],
outdir: "../../dist/sqsConsumer/",
})
.then(() => console.log("SQS consumer build completed successfully!"))

Check warning on line 65 in src/api/build.js

View workflow job for this annotation

GitHub Actions / Run Unit Tests

Unexpected console statement
.catch((error) => {
console.error("SQS consumer build failed:", error);

Check warning on line 67 in src/api/build.js

View workflow job for this annotation

GitHub Actions / Run Unit Tests

Unexpected console statement
process.exit(1);
});
2 changes: 0 additions & 2 deletions src/api/createLambdaPackage.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ export const packagesToTransfer = [
"moment-timezone",
"passkit-generator",
"fastify",
"@fastify/swagger",
"@fastify/swagger-ui",
"zod",
"argon2",
"ioredis",
Expand Down
56 changes: 56 additions & 0 deletions src/api/createSwagger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { fileURLToPath } from "url";
import path from "node:path";
import { writeFile, mkdir } from "fs/promises";
import init from "./index.js"; // Assuming this is your Fastify app initializer

const html = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="ACM @ UIUC Core API Docs" />
<title>ACM @ UIUC Core API</title>
<link rel="stylesheet" href="https://unpkg.com/[email protected]/swagger-ui.css" />
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://unpkg.com/[email protected]/swagger-ui-bundle.js" crossorigin></script>
<script>
window.onload = () => {
window.ui = SwaggerUIBundle({
url: '/docs/openapi.json',
dom_id: '#swagger-ui',
});
};
</script>
</body>
</html>
`;
/**
* Generates and saves Swagger/OpenAPI specification files.
*/
async function createSwaggerFiles() {
try {
const app = await init(false, false);
await app.ready();
console.log("App is ready. Generating specs...");

Check warning on line 37 in src/api/createSwagger.ts

View workflow job for this annotation

GitHub Actions / Run Unit Tests

Unexpected console statement
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const outputDir = path.resolve(__dirname, "..", "..", "dist_ui", "docs");
await mkdir(outputDir, { recursive: true });
const jsonSpec = JSON.stringify(app.swagger(), null, 2);
const yamlSpec = app.swagger({ yaml: true });
await writeFile(path.join(outputDir, "openapi.json"), jsonSpec);
await writeFile(path.join(outputDir, "openapi.yaml"), yamlSpec);
await writeFile(path.join(outputDir, "index.html"), html);

console.log(`✅ Swagger files successfully generated in ${outputDir}`);

Check warning on line 48 in src/api/createSwagger.ts

View workflow job for this annotation

GitHub Actions / Run Unit Tests

Unexpected console statement
await app.close();
} catch (err) {
console.error("❌ Failed to generate Swagger files:", err);

Check warning on line 51 in src/api/createSwagger.ts

View workflow job for this annotation

GitHub Actions / Run Unit Tests

Unexpected console statement
process.exit(1);
}
}

createSwaggerFiles();
Loading
Loading