Publicidade descarada: trabalho na WI (http://wi.co/). Estamos a mudar a forma como as pessoas fora do Vale do Silício trabalham. Se estiveres interessado, dá uma vista de olhos na nossa página de carreiras (http://wi.co/careers) ou envie-me um e-mail para [email protected]
Sobre o Thrift: Se ainda não estiver familiarizado com o RPC ou com o Thrift, talvez queira dar uma vista de olhos em https://thrift.apache.org/
Então, um problema de que já ouvi falar é: «Olha, estamos a disponibilizar as nossas APIs do Thrift a fornecedores externos e precisamos que sejam fáceis de utilizar.» Ora, as opções são as seguintes:
- Divulgue os pontos de extremidade do Thrift, oriente os utilizadores da sua API sobre o Thrift e ajude-os a resolver quaisquer problemas.
- Deve manter uma biblioteca que funcione como um wrapper em torno dos diferentes serviços Thrift para cada linguagem/plataforma que pretenda suportar.
- Criar uma forma de converter manualmente entre JSON legível por humanos para Thrift e vice-versa, e mantê-la para cada estrutura, serviço e função.
Se estas opções não te parecem atraentes, tens razão — podem dar muito trabalho. Mas será que há outra forma?
Vou utilizar o seguinte ficheiro Thrift simples no meu artigo abaixo:
Atualmente, o Thrift suporta um JSONProtocol que transmite dados em formato JSON entre o cliente e o servidor (é isso que utilizamos para a nossa interface web). No entanto, basta dar uma olhadela aos dados que estão a ser enviados para perceber que não será possível disponibilizá-los a terceiros:
E isto serve para uma chamada muito simples : login(e-mail, palavra-passe).
O JSON do Thrift utiliza uma série de termos técnicos para analisar a chamada exata, tais como os tipos de cada argumento/campo, o comprimento de matrizes/conjuntos, o número-chave de cada campo numa estrutura, etc.
Por isso, criámos uma forma de converter JSON legível para o Thrift sem:
- Adicionar um monte de jargão
- A realizar qualquer tipo de manutenção. Quaisquer alterações às definições do Thrift deverão ficar automaticamente disponíveis.
Um exemplo da mesma chamada utilizando o novo método:
Fica muito mais fácil de ler!
O formato é simples. Os valores da chave «method» devem corresponder exatamente ao nome do método na definição Thrift. O objeto «arguments» é a lista de argumentos. As chaves dentro do objeto «arguments» correspondem, mais uma vez, aos nomes dos parâmetros da função na definição Thrift.
Eis um exemplo de resposta:
Um exemplo de uma exceção definida pela API que foi lançada:
Note-se que também consegue lidar facilmente com estruturas (e estruturas aninhadas dentro de outras estruturas). Acima, `currentUser` é uma estrutura. Em JSON, trata-se simplesmente de um objeto JSON cujas chaves são idênticas aos nomes dos campos na definição da estrutura Thrift.
Além disso, o err (a exceção) acima também é uma Struct, uma vez que, no Thrift, as exceções são simplesmente um tipo especial de structs.
Furthermore, note that the success object itself is a struct. Its is an auto generated struct whose name is usually <MethodName>_result (in this case login_result). You can see it if you ever peek into the generated code for any other language. It has two fields: result for a successful call and err for any api defined error that was thrown.
Similarly, the arguments is also an auto generated Struct, usually call <MethodName>_args (in this case login_args). Its fields are simply the function arguments. Thus, this format follows very closely to how actual Thrift works.
Existe um gerador de JSON para o Thrift, que gera todos os metadados do
- Serviços: nome, lista de funções
- Funções: nome, lista de argumentos
- Estruturas: nome, campos, juntamente com os seus nomes e tipos
Segue-se um exemplo dos metadados gerados para o ficheiro Thrift acima referido.
Utilizei estes metadados num novo Protocolo. Um Protocolo é a forma como o Thrift marshala e desmarshala dados. O problema é que os Protocolos no Thrift são fortemente tipados. É necessário que consigam transmitir o tipo exato do campo (ou o tipo de elemento da matriz, ou o tipo de chave e valor do mapa) e outros detalhes, como o tamanho do mapa ou da matriz. É por isso que o JSONProtocol do Thrift contém tanta terminologia técnica. Ele transporta exatamente esta informação.
Este novo protocolo, o HumanReadableJsonProtocol, utiliza o JSON que o cliente envia juntamente com os metadados do gerador de JSON do Thrift para determinar exatamente qual a função que foi chamada, quais os argumentos que foram enviados e quais são os seus tipos exatos.
Por exemplo, na chamada acima, irá primeiro procurar os metadados relativos ao método de início de sessão. Em seguida, para cada chave dentro do objeto «arguments»no JSON do cliente, irá localizar a chave associada na matriz «arguments» dos metadados. Dependendo do tipo, irá analisá-la (se for uma estrutura, uma lista ou um mapa, continuará a recursão até chegar a um tipo base — int, string, boolean, double, etc.). Por exemplo, neste caso, irá procurar um objeto cujovalor de «name» seja«email» nos metadados, verificar que tem o tipo String e, em seguida, confirmar que o valor de«email» no objeto «arguments» do JSON do cliente também é um String. O mesmo se aplica a«password».
Este novo HumanReadableJsonProtocol continua a ser fortemente tipado. Se enviar uma chave cujo valor não corresponda corretamente ao tipo definido nos metadados, será gerado um erro.
Eis um erro que surge num caso como este, em que tentei introduzir um número em vez de uma cadeia de caracteres no campo da palavra-passe:
Note-se que este JSON tem uma chave «exception», enquanto os anteriores tinham uma chave «result» seguida de «success» ou «error». Isto é semelhante à forma como o Thrift trata os diferentes tipos de resposta. Recebe-se um «Result» ou uma «Exception». «Result» significa que a chamada foi bem-sucedida e que não foram lançados erros para além dos erros definidos pela API (os que constam na assinatura do método). Assim, «Result» tem dois campos: um para «success», que contém o resultado bem-sucedido da chamada, e outro para «error», que contém o erro definido pela API que foi lançado. «Exception» contém qualquer outro erro (incluindo erros do Thrift, como dados corrompidos, impossibilidade de analisar dados, tipos errados, etc.).
Uma vez que se trata apenas de um protocolo (forma de marshalizar/desmarshalizar dados), o código gerado pelo Thrift que o utiliza tratará automaticamente de aspetos como campos obrigatórios ou opcionais.
Assim, por exemplo, se o pedido tiver um tipo de conteúdo «application/json», basta utilizar o HumanReadableJsonProtocol para o analisar; caso contrário, utilize o protocolo padrão que costuma utilizar. Terá também de indicar o diretório onde se encontram os metadados JSON gerados.
Por fim, aplica automaticamente quaisquer novas alterações às definições do Thrift (desde que também gere o JSON utilizando o gerador de JSON).
Aqui está o código-fonte do projeto: HumanReadableJsonProtocol
Se quiser obter o código para isto ou se quiser ajudar a expandi-lo para mais idiomas e a escrever testes para o mesmo, por favor, contacte-me.
Excerto do HumanReadableJsonProtocol em Ruby
Aqui está um excerto do código que realiza a análise em Ruby:
Mais uma vez, vou fazer um pouco de autopromoção: trabalho na WI (http://wi.co/). Estamos a mudar a forma como as pessoas fora do Vale do Silício trabalham. Se estiveres interessado, dá uma vista de olhos na nossa página de oportunidades de emprego (http://wi.co/careers) ou envia-me um e-mail para [email protected]











