Boas Práticas na Construção de APIs REST

Walter de Oliveira Pinto Coelho
25 de Junho de 2020

Palavras-chave: API, Boas Práticas, REST, RESTful, Contrato de API, Segurança, Versionamento

Sua solução alcançou um bom nível de estabilidade e agora você pretende criar uma API pública para prover serviços ao seu aplicativo e clientes Web. Porém, você percebe que a construção com qualidade de uma API segura não é algo trivial e efetuar alterações depois que ela está em produção é um processo bastante delicado e arriscado. Qual o melhor caminho? Quais fatores devem ser considerados? A API deve ser versionada? Como aplicar segurança nas transações? A ideia deste artigo é clarear conceitos gerais sobre API REST e fornecer algumas opções como respostas a estas perguntas.

O QUE É UMA API?

De maneira bem resumida, pode-se dizer que a API (Application Programing Interface – Interface de Programação de Aplicações) é uma interface de usuário que é consumida por uma aplicação e não por uma pessoa, permitindo que funcionalidades sejam utilizadas sem conhecimento da implementação de software.

O QUE É REST?

APIs modernas são normalmente criadas sobre o conceito de REST, que é um conjunto de princípios para expor serviços em sistemas distribuídos.

O termo REST (REpresentational State Transfer - Transferência de Estado Representacional) foi introduzido por Roy Fielding em 2000, em sua tese de doutorado [1]. Apesar de Roy Fielding ter sido também um dos criadores do protocolo HTTP, os princípios REST não têm relação obrigatória com HTTP.

O REST se baseia no seguinte conjunto de princípios:

  • Separação clara de responsabilidades entre cliente e servidor;
  • Ausência de estado (stateless): a comunicação entre cliente-servidor deve ocorrer independente de estado, não cabendo ao servidor armazenar qualquer tipo de contexto;
  • Suporte a cache: cada resposta a uma requisição pode ser explícita ou implicitamente marcada como “cacheável”. O uso de cache ajuda a melhorar o desempenho das transações.
  • A interface de acesso dos componentes do servidor deve ser uniforme, baseada em especificações claras e bem definidas. A característica principal que diferencia o estilo arquitetural REST dos demais é uma interface uniforme entre os componentes cliente e servidor.

A estrutura de descrição de um recurso REST possui quatro propriedades:

  • Representação: um ou mais formatos para representação da informação. Exemplos incluem XML, JSON ou formato binário;
  • Identificador (endpoint): uma URL que recupera somente um recurso específico em um dado momento;
  • Metadados: informações relevantes sobre a mensagem;
  • Dados de controle: controle de cache, permissão de modificação, entre outros.

Os recursos REST são manipulados com a utilização de requisições HTTP e métodos apropriados para cada tipo de ação desejada. Abaixo são listados os métodos mais utilizados:

  • POST: criar um Recurso. Pode retornar alguns atributos como resposta, sendo o mais comum o Id, que é o identificador único relativo ao recurso criado;
  • GET: ler um Recurso. Retorna um recurso específico ou uma lista de recursos;
  • PUT: atualizar um Recurso por completo. Todos os dados do Recurso são enviados, mesmo se somente alguns deles foram alterados;
  • PATCH: atualizar parte de um Recurso existente. Somente os dados a serem alterados são enviados na requisição;
  • DELETE: deletar um Recurso.

As mensagens de resposta às requisições e seus formatos variam de acordo com as especificações do provedor API.

O estado das transações é identificado a partir de códigos de status enviados pelo provedor API em resposta às requisições dos clientes. São eles:

  • 1xx: mensagens Informativas;
  • 2xx: indicação de que a Requisição foi recebida com Sucesso;
  • 3xx: indicação de Redirecionamento;
  • 4xx: indicação de Erro por parte do Cliente;
  • 5xx: indicação de Erro por parte do Servidor.

É muito importante que estes códigos sejam interpretados e tratados corretamente, possibilitando a criação de mensagens amigáveis no lado do cliente.

O QUE É RESTFUL?

Há uma confusão com relação aos termos REST e RESTful, mas ambos representam os mesmos princípios, havendo diferença somente gramatical [2]. É comum, e não incorreto, denominar de RESTful os sistemas que utilizam os princípios REST. Dessa forma, pode-se aplicar os conceitos abaixo:

  • REST: conjunto de princípios de arquitetura;
  • RESTful: capacidade de determinado sistema aplicar os princípios de REST.

CONTRATO DE API

A primeira ação que deve ser executada no processo de construção de uma API é a elaboração de um conjunto de especificações técnicas que definem a estrutura para realizar requisições ao servidor e receber as respostas desejadas no cliente (Request/Response). A este conjunto de especificações, é dado o nome de “contrato”.

Assim como acontece com qualquer outro tipo de contrato, todas as regras estabelecidas por ele devem ser rigorosamente seguidas pelas partes envolvidas, neste caso desenvolvedores e software provedor da API. O não atendimento destas regras, ou seja, a “quebra de contrato”, ocasionará um mal funcionamento ou interrupção dos serviços expostos pela API.

O contrato deve ser criado preferencialmente por um desenvolvedor. O ideal é que ele tenha o conhecimento completo do domínio da solução, dando a ele a possibilidade de gerar sozinho as especificações, podendo efetuar testes e validações enquanto as especifica, o que dá agilidade ao processo. Caso contrário, ele irá precisar da ajuda de algum especialista no domínio, o que pode ocasionar um atraso na execução do processo, tendo em vista a dependência da disponibilidade deste especialista e discussões necessárias para alinhamento entre as partes envolvidas.

Existem diferentes ferramentas que permitem criar um contrato e obter sua documentação. Pode-se citar as principais:

  • Swagger (OAI 3.0.1): estrutura de software de código aberto. Sua licença pertence à Apache;
  • RAML: linguagem de modelagem de API RESTful baseada em YAML;
  • BluePrint: ferramenta do design thinking que mapeia interações de prestações de serviços.

Há uma forte tendência de que o Swagger se torne a ferramenta padrão. De qualquer forma, independentemente da ferramenta utilizada, é de extrema importância que a documentação seja feita com qualidade, tomando-se o cuidado de mantê-la sempre atualizada.

REQUISITOS IMPORTANTES

É possível encontrar opiniões diversas na Internet sobre construção de APIs, mas não é difícil perceber que a grande maioria se baseia em discussões acadêmicas, trazendo interpretações subjetivas, padrões confusos, em direção contrária ao que se espera para uma solução ideal.

O mestre em Ciência da Computação, Marcos Mendes [3], lista alguns requisitos de suma importância que devem ser atendidos ao se construir APIs de boa qualidade:

  • Organize APIs condizentes com os recursos relacionados. As URIs (endpoints) expostas por um serviço REST devem ser baseadas em substantivos e não em verbos. Exemplo: “/eventos” ao invés de “/recuperaEventos”;
  • Procure utilizar somente letras minúsculas nas URIs e hífen como separador, melhorando a legibilidade;
  • Evite projetar uma interface REST que espelhe ou dependa da estrutura interna dos dados que ela expõe. O objetivo do REST é mapear as entidades de negócios e as operações que um aplicativo pode executar nessas entidades para a implementação física das mesmas, mas um cliente não deve ser exposto a esses detalhes físicos;
  • Adote uma convenção de nomenclatura consistente nas URIs. Recomenda-se fortemente o uso de substantivos no plural para URIs que fazem referência a coleções;
  • Crie APIs simples. Evite criar URIs de recursos mais complexos do que coleção/item/coleção. Exemplo: /usuarios/12/mensagens, para operações relacionadas às mensagens associadas ao usuário com identificador (id) 12;
  • Considere implementar operações HTTP PUT em massa que possam atualizar em lotes vários recursos de uma coleção de dados. Esta abordagem pode ajudar a reduzir ineficiências do protocolo HTTP e melhorar o desempenho da aplicação.

VERSIONAMENTO

A API deve ser versionada. O controle correto de versões evita que solicitações inválidas, deprecadas, atinjam URIs atualizadas, causando erros ou total paralização do serviço. Uma das principais vantagens em se manter o versionamento é continuar oferecendo versões antigas da API, mesmo que por um período determinado de tempo, dando aos clientes um prazo maior para que seja feita a atualização do seu lado.

Existem opiniões divergentes sobre se uma versão da API deve ser incluída no URL ou em um cabeçalho [4] . Academicamente falando, provavelmente deve estar em um cabeçalho. No entanto, pode-se considerar como melhor abordagem a utilização da versão na URL, o que permite o acesso fácil pelo cliente às diferentes versões.

Seguindo a abordagem que o Stripe  adotou para a versão da API [5], considera-se que a URL deve ter um número de versão principal (v1), mas a API mantém subversões baseadas em datas que podem ser filtradas a partir de um cabeçalho de solicitação HTTP personalizado. Nesse caso, a versão principal fornece estabilidade estrutural da API como um todo, enquanto as subversões são responsáveis ​​por alterações menores (descontinuações de campo, alterações de terminal etc.).

Uma API nunca será completamente estável, alterações são inevitáveis. O importante é como essas alterações são gerenciadas. O correto planejamento, a elaboração de uma boa documentação e o envio de notificações aos clientes em tempo hábil são práticas fundamentais que devem ser seguidas.

SEGURANÇA

A relação entre o esforço na implementação de segurança e seu custo deve ser considerada como principal fator de avaliação. É certo que o ideal seria ter somente sistemas absolutamente seguros, mas isso pode ter um custo bem alto, devendo a decisão ser baseada sempre no que pode ser considerado “bom o suficiente”.

As ações relativas à segurança devem levar em consideração duas partes: infraestrutura e desenvolvimento.

É certo que uma API privada pode ser muito mais blindada pela infraestrutura, tornando menos complexas as preocupações dos desenvolvedores. Tratando-se de numa API pública, o grau de exposição é infinitamente maior, tendo como consequência um grande potencial de sofrer ataques cibernéticos diversos, de diferentes tipos, exigindo por parte da solução uma série de ações para garantir acessos legítimos e autorizados.

Um outro fator importante na decisão do nível de segurança a ser adotado é o grau de sensibilidade dos dados que serão expostos pela API. Quanto mais interessantes forem os dados, mais rígidas devem ser as políticas de controle de acesso.

Atualmente, a utilização de comunicação/tratamento de dados via API é algo bem frequente, sendo normal a integração entre diferentes sistemas utilizando essa abordagem, o que exige um cuidado ainda maior em segurança.

Dentre os mecanismos de segurança mais comuns, tem-se [6]:

Restrição de acesso pela infraestrutura de rede: em APIs internas, pode ser que o controle da segurança seja totalmente implementado pela infraestrutura, através, por exemplo, de restrições de acesso por IP, protocolos de comunicação, portas, Mac Address etc.;

  • Utilização de HTTPS: servidores que se comunicam via HTTPS possuem chance muito menor de brechas de segurança. Sendo utilizado em conjunto com a restrição de acesso na rede, já é uma solução segura para APIs privadas na maioria dos casos;
  • Autenticação/Autorização HTTP básica (HTTP Basic): a autenticação HTTP básica é uma forma simples de um cliente informar suas credenciais de acesso ao fazer uma requisição HTTP. Na autenticação HTTP Básica, o usuário e senha do cliente são enviados ao servidor codificados em Base64. Esta forma de autenticação provê algum controle de acesso, mas é vulnerável a interceptações na rede, o que pode ser minimizado com o uso de HTTPS para proteger o canal de comunicação;
  • Autenticação/Autorização HTTP Digest: a autenticação HTTP Digest é outra forma de controle de acesso a recursos web, e é mais segura que a HTTP Básica. Ela aplica um hash criptográfico MD5 na senha antes de enviá-la pela rede, com uso de valores nonce (número arbitrário que só pode ser usado uma vez) para prevenir contra replay attacks (modalidade de ataque cibernético no qual há a transmissão de dados válidos repetidamente ou propositalmente de forma lenta para prejudicar o desempenho);

Os cálculos MD5 usados na autenticação digest buscam ser unidirecionais, ou seja, deve ser difícil obter o valor de entrada somente a partir da saída.

Porém, se a senha for muito simples não deve ser tão custoso o processo de quebra por força-bruta;

  • Autenticação/Autorização através de Certificados: a autenticação/autorização através de certificados também do lado do cliente é um refinamento adicional de segurança sobre a comunicação HTTPS, que já pode ser feita com certificados só do lado do servidor. Esta forma de autenticação/autorização é bastante segura. Porém, o trabalho e custo de lidar com certificados dos 2 lados é razoável, sendo adequado só em cenários muito sensíveis de segurança;
  • Autorização baseada em Token: esta é uma forma simples e segura de controlar autenticação/autorização de serviços. Baseia-se na criação de um token pelo servidor a partir das credenciais enviadas pelo cliente, podendo ou não haver a utilização de outros dados no processo de criação. Esse token tem um tempo determinado de vida e deve ser utilizado em todas transações entre o cliente e servidor;
  • OAuth: o OAuth é um padrão aberto para autorização. Ele provê um método para clientes acessarem recursos no servidor por parte do dono do recurso. Ele também provê meios de usuários finais autorizarem acesso de terceiros a seus recursos em um servidor sem informar suas credenciais, normalmente através de redirecionamentos e confirmações por parte dos usuários. O OAuth é comumente utilizado quando se tem um aplicativo que precisa manipular APIs com dados de usuários finais e estes precisam autorizar o acesso. O OAuth não tem adesão tão grande devido à complexidade na implementação.

CONCLUSÃO

Não é exagero afirmar que os desenvolvedores são a parte mais importante da cadeia de valores de uma API REST. É fundamental que eles tenham em mãos todas as informações necessárias, tenham total consciência da importância da aplicação de boas práticas na construção de APIs e possuam conhecimento e capacidade para utilizá-las, oferecendo uma solução eficiente, amigável, segura e, por que não, atraente e agradável de ser utilizada.

REFERÊNCIAS BIBLIOGRÁFICAS

[1] Roy T. Fielding. Dissertation - Architectural Styles and the Design of Network-based Software, 2000.

[2] O que é API? REST e RESTful? Conheça as definições e diferenças! Disponível em: <https://becode.com.br/o-que-e-api-rest-e-restful/>. Acesso em 25/10/2019.

[3] Mendes, Marcos. Arquitetura de Sistemas Web - Princípios, Práticas e Tecnologias, 2017

[4] Best Practices for Designing a Pragmatic RESTful API. Disponível em: <https://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api>. Acesso em 24/10/2019.

[5] APIs as infrastructure: future-proofing Stripe with versioning. Disponível em: <https://stripe.com/en-br/blog/api-versioning>. Acesso em: 25/10/2019.

[6] Segurança em APIs REST. Disponível em: <https://blog.mandic.com.br/artigos/seguranca-em-apis-rest-parte-