Skip to content

Commit a53129c

Browse files
committed
docs(apigateway): re-add sample layout with optimizations
1 parent abd8375 commit a53129c

File tree

1 file changed

+166
-0
lines changed

1 file changed

+166
-0
lines changed

docs/core/event_handler/api_gateway.md

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -960,6 +960,172 @@ When necessary, you can set a prefix when including a router object. This means
960960
# many other related /users routing
961961
```
962962

963+
#### Sample layout
964+
965+
!!! info "We use ALB to demonstrate that the UX remains the same"
966+
967+
This sample project contains an Users function with two distinct set of routes, `/users` and `/health`, and a single function to represent a fictitious `users` service.
968+
969+
The layout optimizes for code sharing, no custom build tooling, and it uses [Lambda Layers](../../index.md#lambda-layer) to install Lambda Powertools.
970+
971+
=== "Project layout"
972+
973+
974+
```python hl_lines="6 8 10-13"
975+
.
976+
├── Pipfile # project app & dev dependencies; poetry, pipenv, etc.
977+
├── Pipfile.lock
978+
├── mypy.ini # namespace_packages = True
979+
├── .env # VSCode only. PYTHONPATH="users:${PYTHONPATH}"
980+
├── users
981+
│ ├── requirements.txt # sam build detect it automatically due to CodeUri: users, e.g. pipenv lock -r > users/requirements.txt
982+
│ ├── lambda_function.py # this will be our users Lambda fn; it could be split in folders if we want separate fns same code base
983+
│ ├── constants.py
984+
│ └── routers # routers module
985+
│ ├── __init__.py
986+
│ ├── users.py # /users routes, e.g. from routers import users; users.router
987+
│ ├── health.py # /health routes, e.g. from routers import health; health.router
988+
├── template.yaml # SAM template.yml, CodeUri: users, Handler: users.main.lambda_handler
989+
└── tests
990+
├── __init__.py
991+
├── unit
992+
│ ├── __init__.py
993+
│ └── test_users.py # unit tests for the users router
994+
│ └── test_health.py # unit tests for the health router
995+
└── functional
996+
├── __init__.py
997+
├── conftest.py # pytest fixtures for the functional tests
998+
└── test_lambda_function.py # functional tests for the main lambda handler
999+
```
1000+
1001+
=== "template.yml"
1002+
1003+
```yaml hl_lines="20-21"
1004+
AWSTemplateFormatVersion: '2010-09-09'
1005+
Transform: AWS::Serverless-2016-10-31
1006+
Description: Example service with multiple routes
1007+
Globals:
1008+
Function:
1009+
Timeout: 10
1010+
MemorySize: 512
1011+
Runtime: python3.9
1012+
Tracing: Active
1013+
Environment:
1014+
Variables:
1015+
LOG_LEVEL: INFO
1016+
POWERTOOLS_LOGGER_LOG_EVENT: true
1017+
POWERTOOLS_METRICS_NAMESPACE: MyServerlessApplication
1018+
POWERTOOLS_SERVICE_NAME: users
1019+
Resources:
1020+
UsersService:
1021+
Type: AWS::Serverless::Function
1022+
Properties:
1023+
Handler: lambda_function.lambda_handler
1024+
CodeUri: users
1025+
Layers:
1026+
# Latest version: https://awslabs.github.io/aws-lambda-powertools-python/latest/#lambda-layer
1027+
- !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPython:3
1028+
Events:
1029+
ByUser:
1030+
Type: Api
1031+
Properties:
1032+
Path: /users/{name}
1033+
Method: GET
1034+
AllUsers:
1035+
Type: Api
1036+
Properties:
1037+
Path: /users
1038+
Method: GET
1039+
HealthCheck:
1040+
Type: Api
1041+
Properties:
1042+
Path: /status
1043+
Method: GET
1044+
Outputs:
1045+
UsersApiEndpoint:
1046+
Description: "API Gateway endpoint URL for Prod environment for Users Function"
1047+
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod"
1048+
AllUsersURL:
1049+
Description: "URL to fetch all registered users"
1050+
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/users"
1051+
ByUserURL:
1052+
Description: "URL to retrieve details by user"
1053+
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/users/test"
1054+
UsersServiceFunctionArn:
1055+
Description: "Users Lambda Function ARN"
1056+
Value: !GetAtt UsersService.Arn
1057+
```
1058+
1059+
=== "users/lambda_function.py"
1060+
1061+
```python hl_lines="9 15-16"
1062+
from typing import Dict
1063+
1064+
from aws_lambda_powertools import Logger, Tracer
1065+
from aws_lambda_powertools.event_handler import ApiGatewayResolver
1066+
from aws_lambda_powertools.event_handler.api_gateway import ProxyEventType
1067+
from aws_lambda_powertools.logging.correlation_paths import APPLICATION_LOAD_BALANCER
1068+
from aws_lambda_powertools.utilities.typing import LambdaContext
1069+
1070+
from routers import health, users
1071+
1072+
tracer = Tracer()
1073+
logger = Logger()
1074+
app = ApiGatewayResolver(proxy_type=ProxyEventType.ALBEvent)
1075+
1076+
app.include_router(health.router)
1077+
app.include_router(users.router)
1078+
1079+
1080+
@logger.inject_lambda_context(correlation_id_path=APPLICATION_LOAD_BALANCER)
1081+
@tracer.capture_lambda_handler
1082+
def lambda_handler(event: Dict, context: LambdaContext):
1083+
return app.resolve(event, context)
1084+
```
1085+
1086+
=== "users/routers/health.py"
1087+
1088+
```python hl_lines="4 6-7 10"
1089+
from typing import Dict
1090+
1091+
from aws_lambda_powertools import Logger
1092+
from aws_lambda_powertools.event_handler.api_gateway import Router
1093+
1094+
router = Router()
1095+
logger = Logger(child=True)
1096+
1097+
1098+
@router.get("/status")
1099+
def health() -> Dict:
1100+
logger.debug("Health check called")
1101+
return {"status": "OK"}
1102+
```
1103+
1104+
=== "tests/functional/test_users.py"
1105+
1106+
```python hl_lines="3"
1107+
import json
1108+
1109+
from users import main # follows namespace package from root
1110+
1111+
1112+
def test_lambda_handler(apigw_event, lambda_context):
1113+
ret = main.lambda_handler(apigw_event, lambda_context)
1114+
expected = json.dumps({"message": "hello universe"}, separators=(",", ":"))
1115+
1116+
assert ret["statusCode"] == 200
1117+
assert ret["body"] == expected
1118+
```
1119+
1120+
=== ".env"
1121+
1122+
> Note: It is not needed for PyCharm (select folder as source).
1123+
1124+
This is necessary for Visual Studio Code, so integrated tooling works without failing import.
1125+
1126+
```bash
1127+
PYTHONPATH="users:${PYTHONPATH}"
1128+
```
9631129

9641130
#### Trade-offs
9651131

0 commit comments

Comments
 (0)