© Gerald Versluis 2017

Gerald Versluis, Xamarin.Forms Essentials, https://doi.org/10.1007/978-1-4842-3240-8_7

7. Connecting to a REST Backend

Gerald Versluis

(1)Sittard, The Netherlands

Now that you have seen how the app works in an architectural sense and learned how to build screens, it is time to retrieve some actual data.

I don’t have any numbers or study to back this up, but I dare to make the claim that the percentage of apps that retrieve or send some kind of data to or from a backend service is very close to a hundred.

This chapter looks at various ways to communicate with the backend. It focuses on REST (Representational State Transfer) backends, which are popular because they use common HTTP for communication principles. In the first part, I show you how to make requests to an API backend manually. By this, I mean writing the full code for each request.

From there, we look at the Refit library. This library helps you write less repetitive code when creating requests to a backend by generating the code for you.

In the last part of this chapter, you learn about using third-party libraries that take care of the communication for you. This is the way the “been pwned” app was implemented.

Since this book focuses on the Xamarin.Forms app, I assume that you have some basic knowledge on REST API backends and how they work in general. If you do not, I recommend reading background information about REST APIs, idempotence, and the working of HTTP and HTTP verbs.

The Manual Way

To get the best understanding of how stuff in general works, I like to start off manually. This way, you will learn the most. Also, when you start looking at other libraries to take some repetitive code out of your hands, you will know what happens in the library and understand any errors you encounter. It will also help you appreciate the library and the authors if you know what they do for you.

As mentioned earlier, I like to name classes that provide data services, and it will be no surprise that I put them in the Services folder of the shared project. Because I use a third-party library for the “been pwned” app, code in this example won’t be found in the actual project.

The first thing you need to do is identify all the endpoints that you want to communicate with. If you wrote the backend yourself, the endpoints should be familiar. If someone else provided the backend, there is probably some documentation for it somewhere that identifies the endpoints. The most common ones will use the GET and POST HTTP verbs to retrieve and send data, respectively. The documentation of the haveibeenpwned.com API can be found at https://haveibeenpwned.com/API/ . Because most calls will roughly look the same, I walk you through one or two. The basic layout of my service class can be seen in Listing 7-1.

Listing 7-1 Outline of the Class That Will Act As a Service to Get Data from the haveibeenpwned.com API
public class BeenPwnedService
{
        public BeenPwnedService()
        {
        // TODO       
        }


        public async Task<IEnumerable<object>> GetBreaches()
        {
        // TODO
        }


        public async Task PostBreach(object breach)
        {
          // TODO
        }
}

There is nothing very complicated about it. There will be a constructor to instantiate the HttpClient, which will handle the communication. Furthermore, I show you two methods to retrieve data and send data. Note that there is no endpoint on the HIBP API that accepts POST requests, so I make one up for this. The actual code for this will not work.

First let’s see how to set up the HttpClien t. In the class, I’ve created a private field to hold the client. It is very likely that there will be multiple calls toward the API, so to avoid any overhead on creating the client for every request, the class will keep an instance for us. Look at Listing 7-2 for the private field and the implementation of the constructor code.

Listing 7-2 Implementation of the HttpClient
private readonly HttpClient _httpClient;

public BeenPwnedService()
{
    _httpClient = new HttpClient
    {
        BaseAddress = new Uri("https://haveibeenpwned.com/api/v2/")
    };


    _httpClient.DefaultRequestHeaders.UserAgent.Clear();
    _httpClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("Test", "1"));
}

In the constructor of this service, there is code to create a new instance of the HttpClient. We provide this client with the BaseAddress property . This address is used for every request that is made through the client. At the end, you can see it says v2. This is to identify that we are using version 2 of the API endpoints. This is known as versioning. The idea is that whenever you release a final version of an endpoint at the API side, you freeze that code—or better—you freeze the contract.

To communicate with a certain endpoint, you need to send a request that is understood by the API and it will send you a response in a certain format in return. This is the contract. Whenever something is about to change in either the parameters that you need to send with the request or in the data you can receive back, it is a good practice to create a new version. This way, old applications that call upon the v2 endpoint keep working and have time to switch over to the new version.

As you can see, there are two more lines. These are needed to identify the app to the HIBP API. Troy Hunt implemented this as a way of logging and security, probably. The API must send a user-agent identifier with each request. Failing to do so will result in an error.

This is a very simple form of security, but you can imagine that almost every API has some form limiting access. There can be many variations on this, so it’s impossible to describe all of them. Most of them require you to provide some kind of token or other credential with each request; in this case, it’s the user-agent HTTP header.

Now that the HttpClient is ready to send requests, let’s see how to do this. Listing 7-3 implements the call to retrieve all breaches from the system.

Listing 7-3 Implementation of the Get Breaches Method
public async Task<IEnumerable<object>> GetBreaches()
{
    var response = await _httpClient.GetStringAsync("breaches");


    return JsonConvert.DeserializeObject<IEnumerable<object>>(response);
}

First, we simply retrieve the string contents of the API response. By simply calling the _httpClient.GetStringAsync("breaches") line , we will invoke a GET request to https://haveibeenpwned.com/api/v2/breaches . Because we gave the HttpClient a base address already, we now only need to specify the endpoint, which is breaches.

The result of this call will be all breaches in the HIBP database in JavaScript Object Notation (JSON) format . JSON is a very popular format to describe data structures. It is similar to XML, but much more lightweight. A sample of the HIBP JSON response object is shown in Listing 7-4.

Listing 7-4 Sample JSON Response from the HIBP API, Showing One Record
 [{"Title":"000webhost","Name":"000webhost","Domain":"000webhost.com","BreachDate":"2015-03-01","AddedDate":"2015-10-26T23:35:45Z","ModifiedDate":"2015-10-26T23:35:45Z","PwnCount":13545468,"Description":"In approximately March 2015, the free web hosting provider <a href="http://www.troyhunt.com/2015/10/breaches-traders-plain-text-passwords.html" target="_blank" rel="noopener">000webhost suffered a major data breach</a> that exposed over 13 million customer records. The data was sold and traded before 000webhost was alerted in October. The breach included names, email addresses and plain text passwords.","DataClasses":["Email addresses","IP addresses","Names","Passwords"],"IsVerified":true,"IsFabricated":false,"IsSensitive":false,"IsActive":true,"IsRetired":false,"IsSpamList":false,"LogoType":"png"}]

This JSON object shows a collection of breach records, showing one record for this example. A collection is denoted by the square brackets. One object instance is indicated by the curly brackets. Inside the curly brackets, you can then basically see key-value pairs, separated by a colon. The string before the colon is the name of the property and the value after the colon is the value of that property. The type of the property is inferred by its value. For example, the Title property has a value surrounded by quotes, so that is a string. When we look at the AddedDate, we also see a string, but this will be parsed as a DateTime because of its value. And later on, there is also the IsVerified property , which has a boolean value.

A property in itself can also have a collection and/or object. This way, you can transfer complex objects to a string and then serialize and deserialize them. There is a very good library for this, namely Json.NET. This library is used in the second line of the GET method in Listing 7-3. With this library, we deserialize the retrieved JSON content and return it as a string of objects. In real code, we would’ve implemented a model that holds all the properties for us; for now, I just deserialize it to a generic object. More on the Json.NET library in Chapter 8.

The final method of our service is shown in Listing 7-5.

Listing 7-5 Implementation of the Post Request to the API
public async Task PostBreach(object breach)
{
    var jsonObject = JsonConvert.SerializeObject(breach);


    await _httpClient.PostAsync("breaches",
        new StringContent(jsonObject, Encoding.UTF8, "application/json"));
}

As I mentioned, this endpoint is made up by me, so this will not actually work since the HIBP API does not provide any POST endpoints. But let’s pretend there is such an endpoint and that it lets us send a breach object back to the API, which is then saved in the database. What we see happening is actually the exact way around as with the GET method . We now take in the breach object, serialize it into a JSON string, and then send it to the API using the line await _httpClient.PostAsync("breaches", new StringContent(jsonObject, Encoding.UTF8, "application/json")); line.

You see how the word GET was replaced with POST in the method that we call. Yet the endpoint name is still breaches. This works because now we do not call the endpoint with the GET verb, but with the POST verb. That is one way to distinguish between different operations on the same endpoint. Another way is to just name them different. But the most common way is to group your endpoints by a certain operation or entity and then use GET to retrieve one or more of those objects, POST to insert one, PUT to update, etc. There are various ways to solve these problems for all kinds of different requirements.

Because we posted something now, we need to send some content for the API to save. We will send the serialized object as a StringContent object. With this object, we can specify the encoding of the string and, just as important, the media-type, also known as the Multipurpose Internet Mail Extensions (MIME) type . The MIME type specifies what type of content the string holds. This can for instance be text/html to indicate that the string holds HTML content. For JSON, this is application/json. To learn more about different types, look at the Wikipedia page at https://en.wikipedia.org/wiki/Media_type .

If this code was to be used in a real-life scenario, there are some improvements that would need to be made, so don’t just copy and paste it. Try to understand what it does. That way, you can improve the code and keep it performant and secure. Improvements you could try include error handling to see if a request succeeded, disposing the HttpClient to free up memory, and more.

The Refit Way

In the previous part of this chapter, you saw how to implement calls to the backend. While this works perfectly, a lot of code will be repeated. We have to (de)serialize the object every time and send it through a GET or POST method . If there is one thing we do not like as developers, it’s repeated code. A package that can help you with this is Refit, by Paul Betts.

By using this library, you can omit all the implantation code, as it will be generated at compile-time by Refit. The only thing you have to do is define an interface with the signatures of the endpoints that you want to communicate with. Then all these methods will be adorned with attributes to specify some metadata, like if the call is a POST of a GET and what the URL is. Let’s look at how this works if we wanted to transform our manual class from the previous part into a Refit solution.

Start by installing the Refit NuGet package into the shared project and also the platform projects. We can then simply define an interface like in Listing 7-6.

Listing 7-6 Interface for Our API Calls
[Headers("Accent: application/json")]
public interface IBeenPwnedService
{
    [Get("/breaches")]
    Task<IEnumerable<object>> GetBreaches();


    [Post("/breaches")]
    Task PostBreach(object breach);
}

If you look closely, you will notice that I used the method names from our initial class in the previous part of this chapter. But now, we only have to declare these method signatures. By putting the GET and POST attributes above them, Refit will figure out if it should be a GET or POST request. As a parameter to these attributes, we provide the endpoint name. There is also a Headers attribute above the interface definition. That way, you can send headers with each request that is made. You can also move the Header attribute to one method; it will only be sent with that one method.

Note that all methods must return a Task, since they will be implemented asynchronously. Also, make sure that the endpoints start with a forward slash, or it will result in a runtime error.

For all options that are available—and there are quite a lot—you can check out the projects GitHub page at https://github.com/paulcbetts/refit . One that I would like to mention is how to incorporate dynamic parameters directly into your endpoint URL. It is not uncommon to retrieve a certain object by its ID. An endpoint could then look like this: https://haveibeenpwned.com/api/v2/breachedaccount/my-username . Because we now define the endpoints with an attribute, we cannot simply add values to it. This has been accounted for in Refit. When you define the endpoint in the attribute like this:

[Post("/breachedaccount/{account}")]
Task<object> GetBreachesForAccount(string account);

It will automatically insert the value of the account parameter into the endpoint by matching the parameter name; no code required. Pretty awesome, right?

Since we can’t call on an interface directly and we do need a little bit of configuration, we do need some sort of client to execute these requests. This client can be seen in Listing 7-7.

Listing 7-7 Implementation of the New Service Class
public class BeenPwnedService
{
    private readonly IBeenPwnedService _beenpwnedClient;


    public BeenPwnedService()
    {
        var httpClient = new HttpClient
        {
            BaseAddress = new Uri("https://haveibeenpwned.com/api/v2/")
        };


        _beenpwnedClient = RestService.For<IBeenPwnedService>(httpClient);
    }


    public async Task<IEnumerable<object>> GetBreaches()
    {
        return await _beenpwnedClient.GetBreaches();
    }


    public async Task PostBreach(object breach)
    {
        await _beenpwnedClient.PostBreach(breach);
    }
}

The only thing that remains of the original are some wrapper methods around the interface. To let Refit generate a class for you, you can simply call RestService.For<IBeenPwnedService>(httpClient) ;. You can see that we still need to provide for the HttpClient. This is actually to our advantage, as we could choose another transportation stack if we wanted to.

In earlier versions of Xamarin.Forms, the HttpClient implementation of .NET was used. While this supported the most features, it was not the fastest option. Back then, you had to implement your own message handler to leverage the native HTTP stacks on iOS and Android, which were much faster. This is the default setting in Xamarin.Forms. Normally, you would not have to worry about this. Because we set the HttpClient here, you could also implement your required security headers in here.

Then, as you can see, we simply pass along the interface methods calls through here. If you wanted to, you could do some translation or other logic like error handling before you send it back to your business logic.

Now you can just instantiate the BeenPwnedService class as you did before and call on it. This saves a lot of repetitive code! It’s good to know that when Refit receives an HTTP response that’s not an OK status code, it will throw an exception. So you need to account for that.

The Third-Party Way

When you didn’t build the backend you’re communicating with, chances are good that the author or another third-party author developed a library. This is sort of true for communication with haveibeenpwned.com. There is a library available for it, but I wrote it myself in anticipation of rebuilding the “been pwned” app. This way, other developers might find it easier to incorporate functionality in their applications as well. For the sake of this example, we will treat this library as if it were built by someone else and we want to use it in our app.

To find a library, you can either look at the associated web site or search for it on Google, GitHub, or NuGet. Whenever you find one that suits your needs, you can install it into your app through NuGet. Chances are good that the library is open-source and the source is available online for you to see. (Or at least there should be some documentation on how to get started.) The code for the BeenPwned.Api library can be found on GitHub at https://github.com/jfversluis/BeenPwned.Api/ . To install it, simply find it on NuGet.

After installation, you simply create the service class again and call the methods in the installed third-party library.

The example in the “been pwned” app can be seen in Listing 7-8. This example has been simplified a bit from the actual code at https://github.com/jfversluis/been-pwned/blob/master/src/BeenPwnedApp/Core/Services/BeenPwnedService.cs because the production version implements some error handling and caching.

Listing 7-8 Implementation of the Third-Party Communication Service
public class BeenPwnedService
{
    private IBeenPwnedClient _pwnedClient = new BeenPwnedClient($"BeenPwned-{Device.RuntimePlatform}");


    public IObservable<IEnumerable<Breach>> GetAllBreaches(bool force = false)
    {
        return await _pwnedClient.GetAllBreaches();
    }


    public async Task<IEnumerable<Breach>> GetBreachesForAccount(string account, string domain = "", bool includeUnverified = false)
    {
        return await _pwnedClient.GetBreachesForAccount(account, domain, false, includeUnverified);
    }


    public async Task<bool> GetIsPasswordPwned(string password)
    {
        return await _pwnedClient.GetPwnedPassword(password);
    }


    public async Task<IEnumerable<Paste>> GetPastesForAccount(string account)
    {
        return await _pwnedClient.GetPastesForAccount(account);
    }
}

In the private field, you see how a new client is instantiated with a parameter that will be used as the user-agent header. All the code for the endpoints, setting the user-agent, and using the HttpClient is now abstracted into the NuGet package.

The rest of the calls are calling on the third-party library and wrapping it in our own logic where needed.

Summary

There are of course more ways to connect to a backend than are described in this chapter. For one, not all services will be REST (although most modern backends will likely be). One question that I hear sometimes is how to connect to a PHP or Node.js backend. If those services work the REST way and communicate through the HTTP protocol, there is no reason that the code in this chapter will not work. In fact, I don’t even know in what language and what technique the haveibeenpwned.com API is built, and I don’t have to!

This chapter showed you how to communicate with a backend service, based on the REST principles. It showed you how to implement all the calls by hand, so you will have a better understanding of how the communication works in detail.

From there, we looked at how the Refit library can help you reduce the amount of code needed for communication. This helps you achieve better maintainability and just to have more time for coffee. I didn’t even mention this yet, but the great thing is that Refit can be used in other projects than just Xamarin apps! You can use it in most of your .NET-based projects.

Finally, you learned how to work with a third-party library. This is the simplest way of connecting to a backend. You typically drop in the library and call the right methods.

This chapter concludes most of the actual development. With everything you have learned up until now, you should be able to build a Xamarin.Forms app that gets data from an external source. Of course, there are more challenges to overcome, but you’re well on your way.

The next chapter looks at other libraries, just as awesome as Refit, that are used in most of my apps. By studying these libraries, you will know what is out there, so you don’t have to reinvent the wheel. This will help clarify some of the more important concepts of mobile development.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.159.152