Skip to content

Commit 5040263

Browse files
authored
Migrate backend from Serverless Framework to AWS SAM (#94)
- Replace Serverless Framework v3 with AWS SAM - Upgrade Node.js runtime from 20.x to 22.x - Use esbuild (built into SAM) instead of webpack/babel - Add esbuild-jest for test transformation - Update GitHub Actions workflow for SAM CLI - Update documentation (README, CLAUDE.md) This migration was necessary because Serverless v3 doesn't support Node.js > 20, and Serverless v4 has an incompatible license.
1 parent 3bbfb6e commit 5040263

File tree

14 files changed

+8419
-19293
lines changed

14 files changed

+8419
-19293
lines changed

.github/workflows/backend.yml

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ name: Backend
33
on:
44
push:
55
pull_request:
6-
76
# Allows you to run this workflow manually from the Actions tab
87
workflow_dispatch:
98

@@ -25,6 +24,8 @@ jobs:
2524
node-version-file: 'backend/package.json'
2625
cache: npm
2726
cache-dependency-path: backend/package.json
27+
- name: Setup AWS SAM
28+
uses: aws-actions/setup-sam@v2
2829
- name: Install Dependencies
2930
working-directory: backend
3031
run: npm install
@@ -33,12 +34,13 @@ jobs:
3334
run: npm test
3435
- name: Build
3536
working-directory: backend
36-
run: ./serverless package --package /tmp/artifacts --stage prod
37+
run: npm run build
3738
- name: Store artifacts
3839
uses: actions/upload-artifact@master
3940
with:
40-
name: serverless-package
41-
path: /tmp/artifacts
41+
name: sam-build
42+
path: backend/.aws-sam
43+
4244
deploy:
4345
needs: build
4446
if: success() && github.event_name == 'push' && github.ref == 'refs/heads/master'
@@ -51,20 +53,13 @@ jobs:
5153
steps:
5254
- name: Checkout
5355
uses: actions/checkout@v4
54-
- name: Use Node.js
55-
uses: actions/setup-node@v4
56-
with:
57-
node-version-file: 'backend/package.json'
58-
cache: npm
59-
cache-dependency-path: backend/package.json
60-
- name: Install Dependencies
61-
working-directory: backend
62-
run: npm install
56+
- name: Setup AWS SAM
57+
uses: aws-actions/setup-sam@v2
6358
- name: Load artifacts
6459
uses: actions/download-artifact@master
6560
with:
66-
name: serverless-package
67-
path: /tmp/artifacts
61+
name: sam-build
62+
path: backend/.aws-sam
6863
- name: Deploy
6964
working-directory: backend
70-
run: ./serverless deploy --package /tmp/artifacts --stage prod --conceal --verbose --debug=*
65+
run: sam deploy --no-confirm-changeset

.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ node_modules
44
*.log
55
out
66
jspm_packages
7-
.serverless
8-
.webpack
7+
.aws-sam
98
backend/artifacts
109
backend/coverage
1110
frontend/coverage

CLAUDE.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ npm run build # Production build
3232
cd backend
3333
npm install
3434
npm test # Unit tests
35-
./serverless deploy --stage prod # Deploy (requires AWS credentials)
35+
npm run build # Build with SAM
36+
npm run local # Local API server (requires Docker)
37+
npm run deploy # Deploy to AWS (requires credentials)
3638
```
3739

3840
## Deployment

backend/CLAUDE.md

Lines changed: 66 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11
# Backend
22

3-
AWS Lambda serverless functions for the CryFS website.
3+
AWS Lambda serverless functions for the CryFS website, deployed with AWS SAM.
44

55
## Tech Stack
66

7-
- **Runtime**: AWS Lambda with Serverless Framework
7+
- **Runtime**: AWS Lambda with AWS SAM (Serverless Application Model)
88
- **Language**: JavaScript (ES6+, no TypeScript)
9-
- **Bundler**: Webpack + Babel
9+
- **Bundler**: esbuild (built into SAM)
1010
- **External Services**: SendGrid (email), Mailchimp (newsletter)
1111
- **Secrets**: AWS SSM Parameter Store
1212

13+
## Prerequisites
14+
15+
Install the AWS SAM CLI:
16+
- macOS: `brew install aws-sam-cli`
17+
- Other: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html
18+
1319
## API Endpoints
1420

1521
| Method | Path | Description |
@@ -23,14 +29,57 @@ Both endpoints use simple token-based spam protection (not authentication).
2329

2430
```
2531
backend/
26-
├── *.js # Source modules (handlers and utilities)
27-
├── *.test.js # Jest tests (colocated)
28-
├── __mocks__/ # Jest mocks for external services
29-
├── iam/ # IAM policy documentation
30-
├── serverless.yml # Serverless Framework config
31-
└── webpack.config.js
32+
├── *.js # Source modules (handlers and utilities)
33+
├── *.test.js # Jest tests (colocated)
34+
├── __mocks__/ # Jest mocks for external services
35+
├── iam/ # IAM policy documentation
36+
├── template.yaml # SAM template (infrastructure as code)
37+
└── samconfig.toml # SAM deployment configuration
38+
```
39+
40+
## Commands
41+
42+
```bash
43+
# Install dependencies
44+
npm install
45+
46+
# Run unit tests
47+
npm test
48+
npm run test:watch # Watch mode
49+
npm run test:coverage # Coverage report
50+
51+
# Build Lambda functions
52+
npm run build # or: sam build
53+
54+
# Local development
55+
npm run local # Start local API at http://localhost:3000
56+
sam local invoke NewsletterRegisterFunction --event events/test.json
57+
58+
# Deploy to AWS (requires AWS credentials)
59+
npm run deploy # or: sam deploy --no-confirm-changeset
3260
```
3361

62+
## Local Testing with SAM
63+
64+
1. Build the functions:
65+
```bash
66+
sam build
67+
```
68+
69+
2. Start local API Gateway:
70+
```bash
71+
sam local start-api
72+
```
73+
74+
3. Test endpoints (in another terminal):
75+
```bash
76+
curl -X POST http://localhost:3000/newsletter/register \
77+
-H "Content-Type: application/json" \
78+
-d '{"token": "fd0kAn1zns", "email": "test@example.com"}'
79+
```
80+
81+
Note: Local testing requires Docker. SSM secrets won't work locally unless you mock them or set environment variables.
82+
3483
## Code Conventions
3584

3685
### Lambda Handler Pattern
@@ -39,9 +88,9 @@ All handlers use the `LambdaFunction()` higher-order function wrapper:
3988
```javascript
4089
import { LambdaFunction } from './lambda_function'
4190

42-
export const myHandler = LambdaFunction(async (event) => {
91+
export const myHandler = LambdaFunction(async (body) => {
4392
// Implementation
44-
return { success: true }
93+
return { statusCode: 200, body: JSON.stringify({ success: true }) }
4594
})
4695
```
4796

@@ -80,18 +129,14 @@ jest.mock('mailchimp-api-v3')
80129
Mailchimp.__mockPost.mockResolvedValue({ status: 'subscribed' })
81130
```
82131

83-
## Commands
84-
85-
```bash
86-
npm test # Run tests
87-
npm run test:watch # Tests in watch mode
88-
npm run test:coverage # Coverage report
89-
./serverless package # Package for deployment
90-
./serverless deploy --stage prod # Deploy to AWS
91-
```
92-
93132
## AWS Configuration
94133

95134
Deployment requires:
96135
- AWS credentials with appropriate permissions (see `iam/` directory)
97136
- SSM parameters configured for secrets
137+
138+
## Version Management
139+
140+
IMPORTANT: Node.js version must be kept in sync in two places:
141+
- `package.json``engines.node`
142+
- `template.yaml``Globals.Function.Runtime`

backend/README.md

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,45 @@
1-
Installation
2-
-------------
3-
Run "npm install" to install dependencies
1+
# Backend
42

3+
AWS Lambda backend for CryFS website, deployed with AWS SAM.
54

6-
AWS Setup
7-
-------------
8-
See `iam` folder for required IAM permissions
5+
## Installation
96

7+
```bash
8+
npm install
9+
```
1010

11-
Serverless commands
12-
-------------
13-
First set AWS environment variables AWS_ACCESS_KEY_ID and AWS_SECRET_KEY.
11+
### SAM CLI
1412

15-
Deploy all: $ ./serverless deploy [--stage prod]
16-
Deploy one function: $ ./serverless deploy function -f [functionName] [--stage prod]
17-
Invoke a remote function: $ ./serverless invoke -f [functionName] -l [--stage prod]
18-
Display remote logs: $ ./serverless logs -f [functionName] -t [--stage prod]
19-
Delete remote function: $ ./serverless remove
13+
Install the AWS SAM CLI for local development and deployment:
2014

15+
```bash
16+
# Using pip
17+
pipx install aws-sam-cli
2118

22-
Testing
23-
-------------
24-
Run tests: $ npm test
25-
Run tests in watch mode: $ npm run test:watch
26-
Run tests with coverage: $ npm run test:coverage
19+
# Or using Homebrew (macOS/Linux)
20+
brew install aws-sam-cli
21+
```
22+
23+
## AWS Setup
24+
25+
See `iam` folder for required IAM permissions.
26+
27+
## SAM Commands
28+
29+
First set AWS environment variables `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`.
30+
31+
```bash
32+
sam build # Build Lambda functions
33+
sam deploy --no-confirm-changeset # Deploy to AWS
34+
sam local start-api # Start local API server
35+
sam logs -n NewsletterRegisterFunction --tail # View logs
36+
sam delete # Delete stack
37+
```
38+
39+
## Testing
40+
41+
```bash
42+
npm test # Run tests
43+
npm run test:watch # Watch mode
44+
npm run test:coverage # Coverage report
45+
```

backend/babel.config.js

Lines changed: 0 additions & 17 deletions
This file was deleted.

backend/jest.config.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ module.exports = {
22
testEnvironment: 'node',
33
testMatch: ['**/*.test.js'],
44
testPathIgnorePatterns: ['/node_modules/'],
5+
transform: {
6+
'^.+\\.js$': 'esbuild-jest',
7+
},
58
collectCoverageFrom: [
69
'*.js',
710
'!jest.config.js',
8-
'!webpack.config.js',
911
],
1012
clearMocks: true,
1113
resetModules: true,

0 commit comments

Comments
 (0)