Cómo construir un bot de X en AWS

Code
Por: Mateo Lewinzon / Publicado el 26 may. 2024
- visitas7 min de lectura

En este artículo, voy a ir por encima del concepto de Serverless, y de cómo hice para armar el bot de X Marcus Aurelius' Meditations usando AWS Lambda y DynamoDB, sin que me cobren un sope. Esto es una muestra muy simple de algo que se puede lograr con algo muy poderoso.

Intro

En el desarrollo moderno de aplicaciones, la arquitectura serverless ha emergido como una solución potente y flexible. Utilizado hoy por prácticamente todas las empresas, es la forma por excelencia de ejecutar código bajo demanda de forma eficiente.

Qué es serverles?

Serverless es un modelo de computación en la nube en el cual el proveedor de servicios en la nube (como AWS) se encarga automáticamente de la gestión y la infraestructura necesaria para ejecutar un programa. Entonces, como desarrolladores no necesitamos mantener ni administrar un servidor, sino que solo tenemos que proporcionar el código, y la plataforma se encarga de ejecutarla en base a distintos eventos.

En AWS, el servicio serverless es AWS Lambda.

Un ejemplo

  • Problema: Imaginense que somos ingenieros en Instagram, y tenemos la problemática de que las fotos que suben los usuarios pesan mucho. Y AWS nos está rompiendo la cabeza con las facturas. Los usuarios de xiaomis suben fotos de perfil de 40 MBs y nos vamos a fundir.

  • Solución: Una función serverless en donde cada vez que se suba una nueva foto (trigger), que la achique y baje la calidad (el código que corre).

El Bot de twitter

A continuación nos veremos la utilización de serverless para armar un botcito que postee en twitter.

Por qué Serverless

Principalmente, es más barato. En Cloud Computing las cosas se cobran por tiempo de uso de lo que se está aprovisionando. El serverless consume recursos solo cuando se ejecuta nuestro trigger. Es decir, levanta su propio entorno y lo mata cuando termina de ejecutar el código. Esto es recontra eficiente en contraposición a un server que consume los recursos de manera continua.

Si lo que queremos es solamente ejecutar un código una vez por día, que tan solo demora 10 segundos, no tiene sentido mantener prendido un a instancia 24hs. Noten que para este tipo de cositas, serverless viene como anillo al dedo. Es revolucionario.

Peeero si queremos tener una aplicación de altísima disponibilidad, ahí sí que no podés safar de tener prendido una instancia 24/7.

Después, podríamos considerar otras ventajas. Es muy escalable, fácil de configurar y tenés mucha visibilidad sobre el código y sus ejecuciones. No tener que lidiar con complejidades de settear el entorno de ejecución y despliegue también es un golazo.

Downside: Memoria y estado

Como el entorno se settea en tiempo de ejecución y se destruye una vez ejecutado el código, todo lo que almacenes es efímero, no persiste. Entonces, si uno quiere guardar un estado o variables, hay que usar algo externo. En mi bot, tenía que guardar el libro y quote por la q va. Resuelvo esto conectándome a una tablita DynamoDB en el Lambda. DynamoDB es un servicio de base de datos noSQL de AWS.

Los pasos para hacer un bot

Ahora sí entramos a la parte más técnica.

1. Registrarse en el Portal de Desarrolladores de Twitter:

Para utilizar la API de Twitter vamos a tener que conseguirnos unas keys. Recomiendo crear una cuenta nueva que va a ser el bot en sí, y entrar con esa al panel de devs.

  1. Obtener Credenciales de API:
    • Una vez creada la aplicación, buscamos las siguientes claves que nos van a servir para autenticarnos con nuestro user de twitter y la cuenta de desarrollador:
      • Consumer Key (API Key)
      • Consumer Secret (API Secret Key)
      • Access Token
      • Access Secret

Paso 2: Desarrollar la Función Lambda

  1. Código del Bot:
    • Escribe el código del bot que se conectará a la API de Twitter y publicará tweets.
    • Podés usar directamente algún SDK de la API.
    • Sino usate la implementación que hice yo para el bot, con https y oauth-1.0a . Ejemplo de código:
async function postTweet(text, replyingTo = false){

  const oauth = OAuth({
    consumer: { key: CONSUMER_KEY, secret: CONSUMER_SECRET },
    signature_method: 'HMAC-SHA1',
    hash_function(base_string, key) {
        return crypto
            .createHmac('sha1', key)
            .update(base_string)
            .digest('base64')
        },
    })

    const token = {
        key: ACCESS_KEY,
        secret: ACCESS_SECRET
    }

    const url = 'https://' + process.env.X_API_HOSTNAME + process.env.X_API_PATH

    const authHeader = oauth.toHeader(oauth.authorize({ url, method: 'POST' }, token));

    const options = {
        hostname: process.env.X_API_HOSTNAME,
        path: process.env.X_API_PATH,
        port: 443,
        method: 'POST',
        headers: {
              Authorization: authHeader["Authorization"],
              'user-agent': "v2CreateTweetJS",
              'content-type': "application/json",
              'accept': "application/json"
        }
     }

    return new Promise((resolve, reject) => {
        const req = https.request(options, (res) => {
            let data = '';

            res.on('data', (chunk) => {
                data += chunk;
            });

            res.on('end', () => {
                try {
                    const response = JSON.parse(data)
                    resolve(response.data.id);
                } catch (err) {
                    reject(new Error(err));
                }
            });
        });

        req.on('error', (error) => {
            console.error('An error occurred while making the request to the Twitter API');
            
            reject(error);
        });


        const body = { text, ...(replyingTo ? { reply: { in_reply_to_tweet_id: replyingTo } } : {}) };
      
        
        const payload = JSON.stringify(body)

        req.write(payload);
        req.end();
})}
  1. Crear la Función Lambda:

    • Andá a AWS Lambda y crea una nueva función.
    • Subí tu código al editor en línea o como un archivo .zip.
  2. Añadir Dependencias: Para poder usar alguna dependencia (npm module) tenes que crear una Layer para el lambda.

    • Creá una capa de Lambda para las dependencias de Node.js (oauth-1.0a, crypto).
    • Podés seguir esta guía AWS Nodejs Layer guide, solo que instalando las dependencias que vos necesites.
  3. Configurar Variables de Entorno:

    • Agregá las claves de API de Twitter como variables de entorno (API_KEY, API_SECRET_KEY, ACCESS_TOKEN, ACCESS_TOKEN_SECRET).
    • Agregá todas las variables de entorno que necesite tu función dentro de la configuración de la misma.

Paso 3: Agregar el Trigger de Schedule

  • Estando en tu función, nn la sección de Triggers, vas a "Add trigger"
  • Seleccioná "EventBridge (CloudWatch Events)".
  • Configurá una regla de scheduling para que la función se ejecute a intervalos específicos o en una determinada hora. En mi caso yo puse dos veces al día, a las 7 AM y 7 PM.

add triggers schedule trigger

Paso 4: Tabla DynamoDB

Seguir esta parte solamente si se desea persistir algun tipo de estado

  1. Configurar DynamoDB: En la consola de AWS, navega a DynamoDB y crea una tabl
  2. Configurar Permisos de IAM: Crea una política de IAM que permita a tu Lambda leer y escribir en la tabla de DynamoDB:
     {
       "Version": "2012-10-17",
       "Statement": [
         {
           "Effect": "Allow",
           "Action": [
             "dynamodb:GetItem",
             "dynamodb:PutItem",
             "dynamodb:UpdateItem"
           ],
           "Resource": "arn:aws:dynamodb:REGION:ACCOUNT_ID:table/YourTableName"
         }
       ]
     }
  • Asigna esta política al rol de ejecución de tu función Lambda.

Conclusión

Serverless representa un cambio de paradigma en la manera de desarrollar y desplegar aplicaciones, proporcionando una infraestructura gestionada que permite a los desarrolladores concentrarse en la creación de valor a través del código. En este artículo, exploraremos cómo construir un bot de X utilizando AWS Lambda, uno de los servicios serverless más populares, y DynamoDB para almacenamiento, aprovechando todas las ventajas de la computación serverless.

En este caso lo utilicé para crear mi bot de Twitter, y no solo el desarrollo fue muy fácil sino que también los costos se mantuvieron en $0 :) cero cost aws

Link al repo del código de mi Lambda