diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index e691ab2..0216758 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,27 +1,23 @@ // For format details, see https://aka.ms/devcontainer.json. { - "name": "dev", - "image": "mcr.microsoft.com/devcontainers/python:3", - "features": { - "ghcr.io/devcontainers-extra/features/mise:1": {}, - "ghcr.io/devcontainers/features/aws-cli:1": {} - }, - "customizations": { - "vscode": { - "extensions": [ - "hverlin.mise-vscode", - "tamasfe.even-better-toml", - "redhat.vscode-yaml", - "charliermarsh.ruff", - "ms-python.python" - ] - } - }, - "mounts": [ - "source=${localEnv:HOME}/.aws,target=/home/vscode/.aws,type=bind" - ], - "postCreateCommand": "echo 'eval \"$(mise activate bash)\"' >> ~/.bashrc", - "forwardPorts": [ - "8000:8000" - ] + "name": "dev", + "image": "mcr.microsoft.com/devcontainers/python:3", + "features": { + "ghcr.io/devcontainers-extra/features/mise:1": {}, + "ghcr.io/devcontainers/features/aws-cli:1": {} + }, + "customizations": { + "vscode": { + "extensions": [ + "hverlin.mise-vscode", + "tamasfe.even-better-toml", + "redhat.vscode-yaml", + "charliermarsh.ruff", + "ms-python.python" + ] + } + }, + "mounts": ["source=${localEnv:HOME}/.aws,target=/home/vscode/.aws,type=bind"], + "postCreateCommand": "echo 'eval \"$(mise activate bash)\"' >> ~/.bashrc", + "forwardPorts": ["8000:8000"] } diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 2eee9bf..8c8ea23 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,3 +1,3 @@ github: amrabed -patreon: -custom: "https://paypal.me/amrabed" \ No newline at end of file +patreon: +custom: "https://paypal.me/amrabed" diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md index e1f4198..c140499 100644 --- a/.github/ISSUE_TEMPLATE/bug.md +++ b/.github/ISSUE_TEMPLATE/bug.md @@ -1,10 +1,9 @@ --- name: Bug report about: Report a bug -title: '' -labels: 'bug' -assignees: '' - +title: "" +labels: "bug" +assignees: "" --- **Describe the bug** @@ -12,6 +11,7 @@ A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: + 1. Go to '...' 2. Run '...` @@ -19,10 +19,11 @@ Steps to reproduce the behavior: A clear and concise description of what you expected to happen. **Environment (please complete the following information):** - - OS: [e.g., MacOS 14] - - Template version: - - Python version: - - uv version: + +- OS: [e.g., MacOS 14] +- Template version: +- Python version: +- uv version: **Additional context** Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature.md b/.github/ISSUE_TEMPLATE/feature.md index bbcbbe7..2bc5d5f 100644 --- a/.github/ISSUE_TEMPLATE/feature.md +++ b/.github/ISSUE_TEMPLATE/feature.md @@ -1,10 +1,9 @@ --- name: Feature request about: Suggest an idea for this project -title: '' -labels: '' -assignees: '' - +title: "" +labels: "" +assignees: "" --- **Is your feature request related to a problem? Please describe.** diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md index e08b5cc..53f326d 100644 --- a/.github/ISSUE_TEMPLATE/question.md +++ b/.github/ISSUE_TEMPLATE/question.md @@ -1,10 +1,9 @@ --- name: Question about: Ask a question about the project -title: '' -labels: 'question' -assignees: '' - +title: "" +labels: "question" +assignees: "" --- **Have you searched if your question has already been answered before? If not, please do that first** diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 464e33c..beeee10 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -7,6 +7,7 @@ --> ## Pull Request Type + - [ ] Bug Fix - [ ] Feature - [ ] Optimization @@ -15,6 +16,7 @@ - [ ] Dependency Update ## Summary + _Please replace this line with a brief description of the changes you've made_ ## Related Issues @@ -36,9 +38,11 @@ automatically close the issue. _Please replace this line with instructions on how to test your changes_ ## Submission Checklist + Before submitting a Pull Request, please ensure you've done the following: + - [ ] Created a small PR - [ ] Tested your changes - [ ] Used descriptive commit messages diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d43eb62..02d233d 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -6,29 +6,29 @@ version: 2 updates: - - package-ecosystem: "uv" - directory: "/" - schedule: - interval: weekly - day: friday - versioning-strategy: increase-if-necessary - groups: - dependencies: - applies-to: version-updates - patterns: - - "*" - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: weekly - day: friday - groups: - github-actions: - applies-to: version-updates - patterns: - - "*" - - package-ecosystem: "devcontainers" - directory: "/" - schedule: - interval: weekly - day: friday + - package-ecosystem: "uv" + directory: "/" + schedule: + interval: weekly + day: friday + versioning-strategy: increase-if-necessary + groups: + dependencies: + applies-to: version-updates + patterns: + - "*" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: weekly + day: friday + groups: + github-actions: + applies-to: version-updates + patterns: + - "*" + - package-ecosystem: "devcontainers" + directory: "/" + schedule: + interval: weekly + day: friday diff --git a/.github/template.yml b/.github/template.yml index 9fbef9d..4a08be9 100644 --- a/.github/template.yml +++ b/.github/template.yml @@ -1 +1 @@ -author: amrabed \ No newline at end of file +author: amrabed diff --git a/.template/docs/reference.md b/.template/docs/reference.md index fcecdfd..7f46711 100644 --- a/.template/docs/reference.md +++ b/.template/docs/reference.md @@ -1,2 +1,3 @@ # ${title_name} -::: templates.${name}.handler \ No newline at end of file + +::: templates.${name}.handler diff --git a/.template/docs/template.md b/.template/docs/template.md index f8136a9..48831d0 100644 --- a/.template/docs/template.md +++ b/.template/docs/template.md @@ -1,4 +1,5 @@ # ${title_name} + Template description for ${title_name}. ## Architecture diff --git a/.vscode/settings.json b/.vscode/settings.json index 24a62d6..ccb1941 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,45 +1,41 @@ { - "python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python", + "python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python", + "editor.defaultFormatter": "charliermarsh.ruff", + "editor.formatOnSave": true, + "[python]": { "editor.defaultFormatter": "charliermarsh.ruff", - "editor.formatOnSave": true, - "[python]": { - "editor.defaultFormatter": "charliermarsh.ruff", - "editor.codeActionsOnSave": { - "source.fixAll.ruff": "explicit", - "source.organizeImports.ruff": "explicit" - } - }, - "[toml]": { - "editor.defaultFormatter": "tamasfe.even-better-toml" - }, - "[yaml]": { - "editor.defaultFormatter": "redhat.vscode-yaml" - }, - "python.testing.pytestEnabled": true, - "python.testing.unittestEnabled": false, - "python.testing.pytestArgs": [ - "--tb=short" - ], - "files.exclude": { - "**/__pycache__": true, - "**/*.pyc": true, - "**/.pytest_cache": true, - "**/.ruff_cache": true, - "**/cdk.out": true, - "**/.venv": true - }, - "search.exclude": { - "**/__pycache__": true, - "**/.venv": true, - "**/cdk.out": true, - "**/node_modules": true, - "uv.lock": true - }, - "editor.rulers": [ - 120 - ], - "editor.insertSpaces": true, - "editor.tabSize": 4, - "files.trimTrailingWhitespace": true, - "files.insertFinalNewline": true -} \ No newline at end of file + "editor.codeActionsOnSave": { + "source.fixAll.ruff": "explicit", + "source.organizeImports.ruff": "explicit" + } + }, + "[toml]": { + "editor.defaultFormatter": "tamasfe.even-better-toml" + }, + "[yaml]": { + "editor.defaultFormatter": "redhat.vscode-yaml" + }, + "python.testing.pytestEnabled": true, + "python.testing.unittestEnabled": false, + "python.testing.pytestArgs": ["--tb=short"], + "files.exclude": { + "**/__pycache__": true, + "**/*.pyc": true, + "**/.pytest_cache": true, + "**/.ruff_cache": true, + "**/cdk.out": true, + "**/.venv": true + }, + "search.exclude": { + "**/__pycache__": true, + "**/.venv": true, + "**/cdk.out": true, + "**/node_modules": true, + "uv.lock": true + }, + "editor.rulers": [120], + "editor.insertSpaces": true, + "editor.tabSize": 4, + "files.trimTrailingWhitespace": true, + "files.insertFinalNewline": true +} diff --git a/AGENTS.md b/AGENTS.md old mode 100644 new mode 100755 index 5de71ed..0a2469f --- a/AGENTS.md +++ b/AGENTS.md @@ -79,7 +79,6 @@ mise run init --name="my-project" --description="My description" --author="Name" - Deploy locally using LocalStack: copy `.env.local.example` to `.env.local` and set token from [app.localstack.cloud](https://app.localstack.cloud), then `mise run local:deploy ` (alias `local `, `dl `). - Destroy locally from LocalStack: `mise run local:destroy ` (alias `Dl `). - ## Testing Guidelines - Use pytest, not unittest @@ -185,15 +184,19 @@ if __name__ == "__main__": ``` ### Data Models + - Always move all data models to a separate `models.py` file within the template directory. ### Event Types + - Always use AWS Lambda Powertools event types for parsing and type hinting incoming events. ### SQS Interactions + - Use a separate `queue.py` module with a `Queue` class to encapsulate all SQS interactions (initialization, publishing, etc.). ### Handler Structure + - Create a `Handler` class with a `handle_record` (or similar) method. - Pass the `Handler` instance to the main Lambda entry point. - Decorate handler methods with `@tracer.capture_method`. @@ -201,4 +204,5 @@ if __name__ == "__main__": - For S3 events, manually iterate over records and raise an exception if any record fails to ensure the entire batch is retried by the S3 event source. ### Lambda Entry Point + - The main Lambda entry point should be named `main`. diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 01b95d3..189181f 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -1,4 +1,3 @@ - # Contributing First off, thanks for taking the time to contribute! ❤️ @@ -16,6 +15,7 @@ All types of contributions are encouraged and valued. Here are some ways you can ## Contributing to the code > ### Legal Notice +> > When contributing to this project, you must agree that you have authored 100% of the content, that you have the necessary rights to the content and that the content you contribute may be provided under the project license. Unless your change is trivial (typo, docs tweak etc.), please create an issue to discuss the change before creating a pull request. @@ -42,11 +42,13 @@ You'll need the following prerequisites: mise run install mise run dev ``` + - Create a new branch (with a descriptive name) for your changes: ```bash git checkout -b my-new-feature # use descriptive branch name ``` + - Make your code changes - Run tests and linting locally to make sure everything is working as expected. @@ -54,17 +56,19 @@ git checkout -b my-new-feature # use descriptive branch name mise run lint mise run test ``` + - Commit your changes and push your branch to GitHub + ```bash git add . git commit -m "My new feature" # use descriptive commit message git push origin my-new-feature ``` + - Create a pull request, and request review from the team > Please follow the pull request template and fill in as much information as possible. Link to any relevant issues and include a description of your changes. - ### Code documentation When contributing to this project, please make sure that all code is well documented. The following should be documented using properly formatted docstrings: @@ -85,11 +89,13 @@ The project uses [Hypothesis](https://hypothesis.readthedocs.io) for property-ba Project Documentation is written in Markdown and built using [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/). API documentation is built from docstrings using [mkdocstrings](https://mkdocstrings.github.io/). To preview the documentation locally, run: + ```bash mise run local ``` ## Reporting Bugs + #### Before submitting a bug report A good bug report shouldn't leave others needing to chase you up for more information. Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report. Please complete the following steps in advance to help us fix any potential bug as fast as possible. @@ -100,19 +106,18 @@ A good bug report shouldn't leave others needing to chase you up for more inform - Also make sure to search the internet (including Stack Overflow) to see if users outside of the GitHub community have discussed the issue. - Collect information about the bug, e.g., Stack trace (Traceback), OS, platform, and version, etc. - #### How to submit a good bug report? - Open an issue using the **Bug Report** template. - Explain the behavior you would expect and the actual behavior. -- Provide as much context as possible and describe the *reproduction steps* that someone else can follow to recreate the issue on their own. This usually includes your code. For good bug reports you should isolate the problem and create a reduced test case. +- Provide as much context as possible and describe the _reproduction steps_ that someone else can follow to recreate the issue on their own. This usually includes your code. For good bug reports you should isolate the problem and create a reduced test case. - Provide the information you collected in the previous section. Once submitted, the team will try to reproduce the issue with your provided steps, and label the issue accordingly. ## Requesting Features -Features requests are tracked as GitHub issues. +Features requests are tracked as GitHub issues. #### Before Submitting a feature request @@ -121,7 +126,6 @@ Features requests are tracked as GitHub issues. - Search existing issues to see if the feature has already been requested. If it has, add a comment to the existing issue instead of opening a new one. - Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset. - #### How to submit a good feature request? - Open an issue using the **Feature Request** template. diff --git a/docs/README.md b/docs/README.md index 1b15e8a..184ac94 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,4 +1,5 @@ # AWS Lambda Templates - Python + [![Python](https://img.shields.io/badge/python-3.14+-3776AB.svg?logo=python&style=flat-square)](https://python.org) [![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](LICENSE.md) [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=cur8d_lambda&metric=coverage)](https://sonarcloud.io/summary/new_code?id=cur8d_lambda) @@ -45,25 +46,28 @@ Templates come pre-wired with: - **Tool Management & Tasks**: [mise](https://mise.jdx.dev/) for managing project tools and automating common development tasks ### GitHub files + The repository also comes preloaded with these GitHub files: - AI Agent guidelines - Pull request template - Issue templates - + Bug report - + Feature request - + Question + - Bug report + - Feature request + - Question - Contributing guidelines - Funding file - Code owners - MIT License ## How to use + Click the button below (or [use this link](https://github.com/amrabed/aws-lambda-templates/generate)) to create a new repository for your project, then clone the new repository. Enjoy! [![Use this template](https://img.shields.io/badge/Use%20this%20template-238636?style=for-the-badge)](https://github.com/amrabed/aws-lambda-templates/generate) ### Initialize the project + Run `mise run init` once after cloning, before any other setup steps: ```bash @@ -72,42 +76,52 @@ mise run init --name="my-project" --description="My project description" --autho Pass the following parameters: -Parameter | Description ---- | --- -`name` | Project new name -`description` | Project short description -`author` | Author name -`email` | Author email -`github` | GitHub username +| Parameter | Description | +| ------------- | ------------------------- | +| `name` | Project new name | +| `description` | Project short description | +| `author` | Author name | +| `email` | Author email | +| `github` | GitHub username | ## Prerequisites ### Dev container + - Docker ### Local environment + - [mise](https://mise.jdx.dev/) - Docker (for running LocalStack locally) ## Setup ### Set up dev environment + To set up the local dev environment, run: + ```bash mise run dev ``` + That will: + - Install the project dependencies defined in `pyproject.toml` - Install the pre-commit hooks for the project to format and lint your code automatically before committing ### Format and lint code + To format and lint project code, run: + ```bash mise run lint # alias: l ``` ### Run tests with coverage + To run all tests (including Hypothesis property-based tests) and show the coverage report, run: + ```bash mise run test # alias: t ``` @@ -124,8 +138,8 @@ mise run new # alias: n This runs the `new` script, which builds a skeleton for the new template from `.template`. - ### Synthesize infrastructure + Infrastructure is defined as AWS CDK stacks under `infra/stacks/`. The CDK entry point is `infra/app.py`. @@ -140,39 +154,47 @@ mise run deploy # alias: d ``` Pass `--profile` (or `-p`) to use a named AWS CLI profile: + ```bash mise run deploy --profile ``` ### Destroy a stack + ```bash mise run destroy # alias: D ``` ### Deploy a stack locally (LocalStack) + To deploy CDK stacks locally without an AWS account: 1. Copy `.env.local.example` to `.env.local` and set your auth token from [app.localstack.cloud](https://app.localstack.cloud): + ```bash cp .env.local.example .env.local ``` 2. Start LocalStack via Docker Compose: + ```bash mise run local:up ``` 3. Deploy the stack to LocalStack: + ```bash mise run local:deploy # aliases: local , dl ``` ### Destroy a local stack + ```bash mise run local:destroy # alias: Dl ``` To stop the LocalStack container when finished: + ```bash mise run local:down ``` @@ -180,6 +202,7 @@ mise run local:down ### Generating documentation To build and publish the project documentation to GitHub Pages, run: + ```bash mise run docs ``` @@ -187,7 +210,9 @@ mise run docs That pushes the new documentation to the `gh-pages` branch. Make sure GitHub Pages is enabled in your repository settings and using the `gh-pages` branch for the documentation to be publicly available. ### Local preview + To serve the documentation on a local server, run: + ```bash mise run docs-local ``` @@ -197,6 +222,7 @@ mise run docs-local The project includes a `sonar-project.properties` file and a `verify` GitHub Actions workflow step to automatically scan your code. To enable SonarCloud analysis in GitHub Actions: + 1. Create a project on [SonarCloud](https://sonarcloud.io) and get a token. 2. In your GitHub repository, go to **Settings > Secrets and variables > Actions**. 3. Add a new repository secret named `SONAR_TOKEN` with your token value. @@ -209,7 +235,6 @@ To enable SonarCloud analysis in GitHub Actions: - **Documentation**: Every field in a Pydantic model must include a `Field(description="...")`. - **Repository Pattern**: All database calls are encapsulated in a `Repository` class for better testability. - ## Project Structure ``` diff --git a/docs/reference/repository.md b/docs/reference/repository.md index f966916..214b5d7 100644 --- a/docs/reference/repository.md +++ b/docs/reference/repository.md @@ -1,2 +1,3 @@ # DynamoDB Repository + ::: templates.repository diff --git a/docs/template/agent.md b/docs/template/agent.md index cfb67a6..cb89f5d 100644 --- a/docs/template/agent.md +++ b/docs/template/agent.md @@ -45,21 +45,19 @@ def get_item(item_id: str) -> dict: return handler.get_item(item_id) ``` - ### Item model -Field | Type | Description | Required ---- | --- | --- | --- -`id` | UUID string | Unique item identifier (auto-generated, 1-50 chars) | No -`name` | string | Human-readable item name (1-100 chars) | Yes -`description` | string | Human-readable item description (max 500 chars) | No - +| Field | Type | Description | Required | +| ------------- | ----------- | --------------------------------------------------- | -------- | +| `id` | UUID string | Unique item identifier (auto-generated, 1-50 chars) | No | +| `name` | string | Human-readable item name (1-100 chars) | Yes | +| `description` | string | Human-readable item description (max 500 chars) | No | ### Environment variables -Variable | Description | Required | Default ---- | --- | --- | --- -`TABLE_NAME` | DynamoDB table name | Yes | - -`SERVICE_NAME` | Powertools service name | No | `bedrock-agent` -`METRICS_NAMESPACE` | Powertools metrics namespace | No | `BedrockAgent` -`LOG_LEVEL` | Log level for the Lambda Logger | No | `INFO` +| Variable | Description | Required | Default | +| ------------------- | ------------------------------- | -------- | --------------- | +| `TABLE_NAME` | DynamoDB table name | Yes | - | +| `SERVICE_NAME` | Powertools service name | No | `bedrock-agent` | +| `METRICS_NAMESPACE` | Powertools metrics namespace | No | `BedrockAgent` | +| `LOG_LEVEL` | Log level for the Lambda Logger | No | `INFO` | diff --git a/docs/template/api.md b/docs/template/api.md index eb2a179..4f3896a 100644 --- a/docs/template/api.md +++ b/docs/template/api.md @@ -1,4 +1,5 @@ # REST API + A Lambda function that handles GET/POST requests from a REST API and loads/stores records into a DynamoDB table. ## Architecture @@ -27,23 +28,23 @@ mise run deploy api ### Endpoints -Endpoint | Description | Response codes ---- | --- | --- -`GET /items/{id}` | Retrieve an item by ID | 200 (OK), 400 (Bad Request), 404 (Not Found), 500 (Internal Server Error) -`POST /items` | Create a new item | 201 (Created), 422 (Unprocessable Entity), 500 (Internal Server Error) +| Endpoint | Description | Response codes | +| ----------------- | ---------------------- | ------------------------------------------------------------------------- | +| `GET /items/{id}` | Retrieve an item by ID | 200 (OK), 400 (Bad Request), 404 (Not Found), 500 (Internal Server Error) | +| `POST /items` | Create a new item | 201 (Created), 422 (Unprocessable Entity), 500 (Internal Server Error) | ### Item model -Field | Type | Description | Required ---- | --- | --- | --- -`id` | UUID string | Unique item identifier (auto-generated, 1-50 chars) | No -`name` | string | Human-readable item name (1-100 chars) | Yes +| Field | Type | Description | Required | +| ------ | ----------- | --------------------------------------------------- | -------- | +| `id` | UUID string | Unique item identifier (auto-generated, 1-50 chars) | No | +| `name` | string | Human-readable item name (1-100 chars) | Yes | ### Environment variables -Variable | Description | Required | Default ---- | --- | --- | --- -`TABLE_NAME` | DynamoDB table name | Yes | - -`SERVICE_NAME` | Powertools service name | No | `rest-api` -`METRICS_NAMESPACE` | Powertools metrics namespace | No | `RestApi` -`LOG_LEVEL` | Log level for the Lambda Logger | No | `INFO` +| Variable | Description | Required | Default | +| ------------------- | ------------------------------- | -------- | ---------- | +| `TABLE_NAME` | DynamoDB table name | Yes | - | +| `SERVICE_NAME` | Powertools service name | No | `rest-api` | +| `METRICS_NAMESPACE` | Powertools metrics namespace | No | `RestApi` | +| `LOG_LEVEL` | Log level for the Lambda Logger | No | `INFO` | diff --git a/docs/template/eventbridge.md b/docs/template/eventbridge.md index 367620d..7d900ad 100644 --- a/docs/template/eventbridge.md +++ b/docs/template/eventbridge.md @@ -1,4 +1,5 @@ # EventBridge — API Caller + A Lambda function triggered by an Amazon EventBridge rule that loads an authentication token from AWS Secrets Manager, calls an external HTTP API, and persists the response to a DynamoDB table. ## Architecture @@ -12,8 +13,8 @@ The template sets up: ![Architecture diagram showing an EventBridge rule triggering an AWS Lambda function, which retrieves an API token from Secrets Manager, calls an external API, and saves the response to DynamoDB.](diagrams/eventbridge.png) - ## Code + - **Function code**: [`templates/eventbridge`](/templates/eventbridge) - **Unit tests**: [`tests/eventbridge`](/tests/eventbridge) - **Infra stack**: [`infra/stacks/eventbridge.py`](/infra/stacks/eventbridge.py) @@ -28,27 +29,28 @@ mise run deploy eventbridge ### Data models -Model | Description ---- | --- -`EventBridgeEvent` | Incoming EventBridge event payload (`source`, `detail_type`, `detail`) -`ApiResponse` | Response from the external HTTP API (`id`, `message`) -`Settings` | Runtime configuration from environment variables +| Model | Description | +| ------------------ | ---------------------------------------------------------------------- | +| `EventBridgeEvent` | Incoming EventBridge event payload (`source`, `detail_type`, `detail`) | +| `ApiResponse` | Response from the external HTTP API (`id`, `message`) | +| `Settings` | Runtime configuration from environment variables | #### ApiResponse + Written to the DynamoDB table after calling the external API. -Field | Type | Description | Required ---- | --- | --- | --- -`id` | string | Unique identifier of the API response record (1-50 chars) | No -`message` | string | Message returned by the external API (1-1000 chars) | Yes +| Field | Type | Description | Required | +| --------- | ------ | --------------------------------------------------------- | -------- | +| `id` | string | Unique identifier of the API response record (1-50 chars) | No | +| `message` | string | Message returned by the external API (1-1000 chars) | Yes | ### Environment variables -Variable | Description | Required | Default ---- | --- | --- | --- -`API_URL` | URL of the external HTTP API to call | Yes | - -`TABLE_NAME` | DynamoDB table name for persisting API responses | Yes | - -`SECRET_NAME` | AWS Secrets Manager secret name holding the API token | Yes | - -`SERVICE_NAME` | Powertools service name | No | `eventbridge` -`METRICS_NAMESPACE` | CloudWatch metrics namespace | No | `EventBridge` -`LOG_LEVEL` | Log level for the Lambda Logger | No | `INFO` +| Variable | Description | Required | Default | +| ------------------- | ----------------------------------------------------- | -------- | ------------- | +| `API_URL` | URL of the external HTTP API to call | Yes | - | +| `TABLE_NAME` | DynamoDB table name for persisting API responses | Yes | - | +| `SECRET_NAME` | AWS Secrets Manager secret name holding the API token | Yes | - | +| `SERVICE_NAME` | Powertools service name | No | `eventbridge` | +| `METRICS_NAMESPACE` | CloudWatch metrics namespace | No | `EventBridge` | +| `LOG_LEVEL` | Log level for the Lambda Logger | No | `INFO` | diff --git a/docs/template/graphql.md b/docs/template/graphql.md index 9d7de0a..14f860e 100644 --- a/docs/template/graphql.md +++ b/docs/template/graphql.md @@ -36,22 +36,22 @@ The GraphQL schema is defined in `templates/graphql/schema.graphql`: ```graphql schema { - query: Query - mutation: Mutation + query: Query + mutation: Mutation } type Query { - getItem(id: ID!): Item - listItems: [Item] + getItem(id: ID!): Item + listItems: [Item] } type Mutation { - createItem(name: String!): Item + createItem(name: String!): Item } type Item { - id: ID! - name: String! + id: ID! + name: String! } ``` @@ -79,16 +79,16 @@ def create_item(name: str) -> dict: ### Item model -Field | Type | Description | Required ---- | --- | --- | --- -`id` | UUID string | Unique item identifier (auto-generated, 1-50 chars) | No -`name` | string | Human-readable item name (1-100 chars) | Yes +| Field | Type | Description | Required | +| ------ | ----------- | --------------------------------------------------- | -------- | +| `id` | UUID string | Unique item identifier (auto-generated, 1-50 chars) | No | +| `name` | string | Human-readable item name (1-100 chars) | Yes | ### Environment variables -Variable | Description | Required | Default ---- | --- | --- | --- -`TABLE_NAME` | DynamoDB table name | Yes | - -`SERVICE_NAME` | Powertools service name | No | `graphql-api` -`METRICS_NAMESPACE` | Powertools metrics namespace | No | `GraphQLApi` -`LOG_LEVEL` | Log level for the Lambda Logger | No | `INFO` +| Variable | Description | Required | Default | +| ------------------- | ------------------------------- | -------- | ------------- | +| `TABLE_NAME` | DynamoDB table name | Yes | - | +| `SERVICE_NAME` | Powertools service name | No | `graphql-api` | +| `METRICS_NAMESPACE` | Powertools metrics namespace | No | `GraphQLApi` | +| `LOG_LEVEL` | Log level for the Lambda Logger | No | `INFO` | diff --git a/docs/template/s3.md b/docs/template/s3.md index 64aa77d..9ad8209 100644 --- a/docs/template/s3.md +++ b/docs/template/s3.md @@ -1,4 +1,5 @@ # S3 to SQS + A Lambda function that receives S3 object-creation events, transforms each record into a typed `ProcessedMessage`, and publishes it to an SQS queue. ## Architecture @@ -27,18 +28,18 @@ mise run deploy s3 ### ProcessedMessage model -Field | Type | Description | Required ---- | --- | --- | --- -`bucket` | string | S3 bucket name (3-63 chars) | Yes -`key` | string | S3 object key (1-1024 chars) | Yes -`event_time` | string | ISO-8601 event timestamp | Yes -`source` | string | Origin event source (`s3`) | No (default: `s3`) +| Field | Type | Description | Required | +| ------------ | ------ | ---------------------------- | ------------------ | +| `bucket` | string | S3 bucket name (3-63 chars) | Yes | +| `key` | string | S3 object key (1-1024 chars) | Yes | +| `event_time` | string | ISO-8601 event timestamp | Yes | +| `source` | string | Origin event source (`s3`) | No (default: `s3`) | ### Environment variables -Variable | Description | Required | Default ---- | --- | --- | --- -`SQS_QUEUE_URL` | SQS queue URL to publish processed messages to | Yes | - -`SERVICE_NAME` | Powertools service name | No | `s3-processor` -`METRICS_NAMESPACE` | CloudWatch Metrics namespace | No | `S3Processor` -`LOG_LEVEL` | Log level for the Lambda Logger | No | `INFO` +| Variable | Description | Required | Default | +| ------------------- | ---------------------------------------------- | -------- | -------------- | +| `SQS_QUEUE_URL` | SQS queue URL to publish processed messages to | Yes | - | +| `SERVICE_NAME` | Powertools service name | No | `s3-processor` | +| `METRICS_NAMESPACE` | CloudWatch Metrics namespace | No | `S3Processor` | +| `LOG_LEVEL` | Log level for the Lambda Logger | No | `INFO` | diff --git a/docs/template/sqs.md b/docs/template/sqs.md index 31fd0f8..588146c 100644 --- a/docs/template/sqs.md +++ b/docs/template/sqs.md @@ -1,4 +1,5 @@ # SQS — Batch Processing + A Lambda function that handles SQS messages by batch processing them and storing the processed results into a DynamoDB table. Partial batch failure reporting is enabled so that individual record failures do not cause the entire batch to be retried. @@ -29,27 +30,29 @@ mise run deploy sqs ### Data models #### SqsMessage + Parsed from the SQS message body. -Field | Type | Description | Required ---- | --- | --- | --- -`id` | string | Unique identifier for the message (1-50 chars) | No -`content` | string | The main content of the message (1-1000 chars) | Yes +| Field | Type | Description | Required | +| --------- | ------ | ---------------------------------------------- | -------- | +| `id` | string | Unique identifier for the message (1-50 chars) | No | +| `content` | string | The main content of the message (1-1000 chars) | Yes | #### ProcessedItem + Written to the DynamoDB table. -Field | Type | Description | Required ---- | --- | --- | --- -`id` | string | Unique identifier for the item (partition key, 1-50 chars) | No -`content` | string | The processed content (1-1000 chars) | Yes -`status` | string | Processing status (1-50 chars) | Yes +| Field | Type | Description | Required | +| --------- | ------ | ---------------------------------------------------------- | -------- | +| `id` | string | Unique identifier for the item (partition key, 1-50 chars) | No | +| `content` | string | The processed content (1-1000 chars) | Yes | +| `status` | string | Processing status (1-50 chars) | Yes | ### Environment variables -Variable | Description | Required | Default ---- | --- | --- | --- -`TABLE_NAME` | Destination DynamoDB table name | Yes | - -`SERVICE_NAME` | Powertools service name | No | `sqs-processor` -`METRICS_NAMESPACE` | Powertools metrics namespace | No | `SqsProcessor` -`LOG_LEVEL` | Log level for the Lambda Logger | No | `INFO` +| Variable | Description | Required | Default | +| ------------------- | ------------------------------- | -------- | --------------- | +| `TABLE_NAME` | Destination DynamoDB table name | Yes | - | +| `SERVICE_NAME` | Powertools service name | No | `sqs-processor` | +| `METRICS_NAMESPACE` | Powertools metrics namespace | No | `SqsProcessor` | +| `LOG_LEVEL` | Log level for the Lambda Logger | No | `INFO` | diff --git a/docs/template/stream.md b/docs/template/stream.md old mode 100644 new mode 100755 index aa17a5b..84d7294 --- a/docs/template/stream.md +++ b/docs/template/stream.md @@ -1,6 +1,7 @@ # DynamoDB Stream — Batch Processing + A Lambda function that handles INSERT/MODIFY/DELETE events on items of a source DynamoDB table by batch processing the records and upserting/deleting processed items into/from a destination DynamoDB table. -Partial batch failure reporting is enabled so that individual record failures do not cause the entire batch to be retried. +Partial batch failure reporting is enabled so that individual record failures do not cause the entire batch to be retried. ## Architecture @@ -12,7 +13,6 @@ The template sets up: ![Architecture diagram showing a DynamoDB Stream capturing changes from a source table and triggering an AWS Lambda function to batch-process and upsert records into a destination DynamoDB table.](diagrams/stream.png) - ## Code - **Function code**: [`templates/stream`](/templates/stream) @@ -27,31 +27,32 @@ Deploy the stack using: mise run deploy stream ``` - ### Data models #### SourceItem + Read from the source table stream. -Field | Type | Description | Required ---- | --- | --- | --- -`id` | string | Unique item identifier (1-50 chars) | Yes -`name` | string | Human-readable item name (optional, 1-100 chars) | No +| Field | Type | Description | Required | +| ------ | ------ | ------------------------------------------------ | -------- | +| `id` | string | Unique item identifier (1-50 chars) | Yes | +| `name` | string | Human-readable item name (optional, 1-100 chars) | No | #### DestinationItem + Written to the destination table. -Field | Type | Description | Required ---- | --- | --- | --- -`id` | string | Unique item identifier (1-50 chars) | Yes -`name` | string | Human-readable item name (optional, 1-100 chars) | No +| Field | Type | Description | Required | +| ------ | ------ | ------------------------------------------------ | -------- | +| `id` | string | Unique item identifier (1-50 chars) | Yes | +| `name` | string | Human-readable item name (optional, 1-100 chars) | No | ### Environment variables -Variable | Description | Required | Default ---- | --- | --- | --- -`SOURCE_TABLE_NAME` | Source DynamoDB table name (stream source) | Yes | - -`DESTINATION_TABLE_NAME` | Destination DynamoDB table name | Yes | - -`SERVICE_NAME` | Powertools service name | No | `dynamodb-stream` -`METRICS_NAMESPACE` | Powertools metrics namespace | No | `DynamoDBStream` -`LOG_LEVEL` | Log level for the Lambda Logger | No | `INFO` +| Variable | Description | Required | Default | +| ------------------------ | ------------------------------------------ | -------- | ----------------- | +| `SOURCE_TABLE_NAME` | Source DynamoDB table name (stream source) | Yes | - | +| `DESTINATION_TABLE_NAME` | Destination DynamoDB table name | Yes | - | +| `SERVICE_NAME` | Powertools service name | No | `dynamodb-stream` | +| `METRICS_NAMESPACE` | Powertools metrics namespace | No | `DynamoDBStream` | +| `LOG_LEVEL` | Log level for the Lambda Logger | No | `INFO` | diff --git a/mkdocs.yml b/mkdocs.yml index 4ec3a1d..acf9ae9 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -2,7 +2,7 @@ site_name: AWS Lambda Templates - Python repo_url: https://github.com/amrabed/aws-lambda-templates repo_name: amrabed/aws-lambda-templates edit_uri: edit/main/docs/ -copyright: Copyright © 2026 +copyright: Copyright © 2026 theme: name: material @@ -22,48 +22,48 @@ theme: icon: material/brightness-4 name: Switch to light mode features: - - announce.dismiss - - content.action.edit - - content.action.view - - content.code.annotate - - content.code.copy - - content.tooltips - - navigation.footer - - navigation.indexes - - navigation.sections - - navigation.tabs - - navigation.tabs.sticky - - navigation.tracking - - navigation.top - - search.highlight - - search.suggest - - toc.follow + - announce.dismiss + - content.action.edit + - content.action.view + - content.code.annotate + - content.code.copy + - content.tooltips + - navigation.footer + - navigation.indexes + - navigation.sections + - navigation.tabs + - navigation.tabs.sticky + - navigation.tracking + - navigation.top + - search.highlight + - search.suggest + - toc.follow nav: - Overview: - - Overview: README.md - - Contributing: CONTRIBUTING.md - - License: LICENSE.md + - Overview: README.md + - Contributing: CONTRIBUTING.md + - License: LICENSE.md - Templates: - - Bedrock Agent: template/agent.md - - GraphQL API: template/graphql.md - - REST API: template/api.md - - DynamoDB Stream: template/stream.md - - EventBridge: template/eventbridge.md - - S3 to SQS: template/s3.md - - SQS to DynamoDB: template/sqs.md + - Bedrock Agent: template/agent.md + - GraphQL API: template/graphql.md + - REST API: template/api.md + - DynamoDB Stream: template/stream.md + - EventBridge: template/eventbridge.md + - S3 to SQS: template/s3.md + - SQS to DynamoDB: template/sqs.md - Reference: - - Bedrock Agent: reference/agent.md - - GraphQL API: reference/graphql.md - - REST API: reference/api.md - - DynamoDB Stream: reference/stream.md - - EventBridge: reference/eventbridge.md - - S3: reference/s3.md - - SQS: reference/sqs.md - - Models: reference/models.md - - Queue: reference/queue.md - - Repository: reference/repository.md - - Settings: reference/settings.md + - Bedrock Agent: reference/agent.md + - GraphQL API: reference/graphql.md + - REST API: reference/api.md + - DynamoDB Stream: reference/stream.md + - EventBridge: reference/eventbridge.md + - S3: reference/s3.md + - SQS: reference/sqs.md + - Models: reference/models.md + - Queue: reference/queue.md + - Repository: reference/repository.md + - Settings: reference/settings.md plugins: - search @@ -72,4 +72,4 @@ plugins: python: paths: [.] options: - docstring_style: google # Or numpy, reST, etc., based on your code style + docstring_style: google # Or numpy, reST, etc., based on your code style diff --git a/templates/graphql/schema.graphql b/templates/graphql/schema.graphql index 920f2a1..b99942d 100644 --- a/templates/graphql/schema.graphql +++ b/templates/graphql/schema.graphql @@ -1,18 +1,18 @@ schema { - query: Query - mutation: Mutation + query: Query + mutation: Mutation } type Query { - getItem(id: ID!): Item - listItems: [Item] + getItem(id: ID!): Item + listItems: [Item] } type Mutation { - createItem(name: String!): Item + createItem(name: String!): Item } type Item { - id: ID! - name: String! + id: ID! + name: String! }