Node
Architect runtime helpers are optional but they do make working with CloudFormation provisioned resources nicer. CloudFormation 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 runtime discovery as a first class concern.
Amazon Resource Names (ARNs) are available at runtime to all Lambda functions defined in the same
app.arc
. 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 people friendly and readable names defined in theapp.arc
file.
Setup
Install the Architect runtime helpers for Node:
npm install @architect/functions
Ensure arc
is available to your Lambda function code:
let arc = require('@architect/functions')
API
arc.static
Get a@static
asset patharc.http.async
Middleware for@http
functionsarc.http.express
Express support for@http
functionsarc.http.proxy
Middleware for@static
assetsarc.http.session
Sessions for@http
functionsarc.tables
Generates a DynamoDB client for@tables
arc.events
Publish/subscribe helpers for SNS@events
functionsarc.queues
Publish/subscribe helpers for SQS@queues
functionsarc.ws
WebSocket helpers for@ws
functions
arc.static
Get a static asset path:
let css = arc.static('/index.css')
arc.http.async
Middleware with async
functions is defined on arc.http.async
with middleware functions as parameters. The returned function adheres to the expected AWS Lambda function signature. A function can exit the middleware queue early by returning an HTTP response.
let arc = require('@architect/functions')
exports.handler = arc.http.async(auth, handler)
async function auth(request) {
if (!request.session.account) {
return { status: 403 }
}
}
async function handler(request) {
return {
json: { ok: true }
}
}
Request
The incoming request object is the standard API Gateway request with a few enhancements:
body
is automatically parsedsession
automatically parsed from the request cookie
Response
Architect honors the standard API Gateway response payload parameters:
statusCode
headers
body
isBase64Encoded
And adds the following clean convenience params:
cacheControl
sets theCache-Control
headercss
sets theContent-Type
header totext/css; charset=utf8
code
alias forstatusCode
cors
sets theAccess-Control-Allow-Origin
header to*
html
sets theContent-Type
header totext/html; charset=utf8
js
sets theContent-Type
header totext/javascript; charset=utf8
json
sets theContent-Type
header toapplication/json
session
write a value to the sessionstatus
also an alias forstatusCode
text
sets theContent-Type
header totext/plain; charset=utf8
type
sets theContent-Type
headerxml
sets theContent-Type
header totext/xml; charset=utf8
arc.http.express
Express migration helper.
let arc = require('@architect/functions')
let express = require('express')
let app = express()
app.get('/', (req, res) => res.send('Hello World!'))
app.get('/cool', (req, res)=> res.send('very cool'))
exports.handler = arc.http.express(app)
arc.http.proxy
Middleware for serving @static
folder assets.
let arc = require('@architect/functions')
let asap = arc.http.proxy({
spa: false,
alias: {
'/playground': '/playground.html'
}
})
exports.handler = arc.http.async(asap)
arc.http.session
Read the current session in an @http
request and write it back to a cookie.
async function handler (req) {
// read the session
let session = await arc.http.session.read(req)
// save the session into a cookie string
let cookie = await arc.http.session.write({ count: 1 })
// write the cookie to the browser
return {
statusCode: 200,
headers: { 'set-cookie': cookie },
}
}
arc.tables
Create a DynamoDB client for @tables
.
Given the following app.arc
file:
@app
testapp
@tables
notes
personID *String
noteID **String
Generate a data access layer:
let arc = require('@architect/functions')
let data = await arc.tables()
For the example above the generated API is:
data.notes.get
data.notes.query
data.notes.scan
data.notes.put
data.notes.delete
data.notes.update
The generated client is facade for
AWS.DynamoDB.DocumentClient
. Thedelete
andget
methods take a single parameter that is passed on to theparams.Key
attribute in the correspondingDocumentClient
method. Theput
method takes a single parameter that is passed on as theparams.Item
attribute in theDocumentClient.put
method. Thequery
,scan
, andupdate
methods simply pass theparams
argument with theTableName
parameter prepopulated. See the official DynamoDB documentation for all available parameters.
The generated data layer also allows direct access to DynamoDB through a few methods:
data._db
which returns an instance ofAWS.DynamoDB
data._doc
returns an instance ofAWS.DynamoDB.DocumentClient
data._name
helper function that returns a@table
resource name when you need to go lower level. For example usedata._name("my-table")
to get the name of the "my-table"@table
resource.
arc.events
Subscribe to an SNS topic
let arc = require('@architect/functions')
exports.handler = arc.events.subscribe(handler)
async function handler (event) {
console.log(event)
}
Publish to an SNS topic
let arc = require('@architect/functions')
await arc.events.publish({
name: 'hit-counter',
payload: {hits: 1},
})
arc.queues
Subscribe to an SQS queue
let arc = require('@architect/functions')
exports.handler = arc.queues.subscribe(handler)
async function handler (event) {
console.log(event)
}
Publish to an SQS queue
let arc = require('@architect/functions')
await arc.queues.publish({
name: 'hit-counter',
payload: {hits: 1},
})
arc.ws
Send a message over WebSockets.
let arc = require('@architect/functions')
await arc.ws.send({
id: connectionId,
payload: { message: 'hai 🐶' }
})