Skip to content

azoth-tech/lambda-test

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

E-Commerce Order API (Go)

A cloud-agnostic serverless API for managing e-commerce orders with multi-tenant support and PostgreSQL storage, written in Go.

Architecture

This project uses a separated handler pattern that isolates cloud provider-specific code from core business logic, making it easy to migrate between AWS, Azure, GCP, or OCI.

ecommerce-order-api/
├── core/
│   └── order_service.go          # Cloud-agnostic business logic
├── handlers/
│   ├── aws/main.go                # AWS Lambda handler
│   ├── azure/main.go              # Azure Functions handler
│   └── gcp/main.go                # GCP Cloud Functions handler
├── database/
│   └── schema.sql                 # PostgreSQL schema
└── aws/
    └── template.yaml              # SAM template

Features

  • âś… Multi-tenant architecture with tenant isolation
  • âś… Authentication integration with Cognito/Azure AD/Firebase
  • âś… PostgreSQL database for reliable data storage
  • âś… RESTful API for order management
  • âś… Cloud-agnostic core logic for easy migration
  • âś… Type-safe Go implementation
  • âś… Efficient connection pooling

Prerequisites

  • Go 1.21 or higher
  • AWS CLI and SAM CLI (for AWS deployment)
  • PostgreSQL database
  • Make (optional, for using Makefile)

Quick Start

1. Install Dependencies

go mod download

2. Set Up Database

# Connect to your PostgreSQL instance
psql -h your-db-host -U your-user -d ecommerce

# Run schema
\i database/schema.sql

3. Build for AWS Lambda

# Using Make
make build-aws

# Or manually
cd handlers/aws
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -tags lambda.norpc -o bootstrap main.go

4. Deploy to AWS

# Set environment variables
export DB_HOST=your-db.rds.amazonaws.com
export DB_USER=your_user
export DB_PASSWORD=your_pass
export COGNITO_USER_POOL_ARN=arn:aws:cognito-idp:...

# Deploy using SAM
make deploy-aws

# Or manually
cd aws
sam build
sam deploy --guided \
  --parameter-overrides \
    DBHost=$DB_HOST \
    DBName=ecommerce \
    DBUser=$DB_USER \
    DBPassword=$DB_PASSWORD \
    CognitoUserPoolArn=$COGNITO_USER_POOL_ARN

API Endpoints

Create Order

POST /orders
Authorization: Bearer <cognito-token>
Content-Type: application/json

{
  "customer_name": "John Doe",
  "customer_email": "john@example.com",
  "customer_phone": "+1234567890",
  "shipping_address": "123 Main St",
  "billing_address": "123 Main St",
  "total_amount": 99.99,
  "currency": "USD",
  "items": [
    {
      "product_name": "Widget",
      "product_sku": "WDG-001",
      "quantity": 2,
      "unit_price": 49.99
    }
  ]
}

Response (201 Created):

{
  "message": "Order created successfully",
  "order": {
    "order_id": "uuid-here",
    "tenant_id": "tenant-123",
    "customer_name": "John Doe",
    "total_amount": 99.99,
    "status": "pending",
    "items": [...]
  }
}

Get Order

GET /orders/{order_id}
Authorization: Bearer <cognito-token>

List Orders

GET /orders?limit=50&offset=0&my_orders=true
Authorization: Bearer <cognito-token>

Authentication

The API extracts authentication claims from the cloud provider's authentication service:

AWS Cognito Claims

type AuthClaims struct {
    TenantID string  // From custom:tenant_id
    UserID   string  // From sub
    Email    string  // From email
}

Configure Cognito User Pool with custom attribute custom:tenant_id:

# Create user with tenant_id
aws cognito-idp admin-update-user-attributes \
  --user-pool-id <pool-id> \
  --username user@example.com \
  --user-attributes Name=custom:tenant_id,Value=tenant-123

Development

Project Structure

  • core/order_service.go - Cloud-agnostic business logic

    • NewOrderService() - Initialize service with DB config
    • CreateOrder() - Create order with validation
    • GetOrder() - Retrieve order with tenant isolation
    • ListOrders() - List orders with pagination
  • handlers/aws/main.go - AWS Lambda specific

    • Extracts Cognito claims
    • Formats API Gateway responses
    • Routes HTTP methods

Running Tests

# Run all tests
make test

# Or
go test -v ./...

Local Testing with SAM

# Start local API
make local-aws

# Or
cd aws && sam local start-api

# Test endpoints
curl -X POST http://localhost:3000/orders \
  -H "Content-Type: application/json" \
  -d @../test_order.json

Code Formatting

# Format code
make fmt

# Or
go fmt ./...

Deployment

AWS Lambda

  1. Build the binary:
make build-aws
  1. Deploy with SAM:
cd aws
sam build
sam deploy --guided
  1. Get API endpoint:
aws cloudformation describe-stacks \
  --stack-name ecommerce-order-api \
  --query 'Stacks[0].Outputs[?OutputKey==`OrderApiUrl`].OutputValue' \
  --output text

Azure Functions

  1. Build:
make build-azure
  1. Deploy:
# Create function app
az functionapp create \
  --resource-group your-rg \
  --consumption-plan-location eastus \
  --runtime custom \
  --functions-version 4 \
  --name your-function-app

# Configure settings
az functionapp config appsettings set \
  --name your-function-app \
  --resource-group your-rg \
  --settings \
    DB_HOST=$DB_HOST \
    DB_NAME=ecommerce \
    DB_USER=$DB_USER \
    DB_PASSWORD=$DB_PASSWORD

# Deploy (create host.json and function.json first)
func azure functionapp publish your-function-app

GCP Cloud Functions

  1. Build:
make build-gcp
  1. Deploy:
gcloud functions deploy order-api \
  --gen2 \
  --runtime go121 \
  --entry-point OrderAPI \
  --trigger-http \
  --allow-unauthenticated \
  --set-env-vars \
    DB_HOST=$DB_HOST,\
    DB_NAME=ecommerce,\
    DB_USER=$DB_USER,\
    DB_PASSWORD=$DB_PASSWORD

GCP Cloud Run

  1. Build and push container:
gcloud builds submit --tag gcr.io/YOUR_PROJECT_ID/order-api -f gcp/cloudrun/Dockerfile
  1. Deploy:
gcloud run deploy order-api \
  --image gcr.io/YOUR_PROJECT_ID/order-api \
  --region YOUR_REGION \
  --allow-unauthenticated \
  --set-env-vars \
    DB_HOST=$DB_HOST,\
    DB_NAME=ecommerce,\
    DB_USER=$DB_USER,\
    DB_PASSWORD=$DB_PASSWORD

Database Schema

Multi-Tenant Design

All tables include tenant_id for data isolation:

CREATE TABLE orders (
    order_id UUID PRIMARY KEY,
    tenant_id VARCHAR(255) NOT NULL,
    created_by VARCHAR(255) NOT NULL,
    ...
);

-- Composite index for tenant queries
CREATE INDEX idx_orders_tenant_id ON orders(tenant_id);
CREATE INDEX idx_orders_tenant_created_by ON orders(tenant_id, created_by);

Connection Pooling

The OrderService manages connection pooling:

db.SetMaxOpenConns(25)
db.SetMaxIdleConns(5)
db.SetConnMaxLifetime(5 * time.Minute)

Performance Optimization

  1. Lambda Cold Start: Using ARM64 architecture reduces cold start time
  2. Connection Reuse: DB connection is reused across Lambda invocations
  3. Indexed Queries: All queries use indexed columns
  4. Prepared Statements: PostgreSQL query optimization

Migration Between Cloud Providers

To migrate from AWS to Azure or GCP:

  1. No changes needed to core/order_service.go
  2. Build the target handler:
    make build-azure  # or make build-gcp
  3. Deploy using the target platform's CLI
  4. Update authentication configuration

The core business logic remains identical!

Security Best Practices

  1. Secrets Management:

    • AWS: Use Secrets Manager
    • Azure: Use Key Vault
    • GCP: Use Secret Manager
  2. Database Security:

    • Use SSL/TLS connections (sslmode=require)
    • Store credentials in secrets manager
    • Enable VPC/Private networking
  3. Multi-tenancy:

    • All queries filtered by tenant_id
    • Claims extracted from verified tokens only
    • Never accept tenant_id from request body

Monitoring

AWS CloudWatch

# View logs
aws logs tail /aws/lambda/EcommerceOrderFunction --follow

# View metrics
aws cloudwatch get-metric-statistics \
  --namespace AWS/Lambda \
  --metric-name Duration \
  --dimensions Name=FunctionName,Value=EcommerceOrderFunction \
  --start-time 2024-01-01T00:00:00Z \
  --end-time 2024-01-02T00:00:00Z \
  --period 3600 \
  --statistics Average

Troubleshooting

Common Issues

  1. "Failed to connect to database"

    • Check security groups allow Lambda to access RDS
    • Verify database credentials
    • Ensure database is accessible
  2. "Missing tenant_id in claims"

    • Verify Cognito custom attribute is configured
    • Check user has tenant_id attribute set
    • Decode JWT token to verify claims
  3. Build errors

    • Ensure Go 1.21+ is installed
    • Run go mod download
    • Check GOOS and GOARCH are correct

Debug Tips

# Decode JWT token
echo $TOKEN | cut -d'.' -f2 | base64 -d | jq

# Test database connection
psql -h $DB_HOST -U $DB_USER -d $DB_NAME -c "SELECT 1"

# Check Lambda logs
aws logs tail /aws/lambda/EcommerceOrderFunction --follow

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Run tests: make test
  5. Format code: make fmt
  6. Submit a pull request

License

MIT

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published