How to build a Serverless Twitter bot
Tags: serverless, lambda, python, aws
Published: 2019-01-30 16:22:50

---
title: How to build a Serverless Twitter bot
published: true
description: A tutorial on how to build a Twitter bot using Serverless and AWS Lambda
tags: serverless, lambda, python, aws
cover_image: https://thepracticaldev.s3.amazonaws.com/i/82dl78b9bboi9fvx2lga.png
---

In this post I'm going to show you how to build a Twitter bot using the [Serverless Framework](https://github.com/serverless/serverless). This framework represents "the easy and open way to build serverless applications", and if you don't know what I'm talking about you should definitely check it out.

We're going to build a bot that will retweet at regular intervals the most relevant tweets about serverless computing, and will follow the tweet's author. Have a look [here](https://twitter.com/_serverlessbot_) if you're not afraid of spoilers.

For this tutorial we're using AWS Lambda with the Python 3.6 runtime, but you could easily switch to another provider/programming language. 

We are going to interact with the Twitter API using [Twython](https://twython.readthedocs.io).


# Setup the Twitter Account and App

First of all, you need to create a Twitter account for the bot and then go to [developer.twitter.com](https://developer.twitter.com/) to apply for a developer account to access the Twitter API.

After that, you can create a Twitter App and get the keys and tokens needed. The Twitter interface is easy to use and the process is quite straightforward.


# Install Serverless and configure the environment

The easiest way to install the Serverless framework is to follow their installation guide, [here](https://serverless.com/framework/docs/providers/aws/guide/installation/), and then setup the AWS credentials as shown [here](https://serverless.com/framework/docs/providers/aws/guide/credentials/). 


When the the framework is installed and configured, a new service can be easily created with:

```bash
$ serverless create \
  --template aws-python3 \
  --name serverlessbot \
  --path serverlessbot
```


Then, `cd` into the newly created directory and create a Python virtual environment using `virtualenv`:

```bash
$ cd serverlessbot
$ virtualenv venv --python=python3
```


You will need to activate the virtual environment with:

```bash
$ source venv/bin/activate
```

Now you can install the `twython` library and then save the package versions of the environment to a `requirements.txt` file.

```bash
$ pip install twython
$ pip freeze > requirements.txt
```


At this point we should be ready to start coding the bot. However, manually configuring Lambda to use external libraries could be tricky, therefore we're going to use the `serverless-python-requirements` plugin to make it easier.

First of all, initialize `npm` with:

```bash
$ npm init
```

accept all the defaults (press enter several times)
then install the plugin with:

```bash
$ npm install --save serverless-python-requirements
```

Finally, add the following at the end of your `serverless.yml` file:

```yaml
plugins:
  - serverless-python-requirements

custom:
  pythonRequirements:
    dockerizePip: non-linux
```

You can find more information on this plugin [here](https://serverless.com/blog/serverless-python-packaging/).


# Programming the bot

Now we can finally start building the bot. 

We have to change the `functions` section in the `serverless.yml` file to look like:

```yaml
functions:
  retweet:
    handler: handler.retweet
    events:
      - schedule: rate(2 hours) 
```

This will call the method `retweet` of `handler.py` every 2 hours. 

Then, we can replace the `handler.py` file with the following content:

```python
import json, config
from twython import Twython, TwythonError

def retweet(event, context):

    twitter = Twython(config.APP_KEY, config.APP_SECRET, config.OAUTH_TOKEN, config.OAUTH_TOKEN_SECRET)

    search_results = twitter.search(q='serverless', result_type='mixed', lang='en')
    message = ""

    for tweet in search_results['statuses']:
        try:
            twitter.retweet(id=tweet['id'])
            message = f"Retweeted \"{tweet['text']}\" by {tweet['user']['name']}"
            twitter.create_friendship(id=tweet['user']['id'])
            break
        except TwythonError:
            pass
 
    body = {
        "message": message,
        "input": event
    }

    response = {
        "statusCode": 200,
        "body": json.dumps(body)
    }

    return response
```

The code is quite self-explanatory. Basically, we are searching for English tweets mentioning `serverless`, retweeting them, and follow the tweet's author.

The `return response` is only for logging and testing.

As you can see, the Twitter keys and tokens are read using `config`. All you need to do is to create a `config.py` file in the same directory and fill it with the information you got from the Twitter App page:

```python
APP_KEY="xxxyyyzz"
APP_SECRET="xxxyyyzz"
OAUTH_TOKEN="xxxyyyzz-xxxyyyzz"
OAUTH_TOKEN_SECRET="xxxyyyzz"
```

# Deploying the bot

At this point, we're going to deploy the function with:

```bash
$ serverless deploy -v
```

The Serverless Framework will now take care of everything needed to deploy your Lambda function. When the process is finished, you will be able to see it in the Lambda Management Console on AWS. If you notice, there will be a CloudWatch event configured to fire the function every 2 hours. 

If you don't want to wait 2 hours, you can invoke the function directly with:

```bash
$ serverless invoke -f retweet
```

If you want to remove the function from your AWS account you can simply use:

```bash
$ serverless remove
```

That's it. You now have your own Twitter bot able to retweeting and following users. You can learn how to add many more functionalities reading the Twython documentation.


# Closing remarks

The full code used in this article is available on GitHub:

{% github lorenzotenti/serverlessbot %}


The *\_serverlessbot\_* built in this article can be found [here](https://twitter.com/_serverlessbot_).

I hope you liked this tutorial. If not, let me know why in the comments.