Patterns¶
Patterns are opinions
Everything in this section is a judgement about what is sensible, not a fact about CloudFormation, so it is kept apart from the generated types and the permission names. Treat the patterns as examples to copy and change, not as an API. See Facts first, opinions fenced.
A pattern is an ordinary function that returns a resource, or a small fragment of several resources. That is the whole idea. There is no base class, no registry and no construct tree.
A fragment is a Resources dict, a plain dict[str, AnyResource], so you combine
fragments with | and drop the result into Template["Resources"].
A pattern can also return a handle: a small dataclass with a resources field plus
the logical IDs and references callers need (orders.queue_arn). cfn.combine accepts
a dict or any handle, via the HasResources protocol.
Conventions the patterns follow¶
- Logical IDs are derived from a
nameargument and documented:queue_with_dlq("Order")createsOrderQueueandOrderDLQ. Callers then use the handle (orders.queue_arn) rather than retyping the IDs. The names are visible in the call, never generated behind your back. - A pattern that creates one resource returns that resource's type
(
iam.Role), and a pattern that creates several returnsResources, or a handle with aresourcesfield when callers need to refer back to what it made. - Inputs are typed with
Expr[T], so a caller can pass a literal or aRef/GetAtt. - Optional pieces are only emitted when given. No
Tags: []noise in the output.
Your own patterns¶
The patterns in this book are examples and a starting point. The ones that pay off most are business specific, and only you can
write them: your naming scheme, your mandatory tags and rules, how a service is wired to your platform. Write them as
ordinary functions in your own repository (see a typical project), share them between
repositories with Distributing patterns, and enforce the company's conventions with
mandatory tags and company rules. Copy a pattern from here or from
cfn-typed-sumo when it is close to what you need, and change it.
Where the code lives¶
The patterns in this book that live in a package ship as cfn-typed-sumo, a second
package built from this repository that depends on cfn-typed. It is a fat pattern library with a
volatile API, unlike the core (details):
The code is in
packages/sumo/src/cfn_typed_sumo/patterns.py,
type-checked and tested like any other code, and every snippet on these pages is pulled
straight from that file. Import them (from cfn_typed_sumo import queue_with_dlq) or copy
what you need and change it.
The package also ships the generated types its patterns use as a public module,
cfn_typed_sumo.types. They are generated from packages/sumo/cfn-typegen.toml, which lists
the resource types the patterns need plus the core and everyday services (IAM, Lambda, SQS, SNS, S3,
KMS, DynamoDB, EC2, ECS, both API Gateways, CloudFront, RDS and so on, but not all of AWS); the repository does not contain them, and CI and the
release build generate them. The snippets start from these imports:
import re
from collections.abc import Collection, Mapping, Sequence
from dataclasses import asdict, dataclass, fields
from typing import Any, Literal, TypedDict
from cfn_typed_sumo.types import iam, lambda_, sqs
from cfn_typed import AnyResource, AnyStatement, Expr, Resources, Tag, allow, arn, assume_role_policy, get_att, policy_document, ref
from cfn_typed.policy import service
from cfn_typed.checks import Rule
from cfn_typed.query import prop, resources_of
from cfn_typed.rules import each, forbid, require
Every pattern on these pages is in the package: the catalog lists them with
links to the code and the resources each one creates. Only the stacks that assemble them stay in examples/.
| Pattern | Creates |
|---|---|
| Lambda execution role | one AWS::IAM::Role |
| Queue with a dead-letter queue | {name}Queue and {name}DLQ |
| SQS-triggered Lambda | one AWS::Lambda::EventSourceMapping |
| Load balancer building blocks | a load balancer, target group, listener or ingress rule |
| HTTP API with a JWT authorizer | an HTTP API, a Lambda integration, a JWT authorizer, one route per route key and the invoke permission |
| One load balancer, several ports | security group, load balancer, and a target group and listener per port |
| Encrypted storage | a KMS key, a private bucket and its policy, a table, a repository |
| Publishing values through SSM | SSM parameters that one stack publishes and another reads |
| Parameters as variables | template parameters (including SSM), declared once and used as variables |
| CDK L2 constructs as patterns | a Lambda function, a schedule, an SNS subscription, a VPC, a Fargate service, alarms, and auto scaling for services, Lambda aliases and tables |
| Web frontends | a CloudFront static site, a REST API in front of a Lambda or a table, a Lambda behind a load balancer, DNS aliases |
| Messaging and events | an SNS fan-out to queues with dead-letter queues, EventBridge rules to a Lambda or a queue |
| Data flows | a table stream into a Lambda, a bucket that invokes a Lambda, Firehose into a bucket |
| Fargate tasks | a cluster, a task and its two roles, for workers and for tasks a Lambda starts |
| Serverless Framework in a few lines | the Serverless functions: example, a scheduled Lambda, as patterns |
| Mandatory tags | nothing, but resolves and checks the tags a company requires, from service and per-resource values |
| Company rules | nothing, but checks the finished template against rules of your own, as one more layer on the built-in checks |
| Composing fragments | nothing, but how to combine the above safely |
| A complete stack | all of the above in one template |
Moving off SAM or the Serverless Framework, and uploading and releasing code, are in Deploying and migrating.