Desbloqueando Soluções Personalizadas: Utilizando Apache APISIX e Node-RED em Harmonia

March 6, 2024

Ecosystem

Contexto

Muitos usuários do Apache APISIX precisam de personalização em ambientes empresariais para atender a requisitos específicos em determinados cenários, apesar de ele possuir muitos recursos poderosos de plugins embutidos.

Os usuários frequentemente optam por escrever plugins em Lua e montá-los em instâncias do APISIX para uso. No entanto, Lua tem um público relativamente limitado. Embora seja fácil de começar, dominá-lo não é simples, e implementar lógicas complexas de transformação de dados em Lua pode se tornar bastante intrincado. Atualmente, apenas uma parte dos hooks é exposta pelo Java Plugin Runner para os desenvolvedores chamarem, exigindo modificações no código-fonte do Java Plugin Runner para funcionalidades que não são diretamente suportadas.

O diagrama abaixo ilustra três padrões comuns de uso de plugins: plugins Lua executados diretamente embutidos no núcleo do APISIX; Plugin Runner se comunica via RPC com Plugin Runners em linguagens como Java, Golang, etc.; e plugins WASM são convertidos em bytecode e executados internamente no núcleo do APISIX.

plugin e plugin runners do apisix

Observou-se, a partir do feedback dos usuários, que a necessidade de plugins personalizados está frequentemente relacionada à transformação de dados, como parâmetros de solicitação HTTP e chamadas a APIs externas para processamento de dados.

Para resolver isso, foi proposta uma nova abordagem para aprimorar as capacidades do Apache APISIX. Essa abordagem envolve o uso apenas de plugins embutidos no Apache APISIX para configurar capacidades comuns como autenticação e limitação de taxa, enquanto a lógica personalizada é colocada em serviços externos. O serviço externo pode ser um programa binário ou outro serviço de API, que será tratado como um upstream para o APISIX. Esse serviço externo lidará com solicitações e respostas como um middleware. Essa abordagem também pode ser aplicada a outros gateways de API ou serviços de proxy.

Descrição do Cenário

Temos uma série de serviços que fornecem serviços de consulta de dados upstream (este artigo usa https://api-ninjas.com/api como exemplo). Por exemplo, é possível recuperar as informações meteorológicas mais recentes e informações sobre o país (como o PIB do país, nome da capital e unidade monetária) com base no nome da cidade.

Nosso principal objetivo é fornecer uma interface de solicitação genérica para desenvolvedores, enquanto ainda é possível determinar o conteúdo dos dados que desejam recuperar com base no nome da cidade e nos parâmetros de escopo dos dados. Além disso, para proteger os serviços upstream de abusos, devemos adicionar um serviço de autenticação à interface do desenvolvedor, permitindo que apenas solicitações com a API Key correta sejam encaminhadas para o serviço upstream.

Análise do Problema

Antes de introduzir o Node-Red, para atender aos requisitos acima, os desenvolvedores do APISIX considerariam o uso de plugins Lua. Embora o Apache APISIX forneça documentação detalhada sobre o desenvolvimento de plugins, os desenvolvedores de negócios precisam aprender a sintaxe e técnicas de ajuste do Lua, entender os diferentes hooks de solicitação expostos pelo APISIX e recarregar continuamente os plugins para validação enquanto escrevem a lógica para extração e validação de parâmetros. Após concluir os testes, eles também precisam empacotar os plugins Lua no programa APISIX ou distribuí-los para todas as instâncias do APISIX para montagem.

Os requisitos de exemplo que fornecemos neste blog envolvem a análise de parâmetros específicos das solicitações dos clientes e, em seguida, a construção de solicitações para recuperar dados de diferentes serviços upstream. No entanto, gastamos muito tempo lidando com transações fora da escrita do negócio. Portanto, para lógicas envolvendo conversão de parâmetros, conversão de formato ou chamadas externas, podemos adotar uma abordagem mais leve e intuitiva, que é exatamente o problema que o Node-Red pode resolver.

Introdução ao Node-Red

Node-RED é uma ferramenta poderosa e fácil de usar para programação baseada em fluxos, adequada para tarefas de automação e processamento de fluxo de dados em vários domínios. Sua interface de programação, rica biblioteca de nós e flexibilidade de extensão nos permitem construir rapidamente fluxos complexos e implementar vários cenários de aplicação. Aqui estão alguns dos nós fornecidos pelo Node-RED:

  • Nó HTTP_IN: Expõe um endpoint para invocação de serviços externos, que usaremos como um serviço upstream para o APISIX.

  • Nó Function: Permite que os desenvolvedores escrevam funções de código em JavaScript para modificar, excluir, etc., entrada/saída.

  • Nó Switch: Permite que os desenvolvedores definam um conjunto de condições para entrar no próximo nó especificado quando uma condição for atendida.

  • Nó HTTP_Request: Pode definir URL, etc., para enviar dados a este endpoint via Node-RED ao executar todo o fluxo de trabalho.

  • Nó Change: Pode adicionar, modificar ou excluir valores especificados de um objeto especificado.

  • Nó HTTP_Response: Usado para retornar respostas aos clientes.

Além dos nós listados acima, o Node-RED também fornece muitos outros nós embutidos. Este artigo mostrará aos leitores como implementar os requisitos acima através do Node-RED.

Demonstração de Exemplo

Configuração do Ambiente

Vamos implantar os componentes necessários por meio de conteinerização, usando um Droplet da DigitalOcean como recurso do servidor.

$ doctl compute ssh-key list

ID          Name             FingerPrint
25621060    Zhiyuan Ju       2c:84:b7:d8:14:0a:a0:0f:ca:fe:ca:24:06:a4:fe:39

$ doctl compute droplet create \
    --image docker-20-04 \
    --size s-2vcpu-4gb-amd \
    --region sgp1 \
    --vpc-uuid 646cf2b8-03d8-4f48-b7c8-57cdee60ad27 \
    --ssh-keys 25621060 \
    apisix-nodered-docker-ubuntu-s-2vcpu-4gb-amd-sgp1-01
  
$ doctl compute droplet list

ID           Name                                                    Public IPv4       Private IPv4    Public IPv6    Memory    VCPUs    Disk    Region    Image                                   VPC UUID                                Status    Tags    Features                            Volumes
404094941    apisix-nodered-docker-ubuntu-s-2vcpu-4gb-amd-sgp1-01    143.198.192.64    10.104.0.3                     4096      2        80      sgp1      Ubuntu Docker 25.0.3 on Ubuntu 22.04    646cf2b8-03d8-4f48-b7c8-57cdee60ad27    active            droplet_agent,private_networking

Implantação do Apache APISIX

Vamos usar o APISIX Quickstart para iniciar uma nova instância do APISIX, para documentação específica, consulte https://docs.api7.ai/apisix/getting-started/.

$ curl -sL https://run.api7.ai/apisix/quickstart | sh

Implantação do Node-RED

O Node-RED fornece vários métodos de implantação, e vamos implantá-lo rapidamente via Docker e integrá-lo ao ambiente existente. Para mais detalhes de implantação, consulte a documentação oficial: https://nodered.org/docs/getting-started/.

Ao implantar o Node-RED, certifique-se de que o contêiner seja adicionado à rede do APISIX para garantir que ele possa se comunicar com o APISIX e lidar com solicitações.

$ docker run -d -it -p 1880:1880 -v $PWD/configs/nodered/data:/data --network=apisix-quickstart-net --name mynodered -u Node-Red:dialout nodered/Node-Red

Configuração do Node-RED

  1. Para lidar com solicitações que entram no Node-RED a partir do APISIX, o Node-Red precisa verificar se os parâmetros na solicitação existem e são válidos. Se os parâmetros estiverem ausentes ou forem inválidos, uma mensagem de erro será retornada. Se forem válidos, o próximo nó será executado. Neste cenário específico, permitimos apenas consultas de dados para duas cidades, Estocolmo (city=stockholm) e Berlim (city=berlin).

Usar Node-Red para verificar parâmetros

  1. Uma vez que a solicitação entra no próximo nó, o Node-RED precisa determinar o tipo de dados solicitados. Neste cenário, há três tipos: informações meteorológicas (scope=weather), informações sobre o país onde a cidade está localizada (scope=country) e o PIB do país onde a cidade está localizada (scope=gdp).

Usar Node-Red para direcionar o tipo de dados

  1. Se ambos os parâmetros City e Scope forem válidos, o Node-RED determinará de qual API recuperar os dados com base no valor de scope. Após definir a URL, Método, Payload, X-API-Key, etc., o nó do Node-RED acessará o endpoint correspondente para recuperar dados quando acionado.

Escolher API para obter dados de acordo com o escopo

  1. Ao recuperar dados para scope=gdp, o Node-RED precisa extrair o valor do PIB do corpo da resposta da API externa. Isso pode ser feito usando o nó Change para extração ou o nó Function.

Analisar valor do PIB do corpo da resposta da API externa

  1. Finalmente, o Node-RED retornará os dados processados ao APISIX, que os passará ao cliente. O diagrama final do Node-RED é mostrado abaixo.

Fluxograma da combinação do APISIX e Node-Red

Criação de Rotas do APISIX

Para disponibilizar o serviço Node-Red aos clientes, precisamos usar o APISIX como um proxy reverso para os endpoints expostos pelo Node-Red. Aqui estão os passos que você precisa seguir:

  1. Criar uma Rota do APISIX e definir mynodered:1880 como o upstream para esta Rota. Ao fazer isso, todas as solicitações enviadas a este endpoint serão encaminhadas para o serviço Node-Red.

  2. Habilitar a Autenticação por Chave para garantir que apenas solicitações que carregam uma API Key válida possam passar na autenticação e acessar o serviço Node-Red.

Seguindo os passos acima, podemos expor com segurança o serviço Node-Red aos clientes e garantir que apenas usuários autorizados possam acessá-lo.

$ curl -i "http://127.0.0.1:9180/apisix/admin/routes" -X PUT -d '
{
  "id": "proxy-global-data-endpoint",
  "uri": "/global-data",
  "upstream": {
    "type": "roundrobin",
    "nodes": {
      "mynodered:1880": 1
    }
  },
  "plugins": {
    "key-auth": {}
  }
}'

$ curl -i "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT -d '
{
  "username": "tom",
  "plugins": {
    "key-auth": {
      "key": "secret-key"
    }
  }
}'

Validação de Solicitação

Vamos tentar vários cenários separadamente para verificar se o APISIX e o Node-Red se comportam conforme o esperado:

Cenário 1

  • Descrição do Cenário: Acessar a API com uma Key incorreta.

  • Resultado Esperado: Como a API Key fornecida está incorreta, a solicitação deve ser rejeitada, e a mensagem de erro correspondente deve ser retornada.

$ curl http://143.198.192.64:9080/global-data -H "apikey: invalid-key" -i

HTTP/1.1 401 Unauthorized
Date: Mon, 04 Mar 2024 07:47:24 GMT
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX/3.8.0

{"message":"Invalid API key in request"}

Cenário 2

  • Descrição do Cenário: Acessar a API com a Key correta, mas um campo City inválido.

  • Resultado Esperado: Como os parâmetros da solicitação não atendem aos requisitos, a mensagem de erro correspondente deve ser retornada, indicando que o campo City é inválido.

$ curl "http://143.198.192.64:9080/global-data?city=singapore&scope=country" -H "apikey: secret-key" -i

HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8
Content-Length: 69
Connection: keep-alive
Access-Control-Allow-Origin: *
X-Content-Type-Options: nosniff
ETag: W/"45-IOhgB2XkDHi2Kt4PP42n1xa8Gys"
Date: Mon, 04 Mar 2024 07:48:02 GMT
Server: APISIX/3.8.0

{"errorCode":400,"message":"Allowed city Options: Stockholm, Berlin"}

Cenário 3

  • Descrição do Cenário: Acessar a API com a Key correta e campos City e Scope válidos para recuperar dados do país.

  • Resultado Esperado: A solicitação deve ser bem-sucedida, e informações relevantes sobre o país onde a City está localizada devem ser retornadas.

$ curl "http://143.198.192.64:9080/global-data?city=stockholm&scope=country" -H "apikey: secret-key" -i

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 947
Connection: keep-alive
Access-Control-Allow-Origin: *
X-Content-Type-Options: nosniff
ETag: W/"3b3-XDlm9OHfuUrWH+g42q8L1F2uu/o"
Date: Mon, 04 Mar 2024 07:48:26 GMT
Server: APISIX/3.8.0

[{"gdp":556086,"sex_ratio":100.4,"surface_area":438574,"life_expectancy_male":80.8,"unemployment":6.7,"imports":158710,"homicide_rate":1.1,"currency":{"code":"SEK","name":"Swedish Krona"},"iso2":"SE","employment_services":80.7,"employment_industry":17.7,"urban_population_growth":1.1,"secondary_school_enrollment_female":157.9,"employment_agriculture":1.6,"capital":"Stockholm","co2_emissions":37.6,"forested_area":68.9,"tourists":7440,"exports":160538,"life_expectancy_female":84.4,"post_secondary_enrollment_female":82.1,"post_secondary_enrollment_male":52.7,"primary_school_enrollment_female":127.4,"infant_mortality":2,"gdp_growth":2.2,"threatened_species":98,"population":10099,"urban_population":87.7,"secondary_school_enrollment_male":148.1,"name":"Sweden","pop_growth":0.7,"region":"Northern Europe","pop_density":24.6,"internet_users":92.1,"gdp_per_capita":55766.8,"fertility":1.8,"refugees":310.4,"primary_school_enrollment_male":125.8}]

Cenário 4

  • Descrição do Cenário: Acessar a API com a Key correta e campos City e Scope válidos para recuperar dados de GDP.

  • Resultado Esperado: A solicitação deve ser bem-sucedida, e os dados de GDP para o país onde a City está localizada devem ser retornados.

$ curl "http://143.198.192.64:9080/global-data?city=stockholm&scope=gdp" -H "apikey: secret-key" -i

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 6
Connection: keep-alive
Access-Control-Allow-Origin: *
ETag: W/"6-j8I5kokycgWjCeKC1c2UfJW7AQY"
Date: Mon, 04 Mar 2024 07:48:48 GMT
Server: APISIX/3.8.0

556086

Ao verificar esses quatro cenários, podemos confirmar que o APISIX e o Node-Red estão funcionando conforme o esperado e podem lidar corretamente com vários tipos de solicitações.

Resumo

Fornecemos uma nova abordagem para resolver de forma mais inteligente o problema de desenvolvimento de capacidades personalizadas, demonstrada por um exemplo detalhado.

  1. Roteamento de Solicitação de API e Verificação de Identidade: Primeiro, utilizando a funcionalidade de roteamento do Apache APISIX e plugins de autenticação, o APISIX encaminha as solicitações dos clientes para o serviço Node-Red quando as credenciais fornecidas são válidas.

  2. Processamento e Transformação de Solicitação: No Node-Red, criamos um fluxo para processar as solicitações de API recebidas. Usando o nó HTTP input para receber solicitações do APISIX, analisamos e validamos os parâmetros da solicitação para garantir que atendam aos requisitos do negócio.

  3. Processamento de Lógica de Negócio: Uma vez que uma solicitação válida é recebida, podemos executar a lógica de negócio no Node-Red. Por exemplo, enviar solicitações a diferentes APIs de negócio com base nos parâmetros para recuperar dados e extrair os campos necessários da resposta. Após concluir essas operações, os dados finais são retornados ao APISIX.

  4. Tratamento de Erros e Registro: Durante o processamento, se ocorrerem erros ou exceções, podemos adicionar nós de tratamento de erros no Node-Red para capturar e lidar com situações excepcionais. Além disso, podemos usar nós de registro para gravar informações-chave durante o processamento para posterior solução de problemas e análise, o que não é demonstrado neste exemplo.

Ao combinar o APISIX e o Node-Red, podemos implementar visualmente um processo completo de tratamento de solicitações, incluindo roteamento de solicitações, processamento de dados, lógica de negócio, etc., sem a necessidade de escrever código ou plugins complexos. Essa solução flexível e personalizável pode nos ajudar a construir e ajustar a funcionalidade do sistema mais rapidamente, melhorar a eficiência de desenvolvimento, reduzir custos de desenvolvimento e garantir a estabilidade e escalabilidade do sistema.

Tags: