Aplicações Web modernas trabalham num modelo em que a API tem um papel central. De uma API bem definida e padronizada é possível criar uma camada de apresentação Web num modelo de Single Page Application, uma experiência mobile com Apps ou a integração com sistemas de terceiros.
Num primeiro impulso, pode parecer que usar uma API pré-existente também seria a solução ideal para conectar dispositivos físicos a uma lógica de negócio pré-existente - criando uma experiência real de Internet das Coisas, como permitir que um cliente compre produtos usando um botão físico.
É preciso porém avaliar com mais cuidado se esse é o melhor caminho. IoT tem suas particularidades que precisam ser atendidas.
Dispositivos de IoT em geral são devices de custo razoavelmente baixo, sem tela, muitas vezes com conectividade limitada e distribuídos numa escala maior que aplicações mobile ou web. As projeções indicam que num futuro não distante a quantidade de dispositivos desse tipo deve superar a quantidade de smartphones em proporção de 4:1. Vale a pena considerar os impactos desse cenário.
Há muitos tipos de dispositivo, mas para poder exemplificar as limitações, vamos dividir aqui em dois grupos de estudo: dispositivos semelhantes a Single Board Computers e Microcontroladores. Cada grupo tem suas vantagens e seus desafios.
Na linha de Single Board Computers, o representante mais bem sucedido no momento é o Raspberry Pi e suas variações. Um Raspberry Pi 3 tem muitas opções de conectividade (WiFi, Bluetooth, Ethernet) e capacidade de processamento invejável. É possível trabalhar em cima de um Sistema Operacional como Linux ou Windows e a experiência de se trabalhar com um dispositivo desse tipo é muito parecida com a de se trabalhar com um pequeno servidor virtual na nuvem.
As ferramentas são similares às que usamos no dia-a-dia do desenvolvimento de aplicações convencionais, tendo muitas opções de escolha. Linguagens de alto nível como Java, Javascript, Python e Ruby estão disponíveis e funcionam exatamente da mesma maneira que em um ambiente na nuvem. Os mesmos frameworks e bibliotecas a que temos acesso no momento de construir ou consumir micro serviços também estão disponíveis em um Single Board Computer. O desenvolvimento é fácil e a compatibilidade tecnológica é alta.
Dadas tais características, é possível usar uma API pré-existente de maneira muito natural. Não há grandes diferenças entre um Single Board Computer e um Smartphone ou uma aplicação Web.
Por outro lado, há características que talvez não sejam as mais desejáveis para uma solução de IoT. O custo pode ser elevado (um Pi3 é vendido por aproximadamente 35 dólares) e o consumo de energia elevado torna o uso de baterias improvável.
Do outro lado, temos um outro grupo de dispositivos em soluções de IoT que é o grupo de Microcontroladores. Nessa linha, o representante mais bem sucedido para protótipos e iniciantes é o Arduino.
Soluções baseadas em microcontroladores têm vantagens como consumo de energia muito reduzido e tempo de inicialização extremamente rápido. É possível combinar essas duas características de maneira formidável através da aplicação de duty cycles: ciclos em que o microcontrolador realiza uma determinada tarefa, entra em sono profundo com um consumo de energia extremamente reduzido (~1000x menos que um Single Board Computer) e acorda novamente depois de um período para retomar suas atividades. Combine isso a microcontroladores otimizados para baixo consumo e é possível construir soluções que podem operar por anos em uma única carga de bateria e ocupando pouco espaço. O custo também tende a ser bastante acessível. É possível encontrar dispositivos desse tipo por custos próximos a 2 dólares. Perfeito para sensores em locais de difícil acesso ou ambientes em que não há energia elétrica constante.
As limitações são muitas, entretanto. Tais dispositivos, às vezes chamados de Constrained Devices, estão bastante distantes da realidade do desenvolvedor de aplicações para a nuvem. Não é incomum trabalhar com apenas 2K de memória RAM. O desenvolvimento é com com linguagens de mais baixo nível (C, C++, Sketch, Assembly) e normalmente usando as bibliotecas e ferramentas disponibilizadas pelo próprio fabricante do microcontrolador. Há pouca portabilidade: código escrito para um modelo de dispositivo dificilmente pode ser reutilizado em outro modelo. Há ainda as dificuldades relacionadas a conectividade: frequentemente tais dispositivos estão conectados em rede com baixas taxas de transferência e latência alta. Uma sessão de depuração remota é inviável.
Dadas tais limitações, quando um desenvolvedor de firmwares para microcontroladores precisa interagir com uma API REST, muitas vezes opta por implementar parte do protocolo manualmente, para poupar recursos e evitar importar bibliotecas adicionais. Essas implementações podem ser um problema, uma vez que tratam apenas do mínimo necessário para fazer com que a solução funciona - sem tratar dos pormenores do protocolo. Se no futuro a API evolui ou migra para uma infraestrutura distinta, não há garantias de que as soluções que foram implementadas manualmente - ou que dependem de uma biblioteca pouco usada - serão capazes de lidar com a nova situação.
Um outro ponto de atenção está relacionado com o quão extensos são os cabeçalhos do protocolo. Uma chamada a uma API REST, especialmente se usada para enviar pequenos trechos de dados, gasta mais banda de rede transportando cabeçalhos e metadados do que informação per-se. E numa solução desse tipo, consumo maior de rede em geral implica em consumo maior de bateria - porque o microcontrolador e o rádio precisam ficar mais tempo ligado do que necessário.
APIs REST não são muito naturais do ponto de vista de um desenvolvedor de firmware para dispositivos com capacidade limitada e não são a melhor solução para interagir com tais dispositivos.
Se realmente é necessário exportar um endpoint REST para um dispositivo restrito, algumas práticas podem ser adotadas para minimizar as dificuldades envolvidas. Uma delas é considerar endpoints distintos para a aplicações e dispositivos. Isso permite, entre outras coisas, que a infraestrutura possa ser tunada para os clientes específicos. Dispositivos de IoT em geral precisam de timeouts mais generosos que browsers, por exemplo. Também é possível remover cabeçalhos não essenciais e eventualmente trafegar dados em formatos diferentes. Não é bom contar com a capacidade do dispositivo em tratar de compressão de dados: o melhor é trafegar o mínimo possível de informação, num formato bastante compacto.
Há alternativas, porém. Mecanismos que são capazes de cobrir o gap entre o que é natural para um desenvolvedor de aplicações na nuvem e o que é mais natural para um desenvolvedor de firmware mais limitado.
Uma alternativa é o uso de protocolos mais adequados, como é o caso de MQTT. O MQTT é um protocolo feito especificamente para troca de informações como nos cenários de dispositivos limitados. É um modelo assíncrono (pub/sub) com cabeçalhos bem mais enxutos que HTTP. Além disso, por ser assíncrono, não exige uma resposta do servidor a cada mensagem enviada. Tráfego de informação em formato binário, muito mais compacto e natural do que JSON, é bastante simples em MQTT. Há um grande número de bibliotecas disponíveis para diferentes dispositivos e arquiteturas e a natureza do protocolo binário desencoraja que o desenvolvedor faça a implementação manualmente do lado do device. É frequentemente uma opção mais econômica em termos de recursos e mais robusta para soluções IoT com limitações de rede e bateria.
O ponto negativo dessa abordagem é ter que criar e manter um componente de software e de infra para realizar a interface entre o broker MQTT e a API já pré-existente.
Um outro caminho é o uso de Plataformas e Gateways de IoT. Tais plataformas fazem o trabalho de cobrir o gap entre o mundo cloud e o mundo do device de uma maneira que seja natural para ambos os lados, com pouco ou nenhum esforço de codificação envolvido. Também procuram adicionar serviços, como gestão de dispositivos, monitoração e atualização de firmware, entre outros aspectos de aceleração de construção de dispositivos. Aqui também há pontos a serem considerados. Há soluções que variam desde frameworks a modelos do tipo plataforma como serviço (PaaS), passando por gateways físicos que fazem esse papel. Cada uma dessas soluções tem seus desafios próprios. De uma maneira geral, é importante considerar especialmente o possível problema de vendor lock in. Qualquer solução que se apresente nesse cenário é superior quando trabalha com protocolos abertos e, preferencialmente, seja Open Source.
Em resumo, é possível pensar em disponibilizar uma API convencional para dispositivos em um cenário de IoT - mas deve-se fazê-lo levando em consideração as limitações dos dispositivos. Para alguns cenários, não há grandes preocupações: Single Board Computers tem o mesmo ferramental que servidores na nuvem. Para dispositivos extremamente limitados, como microcontroladores, considere uma abordagem distinta. Uma troca de protocolo ou o uso de uma plataforma para cobrir os gaps entre a API e o dispositivo podem prevenir muitos problemas e produzir melhores resultados.