Consuming a RESTful Web Service in Xamarin Forms using Refit (Part 2)

In the first part of this series of articles, we talked about how to use Refit showing some examples of it’s main features. Also we did our first request.

In this part, we are going to talk about how to structure your project when using Refit, in a way that can be easier to maintain.

For this article, we are going to use some tips/code taken from Resilient network services with mobile Xamarin apps by Rob Gibbens (A must read article).

Structuring your project

Let’s start 

The first thing we are going to do is to change where we are doing our request. In the previous article of this series, just to show the concept we did the request in the view, which is completely wrong.

So, let’s change our structure a little bit:

1-Move your request call to the ViewModel

What we are going to do now is to create a new ViewModel class and associate the view to it, also to call the service we are going to use a Command.

In the end, the structure will look like this:

PDT: To handle the properties changes I’m using a package called PropertyChanged.Fody, if you want to take a look you can read this article about it https://blog.verslu.is/xamarin/keeping-dry-with-propertychanged-fody-for-xamarin-forms/

2-Create your APIService 

  • Install ModerHttpClient Package and Fusillade

ModernHttpClient helps us to do our requests faster (It is faster than HttpClient because uses platform native apis).

Fusillade helps us to handle the request prioritization.

Now we are going to create a new Folder called Services, in this folder, we are going to add an interface called IApiService and a class called ApiService

As you see uses a generic, in which one we will pass our Refit api interface type. 

3-Create your ApiManager 

In our Services folder, we are going to add another class called ApiManager and an interface IApiManager, in the first one we are going to do all the api requests implementation and we are going to use the interface to interact with it.

4-Add a generic request handler method 

  • Install the Polly Package:

Polly will help us to handle Retry, timeout, Circuit Breaker, etc.

  • In the ApiManager class add a generic method to handle all the requests:

5-Add connection handler 

For that, we are going to install the Connectivity plugin to handle the connection changes. And also we are going to use the Acr.UserDialogs plugin to show a Toast if there is no internet connection(That’s optional), but some apps like Skype, Trello likes to give that feedback to the user if the internet connection changes.

Now in our ApiManager:

6-In our Refit api interface update your response type

In the previous part, we were returning a List<MakeUps> instead of doing that we are going to return an HttpResponseMessage. Why? Because using it we can know if there was an error in the server before deserializing the JSON into an object. Also helps to show different messages according to the http response status code.

7-Add your API request definitions in your IApiManager 

In this interface, we are going to add all our request definitions.

8-Implement you IApiManager interface in your ApiManager 

9-Create a Config file

In this file we are going to have all the static values, so is easier to change in case the API URL changes or we are managing/deploying in multiple environments.

The ApiHostName property is used by the connectivity plugin to check if the URL is responding.

10-Call our API 

In the ViewModels folder we are going to add a new class called BaseViewModel which will have a method to handle request exceptions and loading.

Now in our MainPageViewModel we are going to inherit from BasePageViewModel, so we can use the RunSafe, and access to the API just using the inherited ApiManager property.

And that’s all for now, you can see the list of packages Used:

  • Acr.UserDialogs
  • Fody.PropertyChanged
  • Fusillade
  • Polly
  • ModerHttpClient
  • Plugin.Connectivity

Check the full source code here.

Happy coding!

You may also like

12 Comments

  1. Hi, I love all your tutorials, your PRISM tutorials are amazing.

    Can you write about unit testing with Xamarin or maybe something where you use PRISM and Refit with unit testing?, that will be amazing.
    And something more, why do you use share code project and not NET Standard or PCL?

    1. So glad you like it.
      Sure I will add that UnitTesting article to my ToWriteList :).
      About the Shared code, I used not for a specific reason, you can use Refit in any kind of project.

  2. Hi Charlin ,thanks alot for this guide on Refit.

    Do I need to use Lazy Initialization if I’m using Prism?

  3. Ow, great tutorial! Is it possible to cancel the API call after a certain amount of time?

  4. adding a Timeout in the ApiServices (HttpClient) didn’t work for m. Cna you explain more please

    1. mmm, it should work! Are you doing something like:

      var client = new HttpClient(messageHandler)
      {
      BaseAddress = new Uri(apiBaseAddress),
      Timeout= new TimeSpan(100)
      };

  5. Try this libraries:
    – Microsoft.Extensions.DependencyInjection
    – Microsoft.Extensions.Http
    – Microsoft.Extensions.Http.Polly

    …and part of your above solution will be on a few lines:

    TestApi.cs:

    public interface ITestApi
    {
    [Get(“/test”)]
    Task Get(string text);
    }

    App.cs:

    IServiceCollection services = new ServiceCollection();
    services.AddHttpClient(“MyApi”, c =>
    {
    c.BaseAddress = new Uri(“https://localhost:5000/api/values”);
    })
    .AddTypedClient(c => Refit.RestService.For(c))
    .AddTransientHttpErrorPolicy(p => p.WaitAndRetryAsync(
    retryCount: 2,
    sleepDurationProvider: retryAttemp =>
    TimeSpan.FromMilliseconds(Math.Pow(200, retryAttemp)))
    );

    services.AddTransient();
    var provider = services.BuildServiceProvider();

    MainPage = provider.GetService();

    In ViewModel or service layer:

    public class MyViewModel
    {
    ITestApi _api;
    public MyViewModel(ITestApi api)
    {
    _api = api;
    }

    async void SomeEvent()
    {
    var result = await _api.Get(“It works!”);
    }
    }

    😉

  6. Hello!

    you blog it’s very interesting… I have one question.

    I like the method RunSafe, for encapsulate and manage exceptions…

    I don’t understand why there is call a method Task and not void.