APIs e Microsserviços

31 dez, 2014

Melhores de 2014 – Criando uma API respeitável

Publicidade

Desenvolvedores PHP estão progressivamente migrando para o desenvolvimento de APIs, já que há muitos desenvolvedores server-side. É uma tendência que tem ocorrido por alguns anos e chegou a um ponto em que todo mundo está escrevendo artigos que mostram como fazer uma “API incrível”. Infelizmente, a maior parte desses artigos é lamentavelmente inadequada ou promove práticas ruins.

Não vou colocar o link de nenhum exemplo ruim aqui porque isso é rude, mas há algumas regras de ouro às quais me apego ao criar uma API.

Nunca exponha resultados da base de dados diretamente

  1. Se você renomear um campo, então seus usuários estarão ferrados. Converta-os com uma estrutura de array hardcoded.
  2. A maior parte dos drivers de banco de dados (para PHP) exibirá números inteiros como strings numéricas e false como “0” (zero), então você vai querer converter o tipo (typecast) tanto quanto seus arrays forem utilizados para dar saída.
  3. A não ser que estiver utilizando ORM com funcionalidade “escondida”, pessoas verão senhas, saltos e todo o tipo de código extravagante. Se acrescentar qualquer coisa e esquecer de colocá-la no seu array $hidden, então OPS! Declare manualmente suas saídas e NÃO use return Users::all();

Use a URI com parcimônia e corretamente

  1. Use a string de query para parâmetros pais em vez de /users/id/5/active/true. Sua API não precisa ser otimizada para SEO.
  2. ?format=xml é estúpido, use um cabeçalho Accept: application/xml. Eu acrescentei isso certa vez para o servidor rest do CodeIgniter para as pessoas preguiçosas, e agora acham que isso é uma coisa legal, mas não é.
  3. Torne todos os seus recursos plurais. /user/X talvez faça sentido inicialmente, mas quando você tem uma palavra como “oportunidade”, as coisas se tornam estranhas mais rápido. /opportunities e /oppertunity/X causam dor.

Recursos são TUDO

  1. Você está sempre ou requisitando um recurso ou múltiplos. Se for apenas um, apenas retorne os dados como um array. Se requisitou múltiplos, então retorne-os como elementos pais plurais (tal como “users”).
  2. Dois recursos em locais diferentes devem parecer idênticos (seu desenvolvedor iPhone vai te amar por isso). Isso pode ser /me/friends e /users/5/friends ou dados embarcados.
  3. Se quiser múltiplos recursos em uma única chamada, então entregue-os para mim. /users/X,Y,Z em um array “users” funciona bem.
  4. Se requisitar múltiplos e existir algum resultado, envie-os em um array “users”.
  5. Se requisitar múltiplos mas não encontrar nenhum, então um 404 faz sentido.

JSON, XML ou cale-se

  1. Não fique eternamente tentando fazer o seu sistema dar saída de absolutamente tudo o que existe. É claro que você pode dar saída lolcat, mas não é necessário.
  2. Diga a seus usuários para enviar um JSON ou um XML no body. Mexer com application/x-www-form-urlencoded e formatação de chave/valor apenas para conseguir dados com $_POST[‘foo’] é estranho, especialmente quando qualquer framework decente (como o Laravel 4) permitirá Input::json(‘foo’) de qualquer forma.
  3. Sem parâmetros de carga. Já vi APIs aceitarem application/x-www-form-urlencoded com um parâmetro json={}. Se achar que isso é uma boa ideia, é hora de voltar ao seu treino de yoga ou algo assim, pois o estresse deve estar afetando seu julgamento.

Autenticação

  1. OAuth 2 é o lance! Algumas pessoas escreveram bobagens sobre o como ele é inseguro, porque não estavam utilizando SSL. Ou porque a empresa X implementou mal o protocolo. Não implemente mal o protocolo.
  2. A não ser que sua API esteja protegida da Internet por um firewall, use SSL.
  3. Tenha certeza de que sua implementação do Oauth 2 é compatível com as especificações, ou você passará por maus momentos, como este.

Cache

  1. Sua API precisa de uma memória menor do que saber que minha fruta favorita é melancia. Não reconheça o IP, a sessão ou o estado. Não tente adivinhar, deixe que te digam quem são através de seu token de acesso.
  2. Cache deve ocorrer só em informações populares onde não há contexto de usuário e que você sabe que não haverá alteração durante esse tempo.
  3. O cabeçalho Cache-Control permite que as pessoas possam (ou devam) fazer cache das coisas. Se outros desenvolvedores ignoram esses cabeçalhos, então é problema deles.

Tudo em background

  1. “Quando o usuário nos envia uma imagem, redimensione-a, faça o upload para o S3, envie um e-mail e então exiba a confirmação”. Não. Deve haver pelo menos uma tarefa em background, preferencialmente 3, com uma resposta IMEDIATA. Deixe de ter apenas uma tarefa “processamento_imagem” para fazer as coisas.
  2. Crie uma tarefa “email”, uma tarefa “sms” e uma tarefa “APN” por exemplo, para que você possa enviar genericamente qualquer tipo de contato a partir da sua API, suas outras tarefas etc., sem infectar sua API com todo tipo de coisa. Posso trocar do Twilio para… bem, não conheço nada melhor, mas poderia fazer isso muito facilmente ao atualizar a tarefa de envio de SMS.
  3. Ponha seus “workers” em diferentes servidores. O servidor da sua API está ocupado o suficiente administrando requisições e respostas HTTP; não o faça ter que pensar em outra coisa.

Paginação

  1. Faça isso. Muitas pessoas apenas despejam todos os dados do jeito “tome isso” na resposta e esquecem que ela pode ficar bem grande com o tempo.
  2. Inclua um elemento “paging”, que possui uma URL “next” ou “previous” se houver mais coisas de qualquer um dos lados.
  3. Não faça o cliente ter que calcular qualquer coisa.
  4. ENVIE A SAÍDA COM OS TOTAIS. Estou apontando para você Facebook. Porque eu preciso requisitar “next” 20 vezes para manualmente count($response[‘data’]) para ver quantos amigos um usuário específico possui quando você obviamente já sabe a resposta? BAH!

Códigos de respostas

  1. Me dê uma mensagem de erro de verdade, não apenas um código. “Ei, você, um E40255 acabou de acontecer” – Ninguém merece!
  2. Use 410 em vez de 404 caso tenha sido deletado, bloqueado ou rejeitado. “Esse conteúdo foi removido” é mais útil do que “Hum, nada”.

Documentação

  1. Se você tem uma documentação bem escrita, poderá dizer RTFM muitas vezes.
  2. APIs versionadas são mais fáceis de manter atualizadas, porque elas não mudam (ao contrário da API do Facebook, cujos desenvolvedores podem mudá-la toda noite).
  3. Use uma ferramenta. Swagger-PHP + Swagger-UI faz esse truque.

Testes

  1. Escreva testes (Behat é ótimo para isso) e faça com que o Jenkins automatize-os;
  2. Se os testes não forem automatizados, eles podem não existir.
  3. Faça testes unitários para seus componentes, modelos e o que mais quiser.
  4. Não precisa imitar a base de dados, crie um servidor de “testes” e faça ele “sofrer”, apenas imite as chamadas externas da API do FB/Twitter/etc.
  5. TESTE PARA ENCONTRAR ERROS, não apenas sucesso. Tente e acione qualquer sistema de guarda.
  6. Se os testes não forem automatizados, eles talvez não existam. Não, nada de copiar/colar o erro.

Versione a sua API como gente grande

  1. É claro que jogar uma subpasta v1/ no seu app/controllers ou coisa do tipo parece uma forma muito esperta de fazer as coisas, mas como você vai fazer o merge dos ajustes da v1.0 na v1.1 e v2.0?
  2. Se você for usar v1, então tenha certeza de que se trata de uma base de código diferente; não faça com que um app emule todas as versões porque NÃO VAI FUNCIONAR, POR QUE VOCÊ CONTINUA TENTANDO, PARE COM ISSO!
  3. O Nginx vem com um módulo Map bastante útil, para mapear cabeçalhos Accept personalizados para uma variável.
  4. Esses cabeçalhos podem parecer com isto: application/vnd.com.example-v1.0+json. Estranho? Quem sabe.
  5. Use essa variável para mapear para um diretório diferente na configuração do seu host virtual, e cada um desses possui seu próprio branch do Git. Algo como: “set $apipath api-v$apiversion;” seguido por “root /var/www/$api_path/public;”
  6. Faça o merge das mudanças nas versões posteriores, já que muitas bases de código compartilham de um histórico comum. Não tente copiar e colar as mudanças como um idiota.
  7. Todas as regras nesta seção significam que 1.0 poderia ser PHP, 2.0 poderia ser Node (seu hipster!) e 3.0 poderia ser Scala (Eu nem…) e apenas as versões intermediárias precisam se preocupar em fazer o merge das mudanças nas versões posteriores.

Essa mensagem foi trazida até você com a ajuda de cerveja e algum whisky.

Faça suas APIs melhores, pois agora você não tem desculpa.

***

Artigo traduzido pela Redação iMasters, com autorização do autor. Publicado originalmente em http://philsturgeon.co.uk/blog/2013/07/building-a-decent-api