Python runtime helpers
Architect provides an optional runtime utility package designed to make it significantly easier to work with provisioned resources and related assets: architect-functions
We strongly suggest making use of this package when developing Python handlers with Architect.
architect-functions
Setup
Install architect-functions
in your project’s root requirements.txt
file:
pip3 install architect-functions -r requirements.txt
Ensure arc
is available to your Lambda function code:
import arc
Interfaces
arc.events
Publish / subscribe helpers for@events
functionsarc.http
Request/response normalization and session support for@http
functionsarc.queues
Publish/subscribe helpers for@queues
functionsarc.services
Retrieves the Architect service map, exposing metadata for all services making up the applicationarc.tables
Generates a DynamoDB client for@tables
arc.ws
WebSocket helpers for@ws
functions
arc.events
Publish & subscribe helpers for @events
functions. Declare events with the @events
pragma.
arc.events.parse()
Parse the incoming (somewhat complicated, deeply-nested, JSON-encoded) event
:
import arc
def handler(evt):
event = arc.events.parse(evt)
print("incoming event:", event)
arc.events.publish()
Publish an event to an @events
function. Accepts two required arguments:
name
(string) - name of the@events
function you’d like to publish topayload
(dict or array) - payload to be published
import arc
def handler(event):
payload = {"hello": "there"}
arc.events.publish("some-event", payload)
arc.http
Request, response, and session methods for @http
functions. Declare HTTP routes with the @http
pragma.
arc.http.parse_body()
Parse or un-buffer the incoming @http
request’s body. Supports parsing JSON and form URL-encoded (application/x-www-form-urlencoded
) data; other data types are merely decoded from base64 buffers.
import arc
def handler(request, context):
body = arc.http.parse_body(request)
print("request body contents:", body)
arc.http.res()
arc.http.res()
provides a variety of conveniences when publishing HTTP responses, including built-in session writes, automatic compression and encoding of the response body, content-type shortcuts, and many more.
arc.http.res()
accepts two required positional arguments:
request
(dict) - the originating handler request parameterresponse
(dict) - response payload (see below)
A quick example:
import arc
def handler(req, context):
return arc.http.res(req, {"hello": "world"})
arc.http.res()
response payloads honor the standard API Gateway response payload properties (statusCode
, headers
, body
, etc.), in addition to adding the following convenience properties:
cache_control
- str- Sets the
cache-control
header (or overrides it if already present)
- Sets the
compression
- bool- Defaults to
gzip
; sets output compression of non-binary handler responses (e.g. JSON, HTML, etc.) - If requesting client does not support default (
gzip
), compression is automatically disabled - To manually disable output compression for non-binary responses, specify
False
- Defaults to
cookie
- str- Sets the
set-cookie
header (or overrides it if already present) - Note: this convenience property predates API Gateway HTTP v2.0’s
cookies
property; if using that payload format (which is Architect’s default), passingcookies
(a list) is probably better
- Sets the
cors
- bool- Sets the
access-control-allow-origin
header to*
(or overrides it if already present)
- Sets the
status
,code
,status_code
(alias ofstatusCode
) - int- Sets the response HTTP status code
session
- dict- Create or overwrite a client session; see the sessions guide for more
type
- str- Sets the
content-type
header (or overrides it if already present)
- Sets the
Additionally, you may also pass the following content properties (instead of manually setting status
, headers
, and body
):
css
- str- Sets the
content-type
header totext/css; charset=utf8
- Sets the
html
- str- Sets the
content-type
header totext/html; charset=utf8
- Sets the
js
- str- Sets the
content-type
header totext/javascript; charset=utf8
- Sets the
json
- dict or list- JSON-encodes the object or array and sets the
content-type
header toapplication/json; charset=utf8
- JSON-encodes the object or array and sets the
text
- str- Sets the
content-type
header totext/plain; charset=utf8
- Sets the
xml
- str- Sets the
content-type
header totext/xml; charset=utf8
- Sets the
Finally, you may also return an Exception, which will be interpreted as a status 500
, and output the Exception title
in HTML.
Learn more about API Gateway response payloads here
Examples
Respond with an HTML payload
import arc
def handler(req, context):
payload = {"html": "<h1>Hello, world!</h1>"}
return arc.http.res(req, payload)
Mutate a session property, then persist it via response
import arc
def handler(req, context):
session = arc.http.session_read(req)
session["count"] += 1
return arc.http.res(
req,
{
"session": session,
"json": {"ok": True},
}
)
arc.http.session_read()
Read a client session from an incoming request. Returns the client’s session dict (or {}
if none is found).
import arc
def handler(req, context):
session = arc.http.session_read(req)
print("user name:", session.get("name"))
return {"ok": True}
arc.http.session_write()
Manually write a client session. Generally we recommend writing sessions by passing a session
property via arc.http.res()
.
However, should you need additional power and flexibility when writing sessions, we expose arc.http.session_write()
for manually writing the session. This method returns a cookie that must be sent back to the client via the set-cookie
header.
import arc
import json
def handler(req, context):
session = arc.http.session_read(req)
session["count"] += 1
cookie = arc.http.session_write(session)
return {
"statusCode": 200,
"body": json.dumps({"ok": True}),
"headers": {
"set-cookie": cookie,
},
}
arc.queues
Publish & subscribe helpers for @queues
functions. Declare queues with the @queues
pragma.
arc.queues.parse()
Parse the incoming (somewhat complicated, deeply-nested, JSON-encoded) event
:
import arc
def handler(evt):
event = arc.queues.parse(evt)
print("incoming event:", event)
arc.queues.publish()
Publish an event to an @queues
function. Accepts two required arguments:
name
(string) - name of the@queues
function you’d like to publish topayload
(dict or array) - payload to be published
import arc
def handler(event):
payload = {"hello": "there"}
arc.queues.publish("some-event", payload)
arc.services()
Cloud resources are generated with names more friendly for machines than people. Other frameworks leave resource discovery up to end users, which leads to ad hoc implementations becoming a frequent bug vector. Architect treats service discovery as a first class concern.
Amazon Resource Names (ARNs) are available at runtime to all Lambda functions defined in the same Architect project manifest. Things such as DynamoDB tables, SNS topics, SQS queues, API Gateway endpoints, and S3 static bucket ARNs are baked into
@architect/functions
so your runtime program logic interacts with resources using readable, people-friendly names defined in your Architect project manifest.
arc.services()
retrieves the Architect service map: an object mapping the plugins and out-of-the-box Architect infrastructure that makes up your application.
This object is lazily-loaded and cached, and thus the first call may incur a delay as the service map is populated (use of arc.events
, arc.queues
and arc.tables
transparently uses this method in the background).
arc.services()
returns a service map object, with keys equaling any out-of-the-box Architect infrastructure types or plugins used by the Architect application.
An example service map for an application composed of @static
, @events
and an imagebucket
plugin would have the following structure:
import arc
def handler(event):
services = arc.services()
print(services)
# {
# # a plugin named 'imagebucket' exposing some service discovery variables
# "imagebucket": {
# "accessKey": "someAccessKey",
# "name": "arc-plugin-s3-image-bucket-example-image-buket",
# "secretKey": "someSecretKey"
# },
# # built-in @static service discovery variables
# "static": {
# "bucket": "arcplugins3imagebucketexamplestaging-staticbucket-g8rsuk82ancj",
# "fingerprint": "false"
# },
# # built-in @events service discovery variables
# "events": {
# "myevent": "https://some-sns-url.amazon.us-east-2.com"
# }
# }
arc.tables
Client & resource helpers for DynamoDB tables. Declare tables with the @tables
pragma.
arc.tables.name()
Helper method that accepts a logical table name string, and returns a physical AWS resource name. Helpful for when you need to go lower level than the DynamoDB resource provided by arc.tables.table()
.
For example use arc.tables.name('my-table')
to get the human-unfriendly AWS name of the my-table
@tables
resource.
import arc
def handler(event):
name = arc.tables.name('my-table')
print(name)
# MyTableStagingABC123
arc.tables.table()
Accepts a logical table name string and returns a DynamoDB client (specifically, a DynamoDB resource) for your application’s @tables
.
import arc
def handler(event):
data = arc.tables.table('my-table')
items = data.scan()
print("all data from my-table:", items.get("Items"))
arc.ws
Interact with WebSocket services. Declare endpoints with the @ws
pragma.
arc.ws.send()
Send a message via WebSocket. Accepts two required positional parameters:
id
(string) - API GatewayConnectionId
of the client you’d like to send the message topayload
(dict or list) - payload to be sent to the WebSocket client (as JSON)
# src/ws/connect/lambda.py
import arc
def handler(req, context):
connection_id = req["requestContext"]["connectionId"]
arc.ws.send(connection_id, {"hello": "there"})
arc.ws.api()
Return the internal ApiGatewayManagementApi
client from boto3
.
import arc
def handler(req, context):
api = arc.ws.api()
arc.ws.close()
Close a WebSocket connection with the provided id:
id
(string) - API GatewayconnectionId
of the client you’d like to close
import arc
def handler(req, context):
connection_id = req["requestContext"]["connectionId"]
arc.ws.close(connection_id)
arc.ws.info()
A pass-through to the ApiGatewayManagementApi#get_connection method. Retrieve information about the connection with the provided id:
id
(string) - API GatewayConnectionId
of the client you’d like get information about
# src/ws/connect/lambda.py
import arc
def handler(req, context):
connection_id = req["requestContext"]["connectionId"]
info = arc.ws.info(connection_id)
print(info)
# {
# "ConnectedAt": datetime(2023, 1, 1),
# "Identity": {
# "SourceIp": "10.0.0.1",
# "UserAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)..."
# },
# "LastActiveAt": datetime(2023, 8, 11)
# }