Event functions are useful for running background tasks like handling newsletter signups or click tracking. These background tasks are going to allow your application to fan out the workload to independent and scalable Lambda functions. In this article, we will be building an interactive click tracker that generates an event with a data payload that is saved to DynamoDB.
Clone repo and local development
The first step is to click the button to deploy this app to live infrastructure with Begin.
Underneath, Begin will create a new GitHub repo to your account to clone to work on locally. Each push to your default branch will trigger a new build and deploy to the staging
environment. Your CI/CD is already complete!!
When your app deploys, clone the repo, and install the dependencies.
git clone https://github.com/[username]/[your-app-name.git]
cd your-app-name
npm install
Let's first take a look at the app.arc
file:
@app
node-events
@http
post /my-event
@static
@events
my-event
@tables
data
scopeID *String
dataID **String
ttl TTL
The app.arc
file is your Infrastructure as Code, IaC. It shows the cloud functions and database that we need to deploy.
Let's look at the HTTP function that receives a POST request from the front-end. It will publish the event payload to our event function.
// src/http/post-my_event/index.js
const arc = require('@architect/functions')
exports.handler = async function http (req) {
const name = 'my-event'
const payload = arc.http.helpers.bodyParser(req)
await arc.events.publish({ name, payload })
return {
statusCode: 302,
headers: {
location: '/'
}
}
}
Next, we'll look at the event function itself. We use an Architect runtime helper to subscribe this function to the my-event
SNS topic.
// src/events/my-event/index.js
const arc = require('@architect/functions')
const data = require('@begin/data')
const table = 'interactions'
const key = 'clicks'
async function myEvent(event) {
let { name } = event
await data.incr({
table,
key,
prop: name
})
return
}
exports.handler = arc.events.subscribe(myEvent)
And finally, the front end is composed of form elements that POST the value to our HTTP function.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Begin Event Functions Example</title>
</head>
<style>
:root {
--light: #FEFEFE;
--purple: #8D30FF;
--magenta: #FF577B;
--angle: 45deg;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
color: var(--light);
font-family:
ui-sans-serif,
system-ui,
-system-ui,
-apple-system,
BlinkMacSystemFont,
Roboto, Helvetica, Arial,
sans-serif,
"Apple Color Emoji";
line-height: 1.6;
}
html,
body,
.height-100 {
height: 100%;
}
.margin-bottom1 {
margin-bottom: 1rem;
}
.padding-top5 {
padding-top: 9rem;
}
.max-width22 {
max-width: 22rem;
}
.display-flex {
display: flex;
}
.flex-direction-column {
flex-direction: column;
}
.align-items-initial {
align-items: initial;
}
.justify-content-center {
justify-content: center;
}
.justify-content-space-between {
justify-content: space-between;
}
.cursor-pointer {
cursor: pointer;
}
.border-solid {
border: 2px solid;
}
.color-light {
color: var(--light);
}
.color-purple-active:active {
color: var(--purple);
}
.linear-gradient {
background-image: linear-gradient(var(--angle), var(--magenta), var(--purple));
}
.background-size-cover {
background-size: cover;
}
.background-color-transparent {
background-color: transparent;
}
.background-color-light-active:active {
background-color: var(--light);
}
.border-color-light {
border-color: var(--light);
}
.border-radius-pill {
border-radius: 999px;
}
.padding1 {
padding: 1rem;
}
.padding-top1 {
padding-top: 1rem;
}
.padding-right2 {
padding-right: 1.5rem;
}
.padding-bottom1 {
padding-bottom: 1rem;
}
.padding-left2 {
padding-left: 1.5rem;
}
.font-size1 {
font-size: 1rem;
}
.font-weight-500 {
font-weight: 500;
}
@media only screen and (min-width:30em) {
.flex-direction-row-lg {
flex-direction: row;
}
.align-items-center-lg {
align-items: center;
}
}
</style>
<body
class="
padding-top5
padding-right2
padding-left2
linear-gradient
display-flex
flex-direction-column
align-items-initial
align-items-center-lg
"
>
<div
class="
max-width22
"
>
<h1
class="
margin-bottom1
"
>
Publish an event
</h1>
<div
class="
display-flex
flex-direction-column
flex-direction-row-lg
justify-content-space-between
margin-bottom1
"
>
<form
action=/my-event
method=POST
>
<input type="hidden" name="name" value="Bark">
<button
class="
margin-bottom1
padding-top1
padding-right2
padding-bottom1
padding-left2
font-size1
font-weight-500
color-light
color-purple-active
border-radius-pill
border-solid
border-color-light
background-color-transparent
background-color-light-active
cursor-pointer
"
>
🐶 Bark
</button>
</form>
<form
action=/my-event
method=POST
>
<input type="hidden" name="name" value="Meow">
<button
class="
margin-bottom1
padding-top1
padding-right2
padding-bottom1
padding-left2
font-size1
font-weight-500
color-light
color-purple-active
border-radius-pill
border-solid
border-color-light
background-color-transparent
background-color-light-active
cursor-pointer
"
>
😺 Meow
</button>
</form>
<form
action=/my-event
method=POST
>
<input type="hidden" name="name" value="Moo">
<button
class="
margin-bottom1
padding-top1
padding-right2
padding-bottom1
padding-left2
font-size1
font-weight-500
color-light
color-purple-active
border-radius-pill
border-solid
border-color-light
background-color-transparent
background-color-light-active
cursor-pointer
"
>
🐮 Moo
</button>
</form>
</div>
<p>
Now go check out the click tracking in your app's <a class="color-light font-weight-500" href="https://begin.com/forward/data">Begin Data console →</a>
</p>
</div>
</body>
</html>
To sum up the pattern shown here, we have a web form element that POSTs data to a Lambda function. The data is then published to an SNS Topic which is processed by an event function that is subscribed to the same SNS Topic.
Top comments (0)