Skip to content
Back to skills

3008 Chalice Lambda 73723400

BSecurity

Complete guide for building AWS Lambda functions with the AWS Chalice framework.

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added June 1, 2026
devopspythonbashflaskawstestingapidatabaseci/cd

Works with

  • cursor
  • cli
  • api

Security analysis

B80/100
  • mediumUses curl or wget to download content
  • criticalExfiltrates credentials via HTTP — exact pattern from Snyk ToxicSkills study
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 2 files and shows the line behind each finding

Scanned June 1, 2026

npx -y skills add tools-only/X-Skills --skill 3008-chalice-lambda_73723400 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 3008 Chalice Lambda 73723400?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 3008 Chalice Lambda 73723400
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-3008-chalice-lambda-73723400/badge)](https://www.skillsdirectory.com/skills/tools-only-3008-chalice-lambda-73723400)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
# AWS Chalice Lambda Framework

Complete guide for building AWS Lambda functions with the AWS Chalice framework.

## What is Chalice?

AWS Chalice is a Python serverless microframework that lets you quickly create and deploy applications that use AWS Lambda. It provides:

- Decorator-based routing (similar to Flask)
- Automatic IAM policy generation
- Local development server
- Built-in CORS support
- Easy deployment to API Gateway

## Installation

```bash
# Install Chalice
pip install chalice

# Verify installation
chalice --version

# Create new project
chalice new-project my-api
cd my-api
```

## Basic Structure

### Project Layout

```
my-chalice-project/
├── app.py                 # Main application file
├── requirements.txt       # Python dependencies
├── .chalice/
│   ├── config.json       # Stage configuration
│   └── deploy/           # Deployment artifacts (auto-generated)
├── chalicelib/           # Additional Python modules
│   ├── __init__.py
│   └── services.py
└── tests/
    └── test_app.py
```

### Minimal Application

```python
# app.py
from chalice import Chalice

app = Chalice(app_name='hello-world')

@app.route('/')
def index():
    return {'hello': 'world'}
```

## Routing

### HTTP Methods

```python
from chalice import Chalice

app = Chalice(app_name='my-api')

@app.route('/users', methods=['GET'])
def list_users():
    return {'users': []}

@app.route('/users', methods=['POST'])
def create_user():
    user = app.current_request.json_body
    return {'user': user, 'created': True}

@app.route('/users/{user_id}', methods=['GET'])
def get_user(user_id):
    return {'user_id': user_id}

@app.route('/users/{user_id}', methods=['PUT'])
def update_user(user_id):
    updates = app.current_request.json_body
    return {'user_id': user_id, 'updated': updates}

@app.route('/users/{user_id}', methods=['DELETE'])
def delete_user(user_id):
    return {'user_id': user_id, 'deleted': True}
```

### Path Parameters

```python
@app.route('/orders/{order_id}/items/{item_id}')
def get_order_item(order_id, item_id):
    return {
        'order_id': order_id,
        'item_id': item_id
    }
```

### Query Parameters

```python
from urllib.parse import parse_qs

@app.route('/search')
def search():
    # Access query parameters
    query_params = app.current_request.query_params or {}

    search_term = query_params.get('q')
    page = int(query_params.get('page', 1))
    limit = int(query_params.get('limit', 10))

    return {
        'search_term': search_term,
        'page': page,
        'limit': limit
    }
```

## Request Handling

### Accessing Request Data

```python
@app.route('/data', methods=['POST'])
def process_data():
    request = app.current_request

    # Request properties
    return {
        'method': request.method,           # POST
        'path': request.path,               # /data
        'query_params': request.query_params,
        'headers': dict(request.headers),
        'json_body': request.json_body,     # Parsed JSON body
        'raw_body': request.raw_body,       # Raw bytes
        'context': request.context,         # Lambda context
        'stage_vars': request.stage_vars,   # API Gateway stage variables
    }
```

### Custom Responses

```python
from chalice import Response
import json

@app.route('/custom-response')
def custom_response():
    return Response(
        body=json.dumps({'message': 'Custom response'}),
        status_code=201,
        headers={
            'Content-Type': 'application/json',
            'X-Custom-Header': 'value'
        }
    )

@app.route('/binary-data')
def binary_data():
    return Response(
        body=b'binary content',
        status_code=200,
        headers={'Content-Type': 'application/octet-stream'}
    )
```

## CORS Configuration

### Global CORS

```python
from chalice import Chalice, CORSConfig

# Global CORS configuration
cors_config = CORSConfig(
    allow_origin='https://example.com',
    allow_headers=['Content-Type', 'Authorization'],
    allow_credentials=True,
    max_age=600
)

app = Chalice(app_name='my-api')
app.api.cors_config = cors_config
```

### Per-Route CORS

```python
from chalice import CORSConfig

# Simple CORS
@app.route('/public', cors=True)
def public_endpoint():
    return {'data': 'public'}

# Custom CORS per route
custom_cors = CORSConfig(
    allow_origin='https://specific-domain.com',
    allow_headers=['X-Custom-Header']
)

@app.route('/restricted', cors=custom_cors)
def restricted_endpoint():
    return {'data': 'restricted'}
```

## Error Handling

### Built-in Errors

```python
from chalice import (
    Chalice,
    BadRequestError,
    UnauthorizedError,
    ForbiddenError,
    NotFoundError,
    ConflictError,
    UnprocessableEntityError,
    TooManyRequestsError,
    ChaliceViewError
)

app = Chalice(app_name='my-api')

@app.route('/users/{user_id}')
def get_user(user_id):
    user = find_user(user_id)
    if user is None:
        raise NotFoundError(f'User {user_id} not found')
    return user

@app.route('/users', methods=['POST'])
def create_user():
    data = app.current_request.json_body

    if not data or 'email' not in data:
        raise BadRequestError('Email is required')

    if user_exists(data['email']):
        raise ConflictError('User already exists')

    return create_new_user(data)
```

### Custom Error Handler

```python
from chalice import ChaliceViewError

@app.errorhandler(ChaliceViewError)
def handle_errors(error):
    return Response(
        body=json.dumps({
            'error': error.__class__.__name__,
            'message': str(error)
        }),
        status_code=error.STATUS_CODE if hasattr(error, 'STATUS_CODE') else 500,
        headers={'Content-Type': 'application/json'}
    )
```

## AWS Service Integration

### DynamoDB

```python
import boto3
from botocore.exceptions import ClientError

# Initialize at module level for connection reuse
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('my-table')

@app.route('/items/{item_id}')
def get_item(item_id):
    try:
        response = table.get_item(Key={'id': item_id})
        item = response.get('Item')

        if not item:
            raise NotFoundError(f'Item {item_id} not found')

        return item
    except ClientError as e:
        app.log.error(f"DynamoDB error: {e}")
        raise ChaliceViewError('Database error')

@app.route('/items', methods=['POST'])
def create_item():
    item = app.current_request.json_body

    try:
        table.put_item(Item=item)
        return item
    except ClientError as e:
        app.log.error(f"DynamoDB error: {e}")
        raise ChaliceViewError('Failed to create item')
```

### S3

```python
import boto3
import json

s3 = boto3.client('s3')
BUCKET_NAME = 'my-bucket'

@app.route('/files/{key}')
def get_file(key):
    try:
        response = s3.get_object(Bucket=BUCKET_NAME, Key=key)
        content = response['Body'].read()
        return Response(
            body=content,
            status_code=200,
            headers={'Content-Type': response['ContentType']}
        )
    except s3.exceptions.NoSuchKey:
        raise NotFoundError(f'File {key} not found')

@app.route('/files', methods=['POST'])
def upload_file():
    request = app.current_request
    key = request.query_params.get('key')

    if not key:
        raise BadRequestError('Key parameter required')

    s3.put_object(
        Bucket=BUCKET_NAME,
        Key=key,
        Body=request.raw_body,
        ContentType=request.headers.get('content-type', 'application/octet-stream')
    )

    return {'key': key, 'uploaded': True}
```

### SQS

```python
import boto3
import json

sqs = boto3.client('sqs')
QUEUE_URL = 'https://sqs.us-east-1.amazonaws.com/123456789/my-queue'

@app.route('/messages', methods=['POST'])
def enqueue_message():
    message = app.current_request.json_body

    response = sqs.send_message(
        QueueUrl=QUEUE_URL,
        MessageBody=json.dumps(message),
        MessageAttributes={
            'Type': {
                'StringValue': message.get('type', 'default'),
                'DataType': 'String'
            }
        }
    )

    return {
        'message_id': response['MessageId'],
        'status': 'queued'
    }
```

## Configuration

### config.json

```json
{
  "version": "2.0",
  "app_name": "my-api",
  "stages": {
    "dev": {
      "api_gateway_stage": "api",
      "environment_variables": {
        "DEBUG": "true",
        "TABLE_NAME": "dev-table"
      },
      "lambda_functions": {
        "api_handler": {
          "lambda_timeout": 10,
          "lambda_memory_size": 256
        }
      },
      "tags": {
        "Environment": "dev",
        "Project": "my-api"
      }
    },
    "prod": {
      "api_gateway_stage": "api",
      "environment_variables": {
        "DEBUG": "false",
        "TABLE_NAME": "prod-table"
      },
      "lambda_functions": {
        "api_handler": {
          "lambda_timeout": 30,
          "lambda_memory_size": 512,
          "reserved_concurrent_executions": 100
        }
      },
      "tags": {
        "Environment": "prod",
        "Project": "my-api"
      }
    }
  }
}
```

### Environment Variables

```python
import os

# Access environment variables
DEBUG = os.environ.get('DEBUG', 'false').lower() == 'true'
TABLE_NAME = os.environ.get('TABLE_NAME', 'default-table')
SECRET_KEY = os.environ.get('SECRET_KEY')

@app.route('/config')
def get_config():
    return {
        'debug': DEBUG,
        'table_name': TABLE_NAME,
        'has_secret': SECRET_KEY is not None
    }
```

## Local Development

### Local Server

```bash
# Start local development server
chalice local

# With specific port
chalice local --port 8080

# With stage configuration
chalice local --stage dev
```

### Testing Endpoints

```bash
# Test local endpoints
curl http://localhost:8000/
curl -X POST http://localhost:8000/users \
  -H "Content-Type: application/json" \
  -d '{"name": "John", "email": "john@example.com"}'
```

## Deployment

### Deploy to AWS

```bash
# Deploy to default stage (dev)
chalice deploy

# Deploy to specific stage
chalice deploy --stage prod

# Get deployment info
chalice url --stage dev
chalice logs --stage dev
```

### Generate CloudFormation Template

```bash
# Generate SAM/CloudFormation template
chalice package --stage prod ./out

# Output:
# ./out/sam.json          # CloudFormation template
# ./out/deployment.zip    # Lambda deployment package
```

## Advanced Features

### Request Middleware

```python
from chalice import Chalice

app = Chalice(app_name='my-api')

@app.middleware('http')
def auth_middleware(event, get_response):
    # Run before handler
    auth_header = event.headers.get('Authorization')

    if not auth_header and event.path != '/':
        return Response(
            body=json.dumps({'error': 'Unauthorized'}),
            status_code=401
        )

    # Call the actual handler
    response = get_response(event)

    # Run after handler
    response.headers['X-Request-ID'] = event.request_context['requestId']

    return response
```

### Scheduled Events

```python
from chalice import Chalice, Cron

app = Chalice(app_name='scheduled-tasks')

@app.schedule(Cron(0, 12, '*', '*', '?', '*'))
def daily_report(event):
    """Run every day at 12:00 PM UTC"""
    app.log.info("Running daily report")
    generate_daily_report()
    return {'status': 'completed'}

@app.schedule('rate(1 hour)')
def hourly_cleanup(event):
    """Run every hour"""
    app.log.info("Running hourly cleanup")
    cleanup_old_data()
    return {'status': 'completed'}
```

### S3 Event Handlers

```python
@app.on_s3_event(bucket='my-bucket', events=['s3:ObjectCreated:*'])
def handle_s3_upload(event):
    app.log.info(f"File uploaded: {event.key}")
    process_file(event.bucket, event.key)
    return {'status': 'processed'}
```

### SNS Event Handlers

```python
@app.on_sns_message(topic='my-topic')
def handle_sns_message(event):
    app.log.info(f"Received SNS message: {event.subject}")
    app.log.info(f"Message body: {event.message}")
    process_notification(event.message)
    return {'status': 'processed'}
```

### SQS Event Handlers

```python
@app.on_sqs_message(queue='my-queue', batch_size=10)
def handle_sqs_message(event):
    for record in event:
        app.log.info(f"Processing message: {record.body}")
        process_message(record.body)
    return {'status': 'processed'}
```

## Best Practices

1. **Initialize AWS clients at module level** for connection reuse across warm invocations
2. **Use `chalicelib/` for additional modules** to keep `app.py` clean
3. **Configure CORS properly** for browser-based clients
4. **Use environment variables** for configuration, not hardcoded values
5. **Handle exceptions** with Chalice error classes for proper HTTP responses
6. **Log with `app.log`** for CloudWatch integration
7. **Use `chalice package`** for CI/CD pipelines
8. **Set appropriate timeouts and memory** for your workload

## Common Patterns

### CRUD Service Pattern

```python
# chalicelib/users_service.py
import boto3
from botocore.exceptions import ClientError
from chalice import NotFoundError, BadRequestError

class UsersService:
    def __init__(self, table_name):
        self.table = boto3.resource('dynamodb').Table(table_name)

    def get_user(self, user_id):
        response = self.table.get_item(Key={'id': user_id})
        user = response.get('Item')
        if not user:
            raise NotFoundError(f'User {user_id} not found')
        return user

    def create_user(self, user_data):
        if 'id' not in user_data:
            raise BadRequestError('id is required')
        self.table.put_item(Item=user_data)
        return user_data

# app.py
from chalicelib.users_service import UsersService

users_service = UsersService(os.environ.get('TABLE_NAME'))

@app.route('/users/{user_id}')
def get_user(user_id):
    return users_service.get_user(user_id)

@app.route('/users', methods=['POST'])
def create_user():
    return users_service.create_user(app.current_request.json_body)
```

### Pagination Pattern

```python
@app.route('/users')
def list_users():
    query_params = app.current_request.query_params or {}

    limit = int(query_params.get('limit', 20))
    cursor = query_params.get('cursor')

    kwargs = {'Limit': limit}
    if cursor:
        kwargs['ExclusiveStartKey'] = {'id': cursor}

    response = table.scan(**kwargs)

    result = {
        'users': response.get('Items', []),
        'count': response.get('Count', 0)
    }

    if 'LastEvaluatedKey' in response:
        result['next_cursor'] = response['LastEvaluatedKey']['id']

    return result
```

Files in this skill

  • README.md1 KB
  • skill.md14.4 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.