Nel corso degli anni, i servizi di Kinsta sono sempre stati gestiti manualmente tramite il cruscotto MyKinsta. Adesso, grazie l’introduzione dell’API di Kinsta e il continuo rilascio di nuovi endpoint API, si può ottimizzare il proprio workflow creando dei metodi personalizzati per accedere ai servizi di Kinsta. Uno di questi metodi è lo sviluppo di uno Slackbot per monitorare e gestire attività come la creazione di un sito.

Cosa costruiremo

Questo tutorial spiega come costruire uno Slackbot (o un’applicazione Slack) che interagisce con l’API di Kinsta per recuperare informazioni e inviarle sotto forma di messaggi in tempo reale a un canale Slack designato utilizzando gli Incoming Webhook dell’API di Slack.

Per raggiungere questo obiettivo, creeremo un’applicazione Node.js con il framework Express per creare un’interfaccia utente per la creazione di un sito WordPress e integrarla con l’API Kinsta. L’applicazione utilizza un modulo per raccogliere i dettagli di configurazione di un sito WordPress e poi invia al canale Slack specificato un aggiornamento in tempo reale sulle informazioni del sito e i dettagli su come verificarne lo stato di funzionamento.

Gif che mostra l'applicazione che verrebbe costruita e come invia informazioni in tempo reale a Slack.
Gif che mostra l’applicazione da costruire e come invia informazioni in tempo reale a Slack.

Prerequisiti

Per seguire questo progetto, è necessario avere i seguenti requisiti:

  • Conoscenze di base di JavaScript e Node.js
  • Node.js versione 12 o superiore
  • npm (Node Package Manager) installato sul computer
  • Uno spazio di lavoro Slack

Impostazione dell’ambiente di sviluppo

Per iniziare, creiamo una nuova directory per l’applicazione e inizializziamola con npm:

mkdir my-express-app 
cd my-express-app 
npm init -y

Dopo aver eseguito il comando npm init -y, verrà creato un nuovo file package.json nella directory del progetto con valori predefiniti. Questo file contiene informazioni importanti sul progetto e sulle sue dipendenze.

Successivamente, installiamo le dipendenze necessarie per il progetto. Le seguenti dipendenze sono essenziali:

  • ejs: EJS (Embedded JavaScript) è un motore di template che permette di generare contenuti HTML dinamici con JavaScript.
  • express: Express è un framework per applicazioni web veloce e minimalista per Node.js. Semplifica la creazione di applicazioni web e API fornendo funzionalità essenziali come il routing, il supporto al middleware e la gestione delle richieste e delle risposte HTTP.
  • express-ejs-layouts: Express EJS layouts è un’estensione per Express che consente di utilizzare layout o modelli per mantenere una struttura coerente tra più viste.

Per installare queste dipendenze, eseguiamo il comando seguente:

npm install ejs express express-ejs-layouts

Inoltre, dovremo installare le seguenti dipendenze dev per rendere più semplice la build e il test del progetto Node.js:

  • nodemon: Uno strumento prezioso che riavvia automaticamente l’applicazione Node.js ogni volta che vengono rilevati cambiamenti di file nella directory, assicurando un flusso di lavoro di sviluppo semplificato.
  • dotenv: questo modulo a dipendenza zero svolge un ruolo fondamentale nel caricamento delle variabili d’ambiente da un file .env.

Per installare queste dipendenze dev, eseguiamo il comando seguente:

npm install -D nodemon dotenv

Una volta che il package.json è stato inizializzato e tutte le dipendenze sono state installate, creiamo un nuovo file, ad esempio app.js.

touch app.js

Ecco una configurazione predefinita per il file app.js, in cui importare i moduli necessari e impostare l’esecuzione su una porta specifica:

// Import required modules
const express = require('express');
const app = express();

// Set up your routes and middleware here
// ...

// Start the server to listen on the specified port
app.listen(process.env.PORT || 3000, () => {
  console.log(`Server is running on port ${process.env.PORT || 3000}`);
});

Per eseguire l’applicazione Node.js, eseguiamo il comando:

node app.js

Tuttavia, eseguire un’applicazione come questa significa riavviarla manualmente ogni volta che si apportano delle modifiche al progetto. Per ovviare a questo inconveniente, utilizziamo nodemon, che abbiamo già installato. Configuriamolo nel file package.json creando un comando script:

  "scripts": {
    "dev": "nodemon app.js"
  },

Ora, eseguiamo l’applicazione Node.js con riavvio automatico utilizzando il seguente comando:

npm run dev

Primi passi con Express e EJS Templating

In questo tutorial stiamo realizzando un’applicazione Node.js che visualizzerà contenuti sul browser. A tal fine, express.js viene utilizzato come framework web e EJS (Embedded JavaScript) come motore di template.

Per impostare EJS come motore di visualizzazione, aggiungiamo la seguente riga al file app.js. In questo modo sarà possibile eseguire i file di .ejs:

// Use EJS as the view engine 
app.set('view engine', 'ejs');

Ora che Express è configurato con EJS, definiamo le route. Nelle applicazioni web, le route determinano il modo in cui l’applicazione risponde alle diverse richieste HTTP (come GET o POST) e specificano le azioni da intraprendere quando si accede a un URL specifico.

Ad esempio, creiamo una route che carichi una pagina specifica quando un utente naviga verso la pagina indice (/). Per farlo, utilizziamo il metodo di richiesta GET.

// Define a route for the homepage
app.get('/', (req, res) => {
  // Here, you can specify what to do when someone accesses the homepage
  // For example, render an EJS template or send some HTML content
});

Nel codice precedente, quando un utente accede all’indice dell’applicazione, il server eseguirà la funzione di callback specificata come secondo parametro. All’interno di questa funzione di callback, possiamo gestire la logica per il rendering di un modello EJS o per l’invio di un contenuto HTML da visualizzare nella homepage.

Possiamo utilizzare il metodo res.render() per eseguire il rendering di un modello EJS o res.send() per inviare un semplice contenuto HTML.

app.get('/', (req, res) => {
    res.send('Hello World');
});

Quando eseguiamo l’applicazione, nella pagina index verrà visualizzato “Hello World”.

Template EJS

Questo tutorial si concentra sulla logica e include dei file di partenza, così non dovrete preoccuparvi di creare dei template da zero. Seguiamo questi passaggi per iniziare:

  1. Accediamo al template su GitHub per creare un nuovo repository.
  2. Selezioniamo l’opzione Include all branches durante la creazione del repository.
  3. Una volta creato il repository, cloniamo il progetto sul computer utilizzando Git.
  4. Per accedere al codice di partenza, passiamo al branch starter-files nel repository locale.

Nel codice di partenza abbiamo due cartelle principali: public e views. La cartella public contiene tutte le risorse statiche (file CSS e immagini). Vengono aggiunti al template come file statici:

// Static files
app.use(express.static('/public'));
app.use('/css', express.static(__dirname + '/public/css'));
app.use('/images', express.static(__dirname + '/public/images'));

Nella cartella views sono presenti il file layout.ejs e due cartelle: pages e partials. Il file layout.ejs contiene il layout generale del progetto, quindi non sarà necessario ripetere del codice ricorrente per tutte le pagine. Importiamo la libreria express-ejs-layouts nel file app.js e configuriamola:

// Import
const expressEjsLayouts = require('express-ejs-layouts');

// Configure
app.use(expressEjsLayouts);

La cartella pages contiene i file di percorso (index.ejs e operation.ejs), mentre la cartella partials contiene i componenti (header.ejs e footer.ejs). Aggiungiamoli al layout in questo modo:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <link rel="icon" href="/images/favicon.ico" />
        <link rel="stylesheet" href="/css/index.css" />
        <title>Site Builder</title>
    </head>
    <body>
        <div class="app-container">
            <%- include('partials/header') %>
            <div class="container"><%- body %></div>
            <%- include('partials/footer') %>
        </div>
    </body>
</html>

Quando eseguiremo l’applicazione Node.js, l’interfaccia utente verrà caricata, ma dovremo aggiungere la logica a questa applicazione per inviare i dati del modulo all’API di Kinsta e inviare informazioni sul sito a Slack quando l’operazione inizia.

Primi passi con gli Incoming Webhook di Slack

Gli Incoming Webhooks di Slack rappresentano un modo semplice per inviare messaggi da applicazioni esterne a Slack. Per utilizzare gli Incoming Webhook di Slack, creiamo e configuriamo un’applicazione Slack, quindi copiamo l’URL del Webhook per inviare messaggi a Slack in modo programmatico.

Configurare un’applicazione Slack e ottenere l’URL del Webhook

Creiamo una nuova applicazione Slack seguendo i passaggi qui sotto:

  1. Andiamo alla dashboard di Slack API.
  2. Clicchiamo sul pulsante Create new app, che aprirà una finestra di dialogo.
  3. Selezioniamo l’opzione From Scratch per iniziare a costruire l’applicazione da zero.
  4. Indichiamo un nome per l’app Slack, ad esempio Kinsta Bot.
  5. Scegliamo quindi l’area di lavoro in cui vogliamo installare l’app e clicchiamo sul pulsante Create app.

Una volta creata l’applicazione Slack, possiamo attivare gli Incoming Webhook navigando su Features e selezionando Incoming Webhook. Attiviamo l’interruttore per abilitare gli Incoming Webhook per l’applicazione.

Scorriamo verso il basso fino alla sezione Webhook URLs for Your Workspace e clicchiamo su Add New Webhook to Workspace. Ci verrà chiesto di scegliere un canale dove inviare i messaggi. Selezioniamo il canale desiderato e facciamo clic su Authorize.

Dopo l’autorizzazione, verrà fornito un URL Webhook per il canale selezionato. Questo URL è quello che useremo per inviare i messaggi a Slack in modo programmatico. Ecco come si presenta un URL Webhook:

https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX

Questo Webhook è specifico per un singolo utente e un singolo canale. Teniamolo al sicuro, perché funge da token di autenticazione per l’applicazione. Possiamo memorizzare i codici univoci dopo /services/ nel file .env. Verrà inoltre richiesto di reinstallare l’app nello spazio di lavoro affinché le modifiche abbiano effetto.

Inviare messaggi a Slack con Node.js e Kinsta API

Ora che l’interfaccia dell’applicazione Node.js è stata configurata e lo Slackbot è stato creato con successo (insieme all’URL del WebHook), è il momento di gestire la logica.

Recuperare i dati del modulo in Node.js

Nella pagina index, abbiamo un modulo che invierà i dati all’API di Kinsta per creare un nuovo sito WordPress. Per farlo funzionare, dobbiamo creare una richiesta POST dalla pagina indice. Assicuriamoci che il modulo abbia un metodo POST e che i campi di input abbiano un attributo name, che verrà utilizzato nel file app.js.

app.post('/', (req, res) => {
    // Perform the desired operation with the form data
});

Per recuperare i dati da un modulo in Node.js, dovremo utilizzare il seguente middleware:

app.use(express.json());
app.use(express.urlencoded({ extended: true }));

Ora possiamo accedere ai valori del modulo utilizzando req.body.[form field name]. Ad esempio, req.body.displayName ci fornirà il nome visualizzato inviato tramite il modulo. Registriamo i dati complessivi del modulo:

app.post('/', (req, res) => {
    console.log(req.body);
});

Quando eseguiamo il codice, i dati del modulo vengono visualizzati dopo che l’utente avrà compilato il modulo e cliccato sul pulsante Submit.

Dettagli del modulo recuperati dal parametro req in Node.js
Dettagli del modulo recuperati dal parametro req in Node.js.

Creare un sito con l’API di Kinsta in Node.js

Per creare un sito WordPress con l’API di Kinsta in Node.js, possiamo utilizzare il metodo fetch(), che ora è supportato e funziona in modo efficiente nelle ultime versioni di Node.js.

Per eseguire qualsiasi operazione con l’API di Kinsta, dobbiamo creare una chiave API. Per generare una chiave API:

  1. Andiamo alla dashboard MyKinsta.
  2. Andiamo alla pagina delle chiavi API (Nome > Impostazioni dell’azienda > Chiavi API).
  3. Clicchiamo su Crea chiave API.
  4. Scegliamo una data di scadenza o impostiamo una data di inizio personalizzata e un numero di ore di scadenza della chiave.
  5. Assegniamo alla chiave un nome univoco.
  6. Clicchiamo su Genera.

Assicuriamoci di copiare la chiave API generata e di conservarla in modo sicuro, perché sarà visibile solo in questo momento. Per questo progetto, creiamo un file .env nella directory principale e salviamo la chiave API come KINSTA_API_KEY.

Inoltre, per creare un sito WordPress utilizzando l’API di Kinsta, avremo bisogno dell’ID Azienda (che si trova in MyKinsta alla voce Azienda > Dettagli di fatturazione > ID Azienda). Memorizziamo anche questo ID nel file .env, in modo da poter accedere a queste variabili d’ambiente tramite process.env. Per abilitare questa funzionalità, assicuriamoci di configurare la dipendenza dotenv all’inizio del file app.js in questo modo:

require('dotenv').config();

Per procedere alla creazione di un sito WordPress tramite l’API di Kinsta, inviamo una richiesta POST all’endpoint /sites con i dati necessari forniti nell’oggetto req.body:

const KinstaAPIUrl = 'https://api.kinsta.com/v2';

app.post('/', (req, res) => {
    const createSite = async () => {
        const resp = await fetch(`${KinstaAPIUrl}/sites`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                Authorization: `Bearer ${process.env.REACT_APP_KINSTA_API_KEY}`,
            },
            body: JSON.stringify({
                company: process.env.REACT_APP_KINSTA_COMPANY_ID,
                display_name: req.body.displayName,
                region: req.body.location,
                install_mode: 'new',
                is_subdomain_multisite: false,
                admin_email: req.body.email,
                admin_password: req.body.password,
                admin_user: req.body.username,
                is_multisite: false,
                site_title: req.body.siteTitle,
                woocommerce: false,
                wordpressseo: false,
                wp_language: 'en_US',
            }),
        });
        const data = await resp.json();
        console.log(data);
    };
    createSite();
});

Eseguendo il codice qui sopra, creeremo un nuovo sito WordPress con l’API di Kinsta. Ma questo non è il nostro obiettivo principale. Il nostro obiettivo è, invece, inviare un messaggio a Slack contenente informazioni sul sito quando l’operazione di creazione del sito è andata a buon fine.

Inviare un messaggio a Slack con l’URL dell’Incoming Webhook

Per farlo, creiamo un’istruzione If per verificare lo stato della risposta della richiesta API. Se è 202, significa che “la creazione del sito è iniziata” e possiamo inviare un messaggio a Slack utilizzando l’URL Incoming Webhook. A tal fine, possiamo utilizzare la libreria di richieste HTTP che preferiamo (ad esempio Axios) o il metodo che preferiamo per inviare una richiesta POST a Slack. Utilizziamo il metodo fetch():

if (data.status === 202) {
    fetch(
        `https://hooks.slack.com/services/${process.env.SLACK_WEBHOOK_ID}`,
        {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({
                text: 'Hello, world.',
            }),
        }
    );
}

Eseguiamo il codice qui sopra e compiliamo il modulo di creazione del sito. Se il processo va a buon fine, verrà inviato immediatamente un messaggio a Slack.

Hello World inviato da Node.js a Slack con Incoming Webhook
Hello World inviato da Node.js a Slack con Incoming Webhook.

Personalizzare i messaggi Slack

L’esempio precedente invia un messaggio di testo di base, ma gli Incoming Webhook di Slack supportano molto di più del semplice testo. Possiamo personalizzare i messaggi per includere allegati, link, immagini, pulsanti e altro ancora.

Uno dei modi per personalizzare i messaggi di Slack è utilizzare il Block Kit Builder di Slack. Il Block Kit è un framework UI fornito da Slack che permette di costruire messaggi ricchi e interattivi con vari elementi di contenuto.

Per questo tutorial, ecco un blocco creato con il Block Kit Builder per formattare correttamente il messaggio e aggiungere alcuni valori dal modulo e dalla risposta alla creazione del sito:

const message = {
    blocks: [
        {
            type: 'section',
            text: {
                type: 'mrkdwn',
                text: `Hello, your new site (${req.body.displayName}) has started building. It takes minutes to build. You can check the operation status intermittently via https://site-builder-nodejs-xvsph.kinsta.app/operation/${req.body.displayName}/${data.operation_id}.`,
            },
        },
        {
            type: 'divider',
        },
        {
            type: 'section',
            text: {
                type: 'mrkdwn',
                text: "_Here are your site's details:_",
            },
        },
        {
            type: 'section',
            text: {
                type: 'mrkdwn',
                text: `1. *Site URL:* http://${req.body.displayName}.kinsta.cloud/n2. *WP Admin URL:* http://${req.body.displayName}.kinsta.cloud/wp-admin/`,
            },
        },
    ],
};

In questo codice, creiamo un oggetto messaggio contenente un array di blocchi. Ogni blocco rappresenta una sezione specifica del messaggio Slack e può avere diversi tipi di contenuto.

  1. Blocco sezione: Questo tipo di blocco viene utilizzato per visualizzare una sezione di testo. Si utilizza l’indirizzo type: 'section' per indicare che si tratta di un blocco di sezione. All’interno del blocco di sezione, la proprietà text viene utilizzata con type: 'mrkdwn' per specificare che il contenuto del testo deve essere interpretato in formato Markdown. Il contenuto effettivo del testo viene fornito nella proprietà text e si utilizzano i template literals per includere i valori dinamici del modulo e della risposta alla creazione del sito, come req.body.displayName e data.operation_id.
  2. Blocco divisorio: Questo tipo di blocco viene utilizzato per aggiungere una linea orizzontale per separare le sezioni del messaggio. Utilizziamo type: 'divider' per creare il blocco divisorio.

Quando questo messaggio viene inviato a Slack utilizzando l’Incoming Webhook, genererà un messaggio informativo e visivamente accattivante nel nostro canale Slack. Il messaggio includerà i valori dinamici del modulo (come il nome del sito) e le informazioni della risposta alla creazione del sito, rendendolo un messaggio altamente personalizzato.

Per inviare questo messaggio personalizzato, sostituiamo l’oggetto nel corpo del sito fetch() con il contenuto della variabile messaggio:

if (data.status === 202) {
    fetch(
        `https://hooks.slack.com/services/${process.env.SLACK_WEBHOOK_ID}`,
        {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify(message),
        }
    );
}
Messaggio Slack personalizzato con Slack block Kit Builder
Messaggio Slack personalizzato con Slack block Kit Builder.

Gestire l’operazione di creazione del sito con l’API di Kinsta

Nel messaggio inviato a Slack, viene creato un link con l’ID dell’operazione e il nome visualizzato. Possiamo creare un nuovo percorso per la pagina Operations e utilizzare questi dati per verificare lo stato dell’operazione.

In Express, possiamo accedere ai parametri URL con il parametro req. Ad esempio, per ottenere l’ID dell’operazione, usiamo req.params.operationId.

const KinstaAPIUrl = 'https://api.kinsta.com/v2';

app.get('/operation/:displayName/:operationId', (req, res) => {
    const checkOperation = async () => {
        const operationId = req.params.operationId;
        const resp = await fetch(`${KinstaAPIUrl}/operations/${operationId}`, {
            method: 'GET',
            headers: {
                Authorization: `Bearer ${process.env.REACT_APP_KINSTA_API_KEY}`,
            },
        });
        const data = await resp.json();
        res.render('pages/operation', {
            operationID: req.params.operationId,
            displayName: req.params.displayName,
            operationMessage: data.message,
        });
    };
    checkOperation();
});

Con il codice qui sopra, cliccando sul link in Slack verrà effettuata una richiesta all’API di Kinsta per verificare lo stato di funzionamento del sito. Aggiorniamo il file operation.ejs per aggiungere i dati dinamici:

<div class="container-title">
    <h1 class="title">Check Site Operation Status</h1>
    <p>
        Check the status of your site tools operation via the id. Feel free to copy
        the ID and check in few seconds.
    </p>
</div>
<div class="form-container">
    <div class="input-div">
        <input class="form-control" value="<%= operationID %>" readOnly />
    </div>
    <button class="btn" type="submit" onclick="window.location.reload()">
        Refresh Operation Status
    </button>
</div>
<div class="services">
    <div class="details">
        <p><%= operationMessage %>..</p>
    </div>
</div>
<div class="services">
    <p class="description">
        If message above indicates that "Operation has successfully finished", use
        the links below to access your WP admin and the site itself.
    </p>
    <div class="details">
        <a
            href="http://<%= displayName %>.kinsta.cloud/wp-admin/"
            target="_blank"
            rel="noreferrer"
            class="detail-link"
        >
            <p>Open WordPress admin</p>
            <FiExternalLink />
        </a>
        <a
            href="http://<%= displayName %>.kinsta.cloud/"
            target="_blank"
            rel="noreferrer"
            class="detail-link"
        >
            <p>Open URL</p>
            <FiExternalLink />
        </a>
    </div>
</div>
Pagina delle operazioni che mostra l'ID dell'operazione e i dettagli del sito
Pagina delle operazioni che mostra l’ID dell’operazione e i dettagli del sito.

Un’ultima cosa: possiamo utilizzare il metodo di reindirizzamento per navigare alla pagina delle operazioni quando inizia il processo di creazione di un sito:

if (data.status === 202) {
    fetch(
        `https://hooks.slack.com/services/${process.env.SLACK_WEBHOOK_ID}`,
        {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify(message),
        }
    );
    res.redirect(`/operation/${req.body.displayName}/${data.operation_id}`);
}

Il codice sorgente completo di questo progetto è disponibile nel branch principale di questo repository GitHub.

Distribuire un’applicazione Node.js su Kinsta

È possibile distribuire facilmente questa applicazione Node.js sulla piattaforma di Hosting di Applicazioni di Kinsta. Basta inviare il codice al proprio provider Git preferito (Bitbucket, GitHub o GitLab) e poi seguire i passaggi qui sotto:

  1. Accedere al proprio account Kinsta nella dashboard MyKinsta.
  2. Cliccare su Aggiungi servizio.
  3. Selezionare Applicazione dal menu a tendina.
  4. Nella finestra di dialogo che appare, scegliere il repository che si vuole distribuire. Se si hanno più branch, è possibile selezionare il branch desiderato e dare un nome all’applicazione.
  5. Selezionare uno dei data center disponibili. Kinsta rileverà e installerà le dipendenze dell’applicazione dal file package.json, quindi eseguirà la build e la distribuzione.

Infine, non è sicuro inviare le chiavi API a host pubblici come un provider Git. Durante l’hosting, è possibile aggiungerle come variabili d’ambiente utilizzando lo stesso nome e valore della variabile specificata nel file .env.

Impostare le variabili d'ambiente su DevKinsta durante la distribuzione
Impostare le variabili d’ambiente su DevKinsta durante la distribuzione.

Una volta avviata la distribuzione dell’applicazione, questa verrà in genere creata e distribuita in pochi minuti. Verrà fornito un link alla nuova applicazione, che avrà il seguente aspetto: https://site-builder-nodejs-xvsph.kinsta.app.

Riepilogo

In questo tutorial abbiamo imparato come inviare messaggi a Slack da un’applicazione Node.js utilizzando gli Incoming Webhooks e come personalizzare i messaggi di Slack con il Block Kit Builder.

Le possibilità offerte da Slack e dall’API Kinsta sono molto ampie e questo tutorial è solo l’inizio. Integrando questi strumenti, è possibile creare un workflow continuo che mantiene il team ben informato e aumenta la produttività.

Come utilizzate l’API di Kinsta? Quali funzioni vorreste vedere aggiunte/esposte prossimamente?

Joel Olawanle Kinsta

Joel is a Frontend developer working at Kinsta as a Technical Editor. He is a passionate teacher with love for open source and has written over 200 technical articles majorly around JavaScript and it's frameworks.