Consume a REST-based web service

Browse sample. Browse the sample

Representational State Transfer (REST) is an architectural style for building web services. REST requests are typically made over HTTPS using the same HTTP verbs that web browsers use to retrieve web pages and to send data to servers. The verbs are:

  • GET – this operation is used to retrieve data from the web service.
  • POST – this operation is used to create a new item of data on the web service.
  • PUT – this operation is used to update an item of data on the web service.
  • PATCH – this operation is used to update an item of data on the web service by describing a set of instructions about how the item should be modified.
  • DELETE – this operation is used to delete an item of data on the web service.

Web service APIs that adhere to REST are defined using:

  • A base URI.
  • HTTP methods, such as GET, POST, PUT, PATCH, or DELETE.
  • A media type for the data, such as JavaScript Object Notation (JSON).

REST-based web services typically use JSON messages to return data to the client. JSON is a text-based data-interchange format that produces compact payloads, which results in reduced bandwidth requirements when sending data. The simplicity of REST has helped make it the primary method for accessing web services in mobile apps.

Web service operations

The example REST service is written using ASP.NET Core and provides the following operations:

Operation HTTP method Relative URI Parameters
Get a list of todo items GET /api/todoitems/
Create a new todo item POST /api/todoitems/ A JSON formatted TodoItem
Update a todo item PUT /api/todoitems/ A JSON formatted TodoItem
Delete a todo item DELETE /api/todoitems/{id}

The .NET MAUI app and web service uses the TodoItem class to model the data that is displayed and sent to the web service for storage:

public class TodoItem
{
    public string ID { get; set; }
    public string Name { get; set; }
    public string Notes { get; set; }
    public bool Done { get; set; }
}

The ID property is used to uniquely identify each TodoItem object, and is used by the web service to identify data to be updated or deleted. For example, to delete the TodoItem whose ID is 6bb8a868-dba1-4f1a-93b7-24ebce87e243, the .NET MAUI app sends a DELETE request to https://hostname/api/todoitems/6bb8a868-dba1-4f1a-93b7-24ebce87e243.

When the Web API framework receives a request, it routes the request to an action. These actions are public methods in the TodoItemsController class. The Web API framework uses routing middleware to match the URLs of incoming requests and map them to actions. REST APIs should use attribute routing to model the app's functionality as a set of resources whose operations are represented by HTTP verbs. Attribute routing uses a set of attributes to map actions directly to route templates. For more information about attribute routing, see Attribute routing for REST APIs. For more information about building the REST service using ASP.NET Core, see Creating backend services for native mobile applications.

Create the HTTPClient object

A .NET Multi-platform App UI (.NET MAUI) app can consume a REST-based web service by sending requests to the web service with the HttpClient class. This class provides functionality for sending HTTP requests and receiving HTTP responses from a URI identified resource. Each request is sent as an asynchronous operation.

The HttpClient object should be declared at the class-level so that it lives for as long as the app needs to make HTTP requests:

public class RestService : IRestService
{
    HttpClient _client;
    JsonSerializerOptions _serializerOptions;

    public List<TodoItem> Items { get; private set; }

    public RestService()
    {
        _client = new HttpClient();
        _serializerOptions = new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
            WriteIndented = true
        };
    }
    ...
}

The JsonSerializerOptions object is used to configure the formatting of the JSON payload that's received from and sent to the web service. For more information, see How to instantiate JsonSerializerOptions instances with System.Text.Json.

Retrieve data

The HttpClient.GetAsync method is used to send a GET request to the web service specified by the URI, and then receive the response from the web service:

public async Task<List<TodoItem>> RefreshDataAsync()
{
    Items = new List<TodoItem>();

    Uri uri = new Uri(string.Format(Constants.RestUrl, string.Empty));
    try
    {
        HttpResponseMessage response = await _client.GetAsync(uri);
        if (response.IsSuccessStatusCode)
        {
            string content = await response.Content.ReadAsStringAsync();
            Items = JsonSerializer.Deserialize<List<TodoItem>>(content, _serializerOptions);
        }
    }
    catch (Exception ex)
    {
        Debug.WriteLine(@"\tERROR {0}", ex.Message);
    }

    return Items;
}

Data is received from the web service as a HttpResponseMessage object. It contains information about the response, including the status code, headers, and any body. The REST service sends an HTTP status code in its response, which can be obtained from the HttpResponseMessage.IsSuccessStatusCode property, to indicate whether the HTTP request succeeded or failed. For this operation the REST service sends HTTP status code 200 (OK) in the response, which indicates that the request succeeded and that the requested information is in the response.

If the HTTP operation was successful, the content of the response is read. The HttpResponseMessage.Content property represents the content of the response, and is of type HttpContent. The HttpContent class represents the HTTP body and content headers, such as Content-Type and Content-Encoding. The content is then read into a string using the HttpContent.ReadAsStringAsync method. The string is then deserialized from JSON to a List of TodoItem objects.

Warning

Using the ReadAsStringAsync method to retrieve a large response can have a negative performance impact. In such circumstances the response should be directly deserialized to avoid having to fully buffer it.

Create data

The HttpClient.PostAsync method is used to send a POST request to the web service specified by the URI, and then to receive the response from the web service:

public async Task SaveTodoItemAsync(TodoItem item, bool isNewItem = false)
{
    Uri uri = new Uri(string.Format(Constants.RestUrl, string.Empty));

    try
    {
        string json = JsonSerializer.Serialize<TodoItem>(item, _serializerOptions);
        StringContent content = new StringContent(json, Encoding.UTF8, "application/json");

        HttpResponseMessage response = null;
        if (isNewItem)
            response = await _client.PostAsync(uri, content);
        else
            response = await _client.PutAsync(uri, content);

        if (response.IsSuccessStatusCode)
            Debug.WriteLine(@"\tTodoItem successfully saved.");
    }
    catch (Exception ex)
    {
        Debug.WriteLine(@"\tERROR {0}", ex.Message);
    }
}

In this example, the TodoItem instance is serialized to a JSON payload for sending to the web service. This payload is then embedded in the body of the HTTP content that will be sent to the web service before the request is made with the PostAsync method.

The REST service sends an HTTP status code in its response, which can be obtained from the HttpResponseMessage.IsSuccessStatusCode property, to indicate whether the HTTP request succeeded or failed. The typical responses for this operation are:

  • 201 (CREATED) – the request resulted in a new resource being created before the response was sent.
  • 400 (BAD REQUEST) – the request is not understood by the server.
  • 409 (CONFLICT) – the request could not be carried out because of a conflict on the server.

Update data

The HttpClient.PutAsync method is used to send a PUT request to the web service specified by the URI, and then receive the response from the web service:

public async Task SaveTodoItemAsync(TodoItem item, bool isNewItem = false)
{
  ...
  response = await _client.PutAsync(uri, content);
  ...
}

The operation of the PutAsync method is identical to the PostAsync method that's used for creating data in the web service. However, the possible responses sent from the web service differ.

The REST service sends an HTTP status code in its response, which can be obtained from the HttpResponseMessage.IsSuccessStatusCode property, to indicate whether the HTTP request succeeded or failed. The typical responses for this operation are:

  • 204 (NO CONTENT) – the request has been successfully processed and the response is intentionally blank.
  • 400 (BAD REQUEST) – the request is not understood by the server.
  • 404 (NOT FOUND) – the requested resource does not exist on the server.

Delete data

The HttpClient.DeleteAsync method is used to send a DELETE request to the web service specified by the URI, and then receive the response from the web service:

public async Task DeleteTodoItemAsync(string id)
{
    Uri uri = new Uri(string.Format(Constants.RestUrl, id));

    try
    {
        HttpResponseMessage response = await _client.DeleteAsync(uri);
        if (response.IsSuccessStatusCode)
            Debug.WriteLine(@"\tTodoItem successfully deleted.");
    }
    catch (Exception ex)
    {
        Debug.WriteLine(@"\tERROR {0}", ex.Message);
    }
}

The REST service sends an HTTP status code in its response, which can be obtained from the HttpResponseMessage.IsSuccessStatusCode property, to indicate whether the HTTP request succeeded or failed. The typical responses for this operation are:

  • 204 (NO CONTENT) – the request has been successfully processed and the response is intentionally blank.
  • 400 (BAD REQUEST) – the request is not understood by the server.
  • 404 (NOT FOUND) – the requested resource does not exist on the server.

Local development

If you're developing a REST web service locally with a framework such as ASP.NET Core Web API, you can debug your web service and .NET MAUI app at the same time. In this scenario, to consume your web service over HTTP from Android emulators and iOS simulators, you must enable clear-text HTTP traffic in your .NET MAUI app. For more information, see Connect to local web services from Android emulators and iOS simulators.