Source layouts
Start with Getting Started for a complete project.
The same layout is used by the Quickstart REST example
and HTTP API example.
LambdaApi accepts the public SourceLayout values
SourceLayout.ROOT and SourceLayout.SERVICE. The default is ROOT.
In all layouts, lambda_path is the directory scanned recursively. Python
files are parsed as source, and each top-level function with one or more
recognized HTTP decorators becomes a Lambda entry point. The handler name is
the Python function name. lambda_handler is a conventional name that works
well in these examples.
SourceLayout.ROOT
lambda_path is the packaging root. Every discovered handler is packaged from
that directory, and its path relative to lambda_path becomes the
index/module path.
project/
├── lambdas/
│ ├── __init__.py
│ ├── health.py
│ ├── users/
│ │ ├── __init__.py
│ │ └── handler.py
│ └── requirements.txt
└── stack.py
from lambda_api_decorators import GET
@GET("/health")
def lambda_handler(event, context):
return {"statusCode": 200, "body": "ok"}
With lambda_path="lambdas", this handler uses:
| Item | Result |
|---|---|
lambda_path | lambdas |
| entry/source directory | lambdas |
| module and handler | health.lambda_handler |
| dependencies | lambdas/requirements.txt |
For lambdas/users/handler.py, the corresponding result is entry directory
lambdas, module and handler users.handler.lambda_handler.
SourceLayout.SERVICE
The first directory below lambda_path is the packaging boundary for each
handler. Every handler must be inside such a first-level service directory;
a Python file directly under lambda_path raises ValueError.
project/
├── services/
│ ├── orders/
│ │ ├── __init__.py
│ │ ├── handlers/
│ │ │ ├── __init__.py
│ │ │ └── create.py
│ │ └── requirements.txt
│ └── users/
│ ├── __init__.py
│ ├── handlers/
│ │ ├── __init__.py
│ │ └── get.py
│ └── requirements.txt
└── stack.py
from lambda_api_decorators import POST
@POST("/orders")
def lambda_handler(event, context):
return {"statusCode": 201, "body": "created"}
With lambda_path="services", this handler uses:
| Item | Result |
|---|---|
lambda_path | services |
| entry/source directory | services/orders |
| module and handler | handlers.create.lambda_handler |
| dependencies | services/orders/requirements.txt |
The REST and HTTP builders use the same source-layout resolution. Only the API route emission differs; see REST and HTTP APIs.
Discovery and naming rules
The current discovery behavior is deliberately narrow:
- It walks
lambda_pathrecursively and considers files ending in.py. - It inspects top-level
deffunctions. Nested functions, classes, andasync deffunctions are not discovered as handlers. - A function is a route only when its decorator is a recognized direct name:
GET,POST,PUT,DELETE, orANY, called with one non-empty literal path. The decorator must be written in a form the AST parser can identify, such as@GET("/items"). - A handler with a second recognized HTTP decorator is rejected with
ValueError; declare separate functions for separate routes. - Plain
.pyfiles and files whose functions have no recognized HTTP decorator are skipped. A file with only configuration or other decorators does not become a Lambda function.
ROOT accepts handlers directly under lambda_path or at any nested depth.
SERVICE requires the first nested directory. The implementation passes the
resulting directory and Python file path to CDK's PythonFunction; therefore
use normal importable Python package/module names for directories and files
(for example, avoid spaces and hyphens), and include __init__.py files when
your package layout requires them. The code specifically rejects a string such
as "root" in place of the enum member; pass SourceLayout.ROOT or
SourceLayout.SERVICE.
The discovery code checks that route decorator paths are non-empty strings, but does not define a broader route grammar. Keep paths valid for the API Gateway resource type you select. For the complete enum definition, see the SourceLayout API reference.