Tutorial: Building a community on-boarding app with Serverless, StepFunctions, and StackStorm

Are you a serverless developer using the Serverless framework who wants to supercharge your functions with pre-built integrations? Or maybe a StackStorm user who wants to bring the power of StackStorm Exchange to your AWS environment?

If you‘ve got a couple hours to spare and want a guided project that‘s a bit more in-depth than yet another "hello world" example, you‘re in the right place. Over the course of this multi-part tutorial, we‘ll build a real-world serverless application that automates the process of on-boarding new users to a community Slack team.

Here‘s an overview of what the final app will do:

  1. Present a registration form to collect info from prospective new members
  2. Pass the form data to a StepFunction workflow for processing
  3. Use a StackStorm Slack integration to invite the user to our team
  4. Create a contact record in a CRM system
  5. Store the new member info in a DynamoDB table

We‘ll be implementing this with the Serverless framework, AWS Lambda and StepFunctions, and ready-made integrations from StackStorm Exchange.

Sound interesting? Great, let‘s get started! We‘ll take it step-by-step over the course of a few posts. Here‘s what we‘ll cover in part one:

Prerequisites

Before we dive in, let‘s make sure you have the tools you‘ll need.

  • An AWS account and some basic familiarity with AWS services like Lambda and API Gateway. You don‘t need to be an expert but some experience will help.
  • Node.js – version 8.4.0 or higher. Installation instructions here.
  • The Serverless framework. Run npm install -g serverless to install it globally after installing Node.js.
  • Docker. The StackStorm plugin uses Docker to provide a consistent local testing environment. Guides for OS X, Windows, and Linux.
  • A Slack workspace to test with. It only takes a moment to create a new one if you don‘t have a sandbox space already. You‘ll need admin privileges.

Once you have your Slack workspace set up, you‘ll need to grab an API token. Go to the Legacy Token page and generate a token.

Pro Tip: If you prefer, you can grab your own user token instead. It‘s quicker for development purposes but not recommended for real apps.

With that, we should have everything we need. On to the code!

Creating a Serverless Project

Create a new directory for the project and initialize it with npm init:

$ mkdir community-signup
$ cd community-signup 
$ npm init

Answer the prompts (or just hit enter to accept defaults) to generate a package.json file.

Next, let‘s install the serverless-plugin-stackstorm plugin. This is our bridge between the Serverless framework and StackStorm Exchange:

$ npm install --save-dev serverless-plugin-stackstorm

With the plugin installed, create a serverless.yml file in the project root to tell Serverless to use it:

# serverless.yml

plugins:
  - serverless-plugin-stackstorm

We now have a (very minimal) working Serverless project. To make sure everything is wired up correctly, try running:

$ sls stackstorm

You should see output showing a list of available commands that the StackStorm plugin adds to the serverless CLI. If you get an error, double check the steps above and consult the plugin docs for troubleshooting tips.

Adding our First Action

Now for the fun part – pulling in an action from StackStorm Exchange! The Slack pack provides a bunch of actions for working with Slack. The one we want is slack.users_admin_invite to invite new members to our team.

Before we integrate it, let‘s take a look at the action definition:

$ sls stackstorm info --action slack.users_admin_invite

slack.users_admin_invite
  Send an invitation to a slack instance.
Parameters
  email [string] (required) ... Email of user
  channels [string]  .......... Channels to add user to
  first_name [string]  ........ First name
  last_name [string]  ......... Last name
  resend [bool]  .............. Resend invitation if already invited
Config
  admin_token [string]  ....... Admin OAuth token

We can see this action takes a few parameters, but only email is required. Since we‘ll be receiving data from a signup form, let‘s use email and first_name.

The config specifies an admin_token, which is the API token we generated earlier. We‘ll need to provide that, and there are two ways to do it:

  1. Pass it as a parameter when invoking the action
  2. Specify it in the config section of our serverless.yml file

The second approach keeps sensitive tokens out of our code, so let‘s go with that. While we‘re at it, we can move the Slack-specific configuration to its own file to keep things tidy.

Create an env.yml file to hold the config:

# env.yml

slack:
  admin_token: YOUR_TOKEN_HERE

Make sure to replace YOUR_TOKEN_HERE with your actual token.

Important: The env.yml file will contain sensitive info like API keys. Be sure to add it to your .gitignore file so it doesn‘t get committed to source control!

Now update the serverless.yml file to use the config:

# serverless.yml

service: community-signup

plugins:
  - serverless-plugin-stackstorm

provider:
  name: aws
  runtime: python3.6
  stage: dev
  region: us-west-2

custom: 
  slack_config: ${file(env.yml):slack} 

functions:
  invite:
    handler: slack.users_admin_invite
    stackstorm:
      action: slack.users_admin_invite
      input: 
        email: "{{ input.body.email }}"
        first_name: "{{ input.body.first_name }}"
      output:
        body: "{{ output }}"
    events:
      - http:
          path: invite
          method: post

Let‘s break this down:

  • The provider section configures default options for our functions, like the runtime and AWS region to use.

  • custom lets us define variables that can be referenced elsewhere in the file. Here we load the Slack config from env.yml.

  • Under functions, we define our first Lambda function, named invite. The real work happens in the stackstorm section:

    • action specifies which StackStorm action to use
    • input maps the parameters our action expects to the incoming HTTP request
    • output defines what the function will return. To keep things simple, we just echo back the raw result from the action.
  • The events section sets up an API Gateway trigger so we can invoke our function via HTTP

With the configuration in place, we‘re ready to test it out!

Invoking our Action

Let‘s start by doing a quick local test using the sls stackstorm docker command:

$ sls stackstorm docker run --function invite --data ‘{"body":{"email":"[email protected]","first_name":"Alice"}}‘ 

This will spin up a local Docker container to closely replicate the AWS Lambda environment and execute our function with the sample payload. If everything is set up correctly, you should see a successful response.

Pro tip: Use the --passthrough flag to skip the actual StackStorm action invocation. This is handy for debugging the input/output mapping without making repeated calls to the live API and dealing with things like rate limiting.

With the local test passing, we‘re ready to deploy to AWS and try it live!

$ sls deploy

The first deployment takes a few minutes as it sets everything up. Subsequent deploys will be much faster.

After the deploy finishes, you‘ll see the URL for the API Gateway endpoint that was automatically created. We can use this to test our live function.

Using curl:

$ curl -X POST -H "Content-Type: application/json" -d ‘{"email":"[email protected]","first_name":"Alice"}‘ PASTE_YOUR_URL_HERE/invite

Or, if you have HTTPie installed:

$ http POST PASTE_YOUR_URL_HERE/invite [email protected] first_name=Alice

You should get back a successful response containing the email address of the invited user. And if you check Slack, you‘ll see the invitation was actually sent! We‘ve got a working serverless function that integrates with Slack, not bad for a few minutes effort.

Wrapping Up

In this first part of our tutorial, we got a basic Serverless project set up and integrated a Slack action from StackStorm Exchange to invite users to a team. We‘ve already seen how Serverless and StackStorm can help quickly build useful functions without having to write a bunch of boilerplate code.

In the next part, we‘ll add more actions to continue building out the community on-boarding workflow. Then we‘ll chain them together into an automated flow with AWS StepFunctions.

I hope you found this guide informative and practical. Please let me know if you have any questions or feedback! You can reach me on Twitter at @yourtwitterhandle.

Similar Posts