You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/core/event_handler/api_gateway.md
+209-9
Original file line number
Diff line number
Diff line change
@@ -896,14 +896,16 @@ Let's assume you have `app.py` as your Lambda function entrypoint and routes in
896
896
897
897
We use `include_router` method and include all user routers registered in the `router` global object.
898
898
899
-
```python hl_lines="6 8-9"
899
+
```python hl_lines="7 10-11"
900
900
from typing import Dict
901
901
902
+
from aws_lambda_powertools import Logger
902
903
from aws_lambda_powertools.event_handler import ApiGatewayResolver
903
904
from aws_lambda_powertools.utilities.typing import LambdaContext
904
905
905
906
import users
906
907
908
+
logger = Logger()
907
909
app = ApiGatewayResolver()
908
910
app.include_router(users.router)
909
911
@@ -960,22 +962,220 @@ When necessary, you can set a prefix when including a router object. This means
960
962
# many other related /users routing
961
963
```
962
964
965
+
#### Sample layout
966
+
967
+
!!! info "We use ALB to demonstrate that the UX remains the same"
968
+
969
+
This sample project contains an Users function with two distinct set of routes, `/users` and `/health`. 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.
> 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
+
```
1129
+
1130
+
### Considerations
1131
+
1132
+
This utility is optimized for fast startup, minimal feature set, and to quickly on-board customers familiar with frameworks like Flask — it's not meant to be a fully fledged framework.
1133
+
1134
+
Event Handler naturally leads to a single Lambda function handling multiple routes for a given service, which can be eventually broken into multiple functions.
1135
+
1136
+
Both single (monolithic) and multiple functions (micro) offer different set of trade-offs worth knowing.
1137
+
1138
+
!!! tip "TL;DR. Start with a monolithic function, add additional functions with new handlers, and possibly break into micro functions if necessary."
1139
+
1140
+
#### Monolithic function
1141
+
1142
+

1143
+
1144
+
A monolithic function means that your final code artifact will be deployed to a single function. This is generally the best approach to start.
1145
+
1146
+
**Benefits**
1147
+
1148
+
***Code reuse**. It's easier to reason about your service, modularize it and reuse code as it grows. Eventually, it can be turned into a standalone library.
1149
+
***No custom tooling**. Monolithic functions are treated just like normal Python packages; no upfront investment in tooling.
1150
+
***Faster deployment and debugging**. Whether you use all-at-once, linear, or canary deployments, a monolithic function is a single deployable unit. IDEs like PyCharm and VSCode have tooling to quickly profile, visualize, and step through debug any Python package.
1151
+
1152
+
**Downsides**
963
1153
964
-
#### Trade-offs
1154
+
***Cold starts**. Frequent deployments and/or high load can diminish the benefit of monolithic functions depending on your latency requirements, due to [Lambda scaling model](https://docs.aws.amazon.com/lambda/latest/dg/invocation-scaling.html){target="_blank"}. Always load test to pragmatically balance between your customer experience and development cognitive load.
1155
+
***Granular security permissions**. The micro function approach enables you to use fine-grained permissions & access controls, separate external dependencies & code signing at the function level. Conversely, you could have multiple functions while duplicating the final code artifact in a monolithic approach.
1156
+
- Regardless, least privilege can be applied to either approaches.
1157
+
***Higher risk per deployment**. A misconfiguration or invalid import can cause disruption if not caught earlier in automated testing. Multiple functions can mitigate misconfigurations but they would still share the same code artifact. You can further minimize risks with multiple environments in your CI/CD pipeline.
965
1158
966
-
!!! tip "TL;DR. Balance your latency requirements, cognitive overload, least privilege, and operational overhead to decide between one, few, or many single purpose functions."
1159
+
#### Micro function
967
1160
968
-
Route splitting feature helps accommodate customers familiar with popular frameworks and practices found in the Python community.
1161
+

969
1162
970
-
It can help better organize your code and reason
1163
+
A micro function means that your final code artifact will be different to each function deployed. This is generally the approach to start if you're looking for fine-grain control and/or high load on certain parts of your service.
971
1164
972
-
This can also quickly lead to discussions whether it facilitates a monolithic vs single-purpose function. To this end, these are common trade-offs you'll encounter as you grow your Serverless service, specifically synchronous functions.
1165
+
**Benefits**
973
1166
974
-
**Least privilege**. Start with a monolithic function, then split them as their data access & boundaries become clearer. Treat Lambda functions as separate logical resources to more easily scope permissions.
1167
+
***Granular scaling**. A micro function can benefit from the [Lambda scaling model](https://docs.aws.amazon.com/lambda/latest/dg/invocation-scaling.html){target="_blank"} to scale differently depending on each part of your application. Concurrency controls and provisioned concurrency can also be used at a granular level for capacity management.
1168
+
***Discoverability**. Micro functions are easier do visualize when using distributed tracing. Their high-level architectures can be self-explanatory, and complexity is highly visible — assuming each function is named to the business purpose it serves.
1169
+
***Package size**. An independent function can be significant smaller (KB vs MB) depending on external dependencies it require to perform its purpose. Conversely, a monolithic approach can benefit from [Lambda Layers](https://docs.aws.amazon.com/lambda/latest/dg/invocation-layers.html){target="_blank"} to optimize builds for external dependencies.
975
1170
976
-
**Package size**. Consider Lambda Layers for third-party dependencies and service-level shared code. Treat third-party dependencies as dev dependencies, and Lambda Layers as a mechanism to speed up build and deployments.
1171
+
**Downsides**
977
1172
978
-
**Cold start**. High load can diminish the benefit of monolithic functions depending on your latency requirements. Always load test to pragmatically balance between your customer experience and development cognitive load.
1173
+
***Upfront investment**. Python ecosystem doesn't use a bundler — you need a custom build tooling to ensure each function only has what it needs and account for [C bindings for runtime compatibility](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html){target="_blank"}. Operations become more elaborate — you need to standardize tracing labels/annotations, structured logging, and metrics to pinpoint root causes.
1174
+
- Engineering discipline is necessary for both approaches. Micro-function approach however requires further attention in consistency as the number of functions grow, just like any distributed system.
1175
+
***Harder to share code**. Shared code must be carefully evaluated to avoid unnecessary deployments when that changes. Equally, if shared code isn't a library,
1176
+
your development, building, deployment tooling need to accommodate the distinct layout.
1177
+
***Slower safe deployments**. Safely deploying multiple functions require coordination — AWS CodeDeploy deploys and verifies each function sequentially. This increases lead time substantially (minutes to hours) depending on the deployment strategy you choose. You can mitigate it by selectively enabling it in prod-like environments only, and where the risk profile is applicable.
1178
+
- Automated testing, operational and security reviews are essential to stability in either approaches.
Copy file name to clipboardExpand all lines: docs/core/event_handler/appsync.md
+2
Original file line number
Diff line number
Diff line change
@@ -713,6 +713,8 @@ You can subclass `AppSyncResolverEvent` to bring your own set of methods to hand
713
713
714
714
### Split operations with Router
715
715
716
+
!!! tip "Read the **[considerations section for trade-offs between monolithic and micro functions](./api_gateway.md#considerations){target="_blank"}**, as it's also applicable here."
717
+
716
718
As you grow the number of related GraphQL operations a given Lambda function should handle, it is natural to split them into separate files to ease maintenance - That's where the `Router` feature is useful.
717
719
718
720
Let's assume you have `app.py` as your Lambda function entrypoint and routes in `users.py`, this is how you'd use the `Router` feature.
0 commit comments