Skip to content

feat: Sample Node.js REST API with AWS CDK — EC2 + API Gateway, GitLab CI/CD#36

Open
devin-ai-integration[bot] wants to merge 8 commits intomainfrom
devin/1774555408-nodejs-cdk-rest-api
Open

feat: Sample Node.js REST API with AWS CDK — EC2 + API Gateway, GitLab CI/CD#36
devin-ai-integration[bot] wants to merge 8 commits intomainfrom
devin/1774555408-nodejs-cdk-rest-api

Conversation

@devin-ai-integration
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot commented Mar 26, 2026

Summary

Adds a new sample-nodejs-cdk-api/ project — a plain JavaScript (CommonJS) Node.js REST API deployed on EC2 behind API Gateway HTTP API, using AWS CDK for infrastructure and GitLab CI/CD for automated deployment. Zero cold start — Express.js runs continuously on EC2 via PM2 (auto-restart, log management, boot persistence).

Architecture:

Client → API Gateway HTTP API → EC2 (t3.micro, Express.js on port 3000, managed by PM2)

Key components:

  • Express.js REST API with CRUD /api/items endpoints on EC2
  • CDK stack: VPC + EC2 + Security Group + API Gateway HTTP API (direct HTTP proxy to EC2 — no VPC Link, no NLB)
  • S3 Asset deployment: CDK uploads src/ and package.json as S3 assets; EC2 UserData downloads and runs them — single source of truth, no duplicated app code
  • PM2 process manager: EC2 UserData installs PM2, starts the app with pm2 start, saves the process list, and configures pm2 startup for boot persistence
  • .gitlab-ci.yml with validate → test → build → deploy stages (dev/staging/prod)
  • Jest tests (9 passing) asserting CDK-synthesized CloudFormation resources

Review & Testing Checklist for Human

  • S3 Asset unzip path on EC2: UserData runs unzip -o /tmp/app-code.zip -d /home/ec2-user/app/src/. The directory structure inside the zip depends on how CDK packages the src/ directory. If CDK nests it, files may land at .../src/src/app.js instead of .../src/app.js. Deploy to a test account and verify the extracted file paths — this is the highest-risk item since it determines whether the app actually starts.
  • EC2 public IP/DNS instability: The API Gateway integration uses instance.instancePublicDnsName, which changes when the EC2 instance is stopped and restarted. This silently breaks the API Gateway route. Consider adding an Elastic IP to stabilize the integration URI.
  • Unnecessary production dependencies on EC2: The deployed package.json includes aws-cdk-lib and constructs as regular dependencies. These are only needed for CDK synthesis, not at Express runtime, but npm install --omit=dev will still install them (~200 MB). Consider a separate runtime package.json or moving CDK libs to devDependencies.
  • Security — SSH open to 0.0.0.0/0: The security group allows SSH (port 22) from anyIpv4(). For production, restrict to specific CIDRs or remove entirely (SSM Session Manager is already configured via the IAM role).
  • Not deployed to AWS: Lint and Jest pass, local dev server works. However, this has not been deployed to an actual AWS account. The full EC2 bootstrap (Node.js install via nodesource, S3 download, npm install, PM2 setup) is untested against a real Amazon Linux 2023 instance.
  • GitLab CI working directory: The .gitlab-ci.yml assumes it runs at the project root, but the code lives in sample-nodejs-cdk-api/. If this stays as a subdirectory, every CI job needs a cd sample-nodejs-cdk-api or equivalent.

Suggested test plan:

  1. Clone the branch, cd sample-nodejs-cdk-api && npm install
  2. Run npm run dev and hit http://localhost:3000/api/items to verify CRUD locally
  3. Run npx cdk synth --context env=dev and inspect the CloudFormation template — check the UserData script for correct S3 paths and PM2 commands
  4. Deploy to a sandbox AWS account: npx cdk deploy --context env=dev
  5. SSH into EC2, run pm2 list and pm2 logs to verify PM2 is running the app
  6. Verify /home/ec2-user/app/src/ contains the expected files (app.js, local.js, routes/)
  7. Verify both the API Gateway URL and direct EC2 URL (http://<public-ip>:3000/) return valid responses
  8. Reboot the EC2 instance and confirm PM2 restarts the app automatically

Notes

  • The .gitlab-ci.yml is designed for a standalone repo. If this subdirectory layout is kept, each CI job needs working_dir: sample-nodejs-cdk-api or equivalent.
  • Cost: EC2 t3.micro ~$8.50/month (free tier eligible) + API Gateway HTTP API $1/million requests.
  • In-memory data store: Items are stored in a Map — data is lost on EC2 restart. Intentional for a sample app; swap in DynamoDB/RDS for persistence.

Link to Devin session: https://partner-workshops.devinenterprise.com/sessions/898695fe95d84a8fa616c239eedd0166

- Express.js REST API with CRUD endpoints wrapped in @vendia/serverless-express
- AWS CDK stack with Lambda + API Gateway + Provisioned Concurrency (no cold starts)
- Auto-scaling provisioned concurrency (2-10 instances at 70% utilization)
- ARM64 architecture + esbuild bundling for optimized cold start times
- GitLab CI/CD pipeline (.gitlab-ci.yml) with validate/test/build/deploy stages
- Jest test suite for CDK stack assertions
- TypeScript + ESLint configuration
@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

- Replace all .ts files with .js equivalents (CommonJS require/module.exports)
- Remove TypeScript dependencies (typescript, ts-node, ts-jest, @types/*)
- Remove tsconfig.json
- Update cdk.json to use 'node bin/app.js' instead of ts-node
- Update .gitlab-ci.yml: remove typecheck stage
- Update .eslintrc.json: remove TS parser/plugins
- Update jest.config.js: remove ts-jest transform
- Update .gitignore: no longer ignore *.js files
- Update README for JS project structure
Copy link
Copy Markdown
Contributor Author

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 5 additional findings.

Open in Devin Review

- Replace Lambda + Provisioned Concurrency with EC2 (t3.micro) + API Gateway HTTP API
- EC2 runs Express.js via systemd (auto-restart, always-on, zero cold start)
- API Gateway HTTP API with direct HTTP proxy to EC2 public IP (no VPC Link, no NLB)
- VPC with public subnets, security group allowing port 3000 and SSH
- IAM role with SSM Session Manager for secure access
- UserData bootstraps Node.js 20, Express app, and systemd service
- Remove Lambda/esbuild/serverless-express dependencies
- Update tests (8 passing) for EC2 architecture
- Update README with EC2 architecture diagram and docs
@devin-ai-integration devin-ai-integration bot changed the title feat: Sample Node.js REST API with AWS CDK — GitLab CI/CD, zero cold start feat: Sample Node.js REST API with AWS CDK — EC2 + API Gateway, GitLab CI/CD Mar 26, 2026
- Update bin/app.js description: EC2 with API Gateway HTTP API
- Update .gitlab-ci.yml comment: EC2 + API Gateway
- Remove src/handler.js (Lambda handler, no longer needed)
- CDK now uploads src/ as an S3 Asset instead of inlining Express code in UserData
- EC2 UserData downloads the same src/ code from S3 at boot time
- Single source of truth: src/local.js is used by both local dev and EC2 systemd
- Grant EC2 IAM role S3 read access for asset buckets
- Remove stale handler.js reference from README
- Update tests to verify S3 asset IAM policy (9 passing)
- Install PM2 globally in UserData
- Start Express app with pm2 start (auto-restart, log management)
- pm2 save + pm2 startup for boot persistence
- Simpler and more Node.js-native than systemd
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants