Os Apps Lua da Turn.io estão atualmente em um programa de acesso antecipado e ainda não estão disponíveis ao público geral. Se você tem interesse em construir aplicativos personalizados e gostaria de participar, entre em contato com nossa equipe de suporte para discutir seu caso de uso.
Construindo Apps Lua na Turn.io
Bem-vindo ao guia do desenvolvedor para construir Apps Lua na plataforma Turn.io! Este guia irá orientá-lo em tudo que você precisa saber para criar, testar e implantar aplicativos poderosos que estendem as capacidades da Turn.io.
O que são os Apps Lua da Turn.io?
Os Apps Lua da Turn são pacotes autocontidos de código Lua que executam de forma segura dentro da plataforma Turn.io. Eles permitem que você implemente lógica de negócio personalizada que pode ser ativada por eventos da plataforma, requisições HTTP, ou diretamente de uma Jornada.
Com os Apps Lua, você pode:
- Integrar com APIs externas e sistemas de terceiros.
- Criar fluxos de trabalho complexos e com estado que vão além das capacidades padrão de Jornada.
- Construir lógica de backend personalizada para seus serviços de mensagens.
- Lidar com eventos assíncronos, como aguardar um webhook de confirmação de pagamento.
Começando: Seu Primeiro App
A melhor maneira de começar é usando nosso template oficial de app, que inclui uma estrutura básica de app, um framework de testes e um script de empacotamento.
-
Baixe o Template: Obtenha uma cópia do diretório
lua_app_template
. -
Estrutura do Projeto: Seu novo diretório de app ficará assim:
my_app/
├── my_app.lua # Seu arquivo principal da aplicação
├── my_app-0.1.0-0.rockspec # Para gerenciar dependências de teste
├── package.sh # Script para empacotar seu app para upload
├── turn.lua # Um mock das APIs da Turn.io para teste local
└── spec/
└── my_app_spec.lua # Seu arquivo de teste -
Instale as Ferramentas de Teste: Você precisará do Lua e LuaRocks para executar testes localmente.
# No macOS com Homebrew
brew install lua luarocks
# No Debian/Ubuntu
sudo apt-get install lua5.3 luarocks -
Instale as Dependências de Teste: Navegue até o diretório do seu app e execute:
luarocks install --only-deps my_app-0.1.0-0.rockspec
Isso instalará o Busted (um framework de testes) e outros auxiliares.
Agora você está pronto para começar a desenvolver seu app!
A Função on_event
A função on_event
no seu arquivo .lua
principal é o coração da sua aplicação. É o ponto de entrada único que recebe e roteia todos os eventos da plataforma Turn.io.
Sua função receberá quatro argumentos:
app
: Uma tabela contendo a configuração da instância do seu app, incluindo seu UUID único.number
: Uma tabela com informações sobre o número onde o app está instalado.event
: Uma string identificando o tipo de evento (ex:"install"
,"http_request"
).data
: Uma tabela contendo dados específicos daquele evento.
local App = {}
local turn = require("turn")
function App.on_event(app, number, event, data)
if event == "install" then
-- Realiza configuração quando o app é instalado
turn.logger.info("Meu app foi instalado!")
return true -- Retorna true em caso de sucesso
elseif event == "uninstall" then
-- Realiza limpeza quando o app é desinstalado
turn.logger.info("Meu app foi desinstalado.")
return true
elseif event == "contact_changed" then
-- Reage a um contato sendo atualizado
local contact_uuid = data.uuid
turn.logger.info("Contato " .. contact_uuid .. " foi atualizado.")
return true
elseif event == "http_request" then
-- Lida com uma requisição HTTP recebida para o endpoint único do seu app
return true, { status = 200, body = "Olá do meu app!" }
else
-- É uma boa prática lidar com eventos desconhecidos
turn.logger.warning("Evento desconhecido recebido: " .. event)
return false
end
end
return App
Integrando com Jornadas
Uma das funcionalidades mais poderosas dos Apps Lua é sua capacidade de integrar diretamente com Jornadas usando o bloco app()
. Isso permite adicionar lógica personalizada, cálculos ou chamadas de API bem no meio de uma conversa.
Chamando um App a partir de uma Jornada
Na sua Jornada você pode chamar uma função de app assim:
card GetWeather do
# Chama a função 'get_forecast' no 'weather_app'
weather_data = app("weather_app", "get_forecast", ["Cape Town"])
# O resultado está disponível na variável 'weather_data'
text("O clima em Cape Town é: @(weather_data.result.temperature)°C")
end
Isso aciona um journey_event
no seu app Lua.
Lidando com um journey_event
Seu app deve lidar com o journey_event
e pode controlar o fluxo da Jornada pelo seu valor de retorno.
Fluxo Síncrono: continue
Para operações que completam instantaneamente, retorne "continue"
junto com o resultado. A Jornada prosseguirá para o próximo bloco sem pausar.
- Casos de uso: Validação de dados, cálculos simples, formatação de texto.
- Assinatura de retorno:
return "continue", result_table
-- Na sua função on_event
elseif event == "journey_event" and data.function_name == "add" then
local sum = tonumber(data.args[1]) + tonumber(data.args[2])
-- A Jornada continua imediatamente com o resultado
return "continue", { value = sum }
end
Fluxo Assíncrono: wait
e turn.leases
Para tarefas de longa duração, como aguardar um webhook de confirmação de pagamento, você pode dizer à Jornada para pausar retornando "wait"
.
A Jornada permanecerá pausada até que seu app explicitamente a retome enviando dados para seu lease. Um lease é uma retenção temporária do estado da Jornada, identificado pelo chat_uuid
.
- Casos de uso: Aguardar webhooks, aprovações humanas ou atrasos temporizados.
- Assinatura de retorno:
return "wait"
Exemplo de Fluxo de Trabalho: Aguardando um Webhook de Pagamento
-
Jornada Inicia e Aguarda: A Jornada chama seu app, que inicia um pagamento e diz à Jornada para aguardar.
-- manipulador de journey_event
if data.function_name == "waitForPayment" then
-- O app pode chamar uma API de pagamento externa aqui
-- ...
-- Agora, diga à Jornada para pausar
return "wait"
end -
Webhook Externo Chega: Mais tarde, seu provedor de pagamento envia um webhook para o endpoint HTTP do seu app. O manipulador
http_request
do seu app o analisa. -
App Retoma a Jornada: Dentro do manipulador
http_request
, você usaturn.leases.send_input()
com ochat_uuid
original para retomar a Jornada correta e entregar o resultado.-- manipulador de http_request
-- Assuma que você obteve o chat_uuid dos metadados do webhook
local chat_uuid = webhook_payload.metadata.chat_uuid
local result_data = {
payment_confirmed = true,
transaction_id = "txn_123"
}
turn.leases.send_input(chat_uuid, result_data)
A Jornada recebe os result_data
e automaticamente retoma a execução.
Referência da API
A tabela global turn
fornece acesso em sandbox às funcionalidades da plataforma.
-
turn.assets
Carrega arquivos estáticos (como templates ou imagens) de uma pasta
assets/
no arquivo.zip
do seu app.list(directory_path)
: Lista arquivos em um diretório.directory_path
(string, opcional): O caminho dentro deassets/
.
exists(asset_path)
: Verifica se um arquivo existe.asset_path
(string): O caminho completo para o ativo.
load(asset_path)
: Carrega o conteúdo de um ativo.asset_path
(string): O caminho completo para o ativo.
local journey_files = turn.assets.list("journeys")
for _, filename in ipairs(journey_files) do
local content = turn.assets.load("journeys/" .. filename)
turn.logger.info("Template de jornada carregado: " .. filename)
end -
turn.configuration
Gerencia as configurações do seu app.
get_config()
: Retorna uma tabela de toda a configuração.get_config_value(key)
: Retorna o valor para uma chave específica.key
(string): A chave de configuração.
update_config(updates)
: Mescla uma tabela de atualizações na configuração.updates
(table): Pares chave-valor para atualizar.
set_config(new_config)
: Substitui toda a configuração.new_config
(table): A nova tabela de configuração.
local api_key = turn.configuration.get_config_value("api_key")
if not api_key then
turn.logger.error("A chave da API não está configurada!")
return false
end
turn.configuration.update_config({ last_synced_at = os.time() }) -
turn.contacts
Encontra contatos e gerencia seus campos personalizados.
find(query)
: Encontra um contato.query
(table): Pares chave-valor para buscar por (ex:{ msisdn = "+27..." }
).
update_contact_details(contact, details)
: Atualiza os campos de um contato.contact
(table): O objeto contato defind()
.details
(table): Pares chave-valor de campos para atualizar.
create_contact_field(field_def)
: Cria um novo campo personalizado no esquema.field_def
(table): Uma tabela com chavestype
,name
edisplay
.
local contact, found = turn.contacts.find({ msisdn = "+27820000000" })
if found then
turn.contacts.update_contact_details(contact, { loyalty_id = "LTY-12345" })
end -
turn.google
Autentica com APIs do Google.
get_access_token(service_account_json, scopes)
: Obtém um token OAuth2.service_account_json
(string): O conteúdo JSON do arquivo de conta de serviço.scopes
(table, opcional): Uma lista de escopos da API do Google.
local ok, token = turn.google.get_access_token(sa_json)
if ok then
-- Use token na requisição turn.http
end -
turn.http
Faz requisições HTTP externas.
request(options)
: Envia uma requisição HTTP.options
(table): Uma tabela comurl
,method
,headers
(table) ebody
(string).
local body, status = turn.http.request({
url = "https://api.example.com/v1/events",
method = "POST",
headers = { ["Content-Type"] = "application/json" },
body = turn.json.encode({ message = "Olá" })
}) -
turn.journeys
Gerencia Jornadas programaticamente.
create(journey_def)
: Cria uma nova Jornada.journey_def
(table): Uma tabela comname
,notebook
eenabled
.
update(journey_uuid, updates)
: Atualiza uma Jornada existente.journey_uuid
(string): O UUID da jornada para atualizar.updates
(table): Uma tabela comname
,notebook
ouenabled
.
delete(journey_def)
: Deleta uma Jornada pelo nome.journey_def
(table): Uma tabela com oname
da jornada.
list()
: Retorna uma lista de todas as Jornadas.
local journey, ok = turn.journeys.create({
name = "Integração de Novo Usuário",
notebook = turn.assets.load("journeys/onboarding.md"),
enabled = true
}) -
turn.json
Codifica e decodifica dados JSON.
encode(data, options)
: Codifica uma tabela Lua em uma string JSON.data
(table): A tabela Lua para codificar.options
(table, opcional): ex:{ indent = true }
.
decode(json_string)
: Decodifica uma string JSON em uma tabela Lua.json_string
(string): A string para decodificar.
local my_table = { name = "João Silva", age = 30 }
local json_string = turn.json.encode(my_table) -
turn.leases
Usado para retomar Jornadas em espera. Veja a seção de fluxo assíncrono para um exemplo detalhado.
send_input(chat_uuid, input_data)
: Envia dados para uma Jornada pausada, retomando-a.chat_uuid
(string): O UUID do chat cuja Jornada está aguardando.input_data
(any): Os dados para enviar como resultado do blocoapp()
.
turn.leases.send_input(chat_uuid, { payment_status = "confirmed" })
-
turn.logger
Escreve logs que são visíveis na UI da Turn.io para depuração.
debug(message)
,info(message)
,warning(message)
,error(message)
message
(string): A mensagem de log.
turn.logger.error("Falha ao conectar com o banco de dados: " .. err_msg)
-
turn.media
Salva dados binários (como imagens ou documentos) como mídia que pode ser reutilizada em mensagens.
save(media_data)
: Salva dados binários como um item de mídia.media_data
(table): Uma tabela comdata
(string binária),filename
(string) econtent_type
(string).
local qr_table, ok = turn.qrcode.generate({ data = "..." })
if ok then
local saved, media_info = turn.media.save(qr_table)
end -
turn.qrcode
Gera imagens de código QR.
generate(options)
: Cria um PNG de código QR.options
(table): Uma tabela comdata
(string) e chaves opcionais comofilename
,color
,image_data
.
local qr_table, ok = turn.qrcode.generate({
data = "https://www.turn.io/",
color = "#8654CD" -- Roxo da Turn.io!
})
Testando Seu App
O template de app vem com uma configuração completa de testes usando o framework Busted.
- APIs Mock: O arquivo
turn.lua
fornece uma versão simulada das APIs da Turn.io, para que você possa testar a lógica do seu app de forma isolada. - Escrevendo Testes: Escreva seus testes no diretório
spec/
. Você pode usar spies para verificar se seu app chamou as APIs corretas da Turn.io. - Executando Testes:
# Execute todos os testes do diretório raiz do seu app
busted -C .
Empacotamento para Implantação
Quando seu app estiver pronto, você precisa empacotá-lo em um arquivo .zip
para fazer o upload.
- Use o Script: O script
package.sh
do template automatiza isso para você. Ele executará seus testes e então criará o arquivo ZIP em um diretóriodist/
../package.sh --name my_app --version 1.0.0
- Empacotamento Manual: Se preferir, você pode compactar os arquivos você mesmo. É crucial incluir apenas os arquivos fonte da sua aplicação (
.lua
) e quaisquer ativos. Não inclua arquivos de teste ou o arquivo mockturn.lua
.
Fornecendo Documentação do App na UI
Para garantir uma ótima experiência do usuário, você pode fornecer documentação que aparecerá diretamente na UI da Turn.io. Lide com o evento get_app_info_markdown
e retorne uma string Markdown.
Este é o lugar perfeito para explicar o que seu app faz, listar suas funcionalidades e fornecer instruções de configuração ou exemplos de endpoint de API.
elseif event == "get_app_info_markdown" then
return [[
# Meu App Incrível
Este app se integra com o serviço externo `XYZ`.
## Configuração
Para usar este app, forneça sua `XYZ_API_KEY` na configuração abaixo.
## Endpoint de Webhook
Envie requisições `POST` do seu serviço para a seguinte URL:
`/apps/]] .. app.uuid .. [[/webhook`
]]
end