Xamarin Forms - Usando Refit para acessar APIs Restfull  

Hoje vou apresentar o Refit um pacote Nuget que promete simplificar o código que você tem que escrever para acessar uma API REST.

Como atualmente o acesso e o consumo de APIs REST é muito comum, nada melhor do que uma opção para evitar ter que repetir todo o código que precisamos escrever para realizar tal acesso.

A maneira tradicional de acesso para consumir APIs REST em aplicações Xamarin Forms é usar os recursos da classe HttpClient.

A biblioteca Refit é open source e foi criada por Paul Betts

Você pode verificar o código fonte completo aqui: https://github.com/paulcbetts/refit.

Um dos motivos que o faria usar o Refit é que ele é simples, com um código limpo, fácil de entender e manter.

Neste artigo vamos criar uma aplicação Xamarin Forms e consumir uma API REST disponbilizada de forma gratuita pelo JSONPlaceholder que retorna dados de post no formato JSON abaixo:

Para converter o formato JSON retornado para um objeto .NET podemos usa o serviço disponibilizado no site http://json2csharp.com/

Copiamos o retorno JSON da API e ao clicar no botão Generate temos o objeto .NET que eu vou chamar de User que será definida assim :

 public class User
 {
        public int UserId { get; set; }
        public int Id { get; set; }
        public string Title { get; set; }
        public string Body { get; set; }
 }

Isso posto vamos usar o Refit para consumir esse serviço REST.

Recursos usados:

Criando o projeto Xamarin Forms

Abra o  VS 2017 Community e clique em New Project e a seguir escolha Cross Platform -> Mobile App (Xamarin.Forms) e informe o nome XF_RestAPI;

A seguir selecione a Plataforma (eu marquei somente Android) e escolha a estratégia de compartilhamento que será .NET Standard.

Clique no botão OK.

Pronto, nosso projeto já esta criado.

Aqui aceitamos a definição padrão que indica a página MainPage como a página que vai iniciar a nossa aplicação.

Vamos criar duas pastas no projeto compartilhado:

Incluindo o pacote Refit no projeto

No menu Tools clique em Nuget Package Manager e a seguir em Manage Nuget Packages for Solution;

Na guia Browse digite Refit e localize e instale o pacote em todos os projetos:

Definindo o modelo de domínio

Vamos definir um modelo de domínio criando uma pasta Models no projeto compartilhado a classe User abaixo que representa o retorno da API Rest:

 public class User
 {
        public int UserId { get; set; }
        public int Id { get; set; }
        public string Title { get; set; }
        public string Body { get; set; }
 }

Usando o Refit

Para usar o Refit temos que criar uma interface na pasta Services com as chamadas para a nossa API REST.

Atente que nossa API possui apenas os métodos para retornar todos os posts e para retornar um post pelo seu id.

Assim vamos criar uma classe chamada IRestClientAPI com o código abaixo:

using Refit;
using System.Collections.Generic;
using System.Threading.Tasks;
using XF_RestAPI.Models;

namespace XF_RestAPI.Services
{
    public interface IRestClientAPI
    {
        [Get("/posts")]
        Task<ICollection<User>> GetAll();

        [Get("/posts/{id}")]
        Task<User> GetAll(int id);

        //[Post("/posts")]
        //Task AddPost(User post);

    }
}

Nos métodos definidos temos o tipo de request GET , o tipo de retorno Task<User> e Task<ICollection<User>> e a uri relativa /posts e /posts/id. (não existe um método POST)

A seguir vamos criar uma classe chamada RestClientAPI na pasta Services que implementa esta interface:

using Refit;
using System.Collections.Generic;
using System.Threading.Tasks;
using XF_RestAPI.Models;

namespace XF_RestAPI.Services
{
    public class RestClientAPI : IRestClientAPI
    {
        private readonly IRestClientAPI _restClient;

        public RestClientAPI()
        {
            _restClient = RestService.For<IRestClientAPI>(RestEndPoints.BaseUrl);
        }

        public async Task<ICollection<User>> GetAll()
        {
            return await _restClient.GetAll();
        }

        public async Task<User> GetAll(int id)
        {
            return await _restClient.GetAll(id);
        }
    }
}

Além disso vamos criar a classe RestEndPoints com um método estático que retorna a URI de acesso ao serviço REST :

    public class RestEndPoints
    {
        public static string BaseUrl => "https://jsonplaceholder.typicode.com";
    }

Criando a view para exibir informações da API

Abra o arquivo MainPage.xaml e defina o código abaixo que vai exibir os dados retornados pela API:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:XF_RestAPI"
             x:Class="XF_RestAPI.MainPage">

    <ListView x:Name="lv2" HasUnevenRows="True" IsPullToRefreshEnabled="True"
              ItemsSource="{Binding Users}">

        <ListView.ItemTemplate>
            <DataTemplate>

                <ViewCell>
                    <StackLayout Orientation="Horizontal">
                        <Label Text="{Binding UserId}" />
                        <StackLayout HorizontalOptions="StartAndExpand">
                            <Label Text="{Binding Title}" TextColor="Black"/>
                            <Label Text="{Binding Body}" TextColor="Gray"/>

                        </StackLayout>
                    </StackLayout>
                </ViewCell>

            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

</ContentPage>

Criando a viewmodel MainPageViewModel

Vamos criar a nossa viewmodel chamada MainPageViewModel onde vamos definir a lógica da nossa View e implementar a interface INotifyPropertyChanged para notificar a View das alterações ocorridas nos dados:

using Refit;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using XF_RestAPI.Models;
using XF_RestAPI.Services;

namespace XF_RestAPI
{
    public class MainPageViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
        {
            if (EqualityComparer<T>.Default.Equals(storage, value))
            {
                return false;
            }

            storage = value;
            OnPropertyChanged(propertyName);
            return true;
        }

        public ObservableCollection<User> Users { get; }
        public MainPageViewModel ()
        {
            Users = new ObservableCollection<User>();
            LoadUsers().GetAwaiter();
        }

        private async Task LoadUsers(List<User> lista = null)
        {
            Users.Clear();

            var userAPI = RestService.For<IRestClientAPI>(RestEndPoints.BaseUrl);
            var result = await userAPI.GetAll();

            foreach (var user in result)
            {
                Users.Add(user);
            }
        }
    }
}

Note que no método LoadUsers() estamos usando o método  RestService.For<IRestClientAPI>(RestEndPoints.BaseUrl); para mapear o método que desejamos usar e a seguir chamamos o método GetAll() para obter todos os dados.

No arquivo MainPage.xaml.cs vamos definir o código para definir o BindingContext usando o construtor da viewmodel MainPageViewMode:

using Xamarin.Forms;

namespace XF_RestAPI
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
            BindingContext = new MainPageViewModel();
        }
    }
}

Executando o projeto iremos obter o resultado a seguir:

Para saber mais detalhes da implementação acesse a documentação em : https://github.com/reactiveui/refit

Pegue o projeto compartilhado aqui: XF_RestAPI.zip

"Palavra fiel é esta: que, se morrermos com ele, também com ele viveremos;
Se sofrermos, também com ele reinaremos; se o negarmos, também ele nos negará;
Se formos infiéis, ele permanece fiel; não pode negar-se a si mesmo."
2 Timóteo 2:11-13

Referências:


José Carlos Macoratti