apis e restease capa post

APIs e RestEase: Defina clientes REST em .NET do jeito fácil

Acessar APIs é uma parte importante da construção de software, seja para integrar com parceiros externos ou clientes, seja para comunicar com micro serviços internos.

O meio mais comum de expor APIs atualmente é através de serviços HTTP, geralmente usando JSON no corpo das requisições e respostas. E a forma mais comum de implementar clientes para estas APIs em .NET tem sido através do uso do HttpClient, para encapsular o protocolo HTTP, e do Newtonsoft Json.NET, para a serialização/desserialização de JSON.

Mas já reparou como o código destes clientes é repetitivo? A tarefa básica é sempre a mesma: disparar uma chamada serializando um objeto que representa a requisição, avaliar o retorno HTTP e desserializar a resposta para um outro objeto. Por mais que seja simples e rápido, há gasto de tempo e, ainda, código adicional para ser mantido.

A biblioteca RestEase (inspirada na biblioteca Refit, baseada no Roslyn, que por sua vez foi inspirada na Retrofit, disponível para Java/Android) é uma excelente alternativa para tornar o acesso a estas APIs ainda mais simples e rápido, com pouquíssimo código a ser mantido.

Com RestEase, um cliente é definido simplesmente pela declaração de uma interface decorada com atributos que descrevem como os parâmetros dos métodos serão incorporados à requisição HTTP. A implementação gerada pela biblioteca utiliza nossos conhecidos HttpClient e Json.NET, possuindo vários pontos de extensão para customizações em diversos cenários comuns.

Vou mostrar como ela funciona através de exemplos:

1. API Github

Vamos criar um cliente para acessar uma funcionalidade simples da API pública do Github: recuperar os detalhes de um usuário. Para isso, basta fazer uma requisição GET no endpoint:

https://api.github.com/users/<username>

Podemos definir a seguinte interface para esta chamada:

public interface IGithubClient
{
    [Get("users/{username}")]
    Task<GithubUser> GetUserAsync(
[Path("username")] string username, 
CancellationToken cancellationtoken);
}

Adicionamos o atributo Get do RestEase ao método GetUserAsync para indicar o verbo e o caminho do endpoint HTTP que será usado por esse método.

Como esse endpoint recebe o parâmetro do nome do usuário no próprio caminho, isto é indicado através da marcação {username} na string do atributo Get, e na assinatura do método marcamos com o atributo Path qual parâmetro deverá ser utilizado para preencher este valor na chamada.

Obs: o atributo Path pode ser declarado sem a string adicional no construtor quando o nome do parâmetro marcado com o atributo é igual à marcação na string do atributo Get. Mas é interessante sempre declarar explicitamente, para evitar que uma eventual renomeação do parâmetro por um programador desavisado “quebre” o funcionamento do cliente.

A classe GithubUser precisará ser definida para receber a resposta desserializada da requisição. Uma maneira rápida de fazer isso automaticamente é através do site Quicktype: basta incluir um exemplo de um JSON que ele produzirá a classe C# correspondente, seguindo as convenções de nomeação de propriedades e os respectivos atributos Json.NET para desserialização.

A figura abaixo (clique para aumentar) mostra o resultado, usando como exemplo o username takenet.

O RestEase suporta, ainda, que o retorno do método seja uma string (retornará o corpo da resposta), um HttpResponseMessage (utilizado pelo HttpClient), entre outros, para facilitar qualquer necessidade de processamento sobre o retorno.

Como a API do Github exige que o cabeçalho HTTP User-Agent seja enviado, é preciso adicionar mais um atributo para que a interface funcione sem erros:

[Header("User-Agent", "RestEase Sample")]
public interface IGithubClient
{
    [Get("users/{username}")]
    Task<GithubUser> GetUserAsync(
[Path("username")] string username, 
CancellationToken cancellationtoken);
}

O atributo Header pode ser adicionado também em métodos, para especificar que aquela chamada específica deverá ter um cabeçalho HTTP, ou ainda decorando um parâmetro de um método, quando cada chamada puder ter um valor diferente no cabeçalho.

Definida a interface, basta criar uma instância passando a URL base para obter o cliente pronto para uso:

var githubClient = RestClient.For<IGithubClient>("https://api.github.com");
var user = await githubClient.GetUserAsync("takenet", CancellationToken.None);

Fácil, não?

2. API Facebook Messenger

Vamos ver como seria o uso do RestEase com a API  de envio de mensagens do Facebook Messenger. O endpoint para isto é:

https://graph.facebook.com/v2.6/me/messages?access_token=<PAGE_ACCESS_TOKEN>

Obs: a plataforma do Messenger suporta o envio de vários tipos de conteúdos, mas para simplificar, vamos enviar um texto simples.

Deve ser enviada uma requisição usando o método HTTP POST, enviando no corpo um JSON com as informações para envio. Usando novamente o Quicktype e o exemplo do JSON na documentação, criamos a classe MessengerRequest conforme a figura abaixo:

Veja que o Quicktype consegue detectar que algumas propriedades também são objetos e gerar as devidas classes recursivamente.

A resposta do envio é um JSON, para o qual também geramos a classe MessengerResponse no Quicktype, mostrada na figura abaixo:

Agora, definimos a interface que será usada pelo RestEase:

public interface IMessengerSender
{
    [Post("me/messages")]
    Task<MessengerResponse> SendMessageAsync(
        [Body] MessengerRequest request,
        [Query("access_token}")] string accessToken,
        CancellationToken cancellationToken);
}

Da mesma forma que o exemplo anterior, o atributo Post indica o verbo e o caminho do endpoint HTTP que serão usados nesta requisição.

O atributo Body indica que o parâmetro request será usado como corpo da requisição. Nesse caso, o tratamento padrão do RestEase é serializar classes como um JSON, adicionando inclusive o cabeçalho Content-Type: application/json na requisição. Existem, ainda, outras formas de definir o envio do conteúdo.

O atributo Query indica que o valor do segundo parâmetro será adicionado na query string da URL da requisição, usando como chave o valor access_token.

Obs: Por padrão, RestEase adiciona qualquer parâmetro não decorado com atributos à query string e utiliza como chave o próprio nome da variável no método. Mas aqui, novamente é melhor definir explicitamente o atributo com o valor da chave, tanto para manter a convenção de nomes do C# como para evitar que renomeações “quebrem” o funcionamento do cliente.

Pronto, basta criar o cliente passando novamente a URL base para começar a usar:

var messengerSender = RestClient.For<IMessengerSender>("https://graph.facebook.com/v2.6");
var response = await messengerSender.SendMessageAsync(
    new MessengerRequest
    {
        MessagingType = "UPDATE",
        Recipient = new Recipient { Id = "xxxxxxxxxx" },
        Message = new Message { Text = "Hello!" }
    },
    "<access token>",
    CancellationToken.None);

RestEase é extremamente conveniente e configurável. Além das funcionalidades básicas que demonstrei, existem vários pontos de extensão, incluindo a definição de sua própria instância do HttpClient (que por si só é configurável via MessageHandlers) e o controle de serialização/desserialização (suportanto inclusive XML).

Na próxima vez que precisar criar um cliente para uma API HTTP, experimente esta biblioteca e tenha mais tempo para implementar o que realmente traz valor para seu produto ou projeto.

* Todo o código deste artigo está disponível no Github.


minelli post apis e RestEase
  • Facebook
  • Twitter
  • Google+
  • LinkedIn

André Minelli

Developer e Líder Técnico na Take

LinkedIn

 

 

 

 

 

 

 

 

Leia mais:

11 bibliotecas essenciais para Android

Performance no front-end: Faça sua aplicação web voar

Seu bot não deve se resumir a uma linha de comandos

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Share This