DEV Community

Frederik Van Lierde
Frederik Van Lierde

Posted on

Considerations to speed up API Calls with C#

Speeding up API calls in an App is important because it can significantly impact the user experience, scalability, and overall reliability of the application. Users expect instant results and a seamless experience when using an App. Slow and unresponsive API calls can lead to user frustration and potentially drive them away from using the application.

Note

The upcoming chapters present various ideas to accelerate API calls by utilizing C-Sharp and Xamarin. However, it's important to note that not all of these ideas will have a significant impact, and some may need further testing and discussion. The speed of API calls depends on several factors, and the effectiveness of these ideas may vary based on the specific requirements and constraints of your application.

HttpClient Readonly

In C#, the readonly keyword is used to indicate that a variable or field can only be assigned a value once, and its value cannot be changed afterwards. When it comes to using the HttpClient in .NET and Xamarin development, making it readonly can provide some benefits.

Thread-safety: The HttpClient class is designed to be thread-safe when used correctly. However, if you're not careful, you can accidentally create race conditions that can lead to unpredictable behavior. Making your HttpClient readonly can help ensure that it's not modified by multiple threads simultaneously.

Connection pooling: The HttpClient class uses connection pooling to reuse existing connections to a given host. If you create a new instance of HttpClient every time you make an HTTP request, you'll be creating new connection pools each time as well, which can impact performance. By making your HttpClient readonly, you can ensure that it's only created once, and the connection pool is reused across multiple requests.

Performance: Creating a new instance of HttpClient every time you make an HTTP request can be expensive, as it involves setting up a new connection and performing the necessary handshakes. By making your HttpClient readonly, you can ensure that it's only created once, which can improve performance.

namespace SmoodApp.Models
{
    public class SmoodAPI
    {
        #region Properties
        private readonly HttpClient _httpClient;
        #endregion
    }
}
Enter fullscreen mode Exit fullscreen mode

In the given code snippet, we have a class named "SmoodAPI". This class consists of a private field named "_httpClient" , which is marked as "readonly". Later, this class will contain various calls that use this readonly _httpClient.

Set Proxy to Null

Setting the proxy properties of the HttpClient to null can provide several advantages, including:

Improved performance: If your application doesn't need to use a proxy server to make HTTP requests, setting the proxy properties to null can help eliminate the overhead of proxy resolution, which can improve the overall performance of your application.

Avoidance of potential issues: Using a proxy server to make HTTP requests can sometimes introduce issues with connectivity, authentication, or security. By setting the proxy properties to null, you can avoid these potential issues altogether.

As Smood doesn’t use a proxy server, we can set the value to null

#region Constructors
      public SmoodAPI() {
            HttpClientHandler _httpHandler = new HttpClientHandler();
            _httpHandler.Proxy = null;
            _httpHandler.UseProxy = false;
            _httpClient = new HttpClient(_httpHandler);
        }
#endregion
Enter fullscreen mode Exit fullscreen mode

HttpClient Compression

Setting HttpClient compression to gzip can provide several benefits, including:

Reduced network traffic: By enabling gzip compression, the size of the data sent over the network can be significantly reduced, resulting in less network traffic and potentially faster transfer times. This can help improve the performance of your application, especially if it makes a large number of HTTP requests or handles large amounts of data.

Improved bandwidth utilization: Gzip compression can help make better use of available bandwidth by reducing the amount of data that needs to be transferred. This can help reduce costs associated with data transfer and increase the efficiency of your application.

Better user experience: By reducing the amount of data that needs to be transferred, enabling gzip compression can help improve the overall responsiveness and speed of your application. This can lead to a better user experience, which can help increase engagement and retention.

Standardized compression: Gzip compression is a widely used and accepted compression algorithm, which means that enabling it can help ensure compatibility and interoperability across different platforms and systems.

#region Constructors
        public SmoodAPI() {
            HttpClientHandler _httpHandler = new HttpClientHandler();
            _httpHandler.Proxy = null;
            _httpHandler.UseProxy = false;
            _httpHandler.AutomaticDecompression = System.Net.DecompressionMethods.GZip;
            _httpClient = new HttpClient(_httpHandler);
        }
endregion
Enter fullscreen mode Exit fullscreen mode

The GetJson Function

Using a stream to call an API can be faster than using other methods because it allows for a more efficient transfer of data between the client and server.

When making an API call, data is typically sent back and forth between the client and server as a series of bytes. This data can be transferred using different methods, such as byte arrays, strings, or streams.

When using a stream to transfer data, the data is transferred in a continuous flow of bytes, rather than as discrete chunks of data. This can help reduce the amount of overhead required to transfer the data, as there is less need for buffering and chunking.

Additionally, when using a stream, the data can be read and processed as it is received, rather than waiting for the entire response to be received before processing it. This can help reduce the latency associated with API calls, as the client can begin processing the data as soon as it starts to arrive.

Using a stream can also help reduce the memory usage associated with API calls, as the data can be read and processed in smaller, more manageable chunks, rather than loading the entire response into memory at once.

public async Task<T> GetJson<T>(string apiURL, CancellationToken cancellationToken) where T : new()
        {
            SetAuthorizationHeader();

            using (var request = new HttpRequestMessage(HttpMethod.Get, apiURL))
            using (var response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken))
            {
                var stream = await response.Content.ReadAsStreamAsync();

                if (response.IsSuccessStatusCode)
                    return (JsonSerializer.Deserialize<T>(stream)) ?? new T();
            }
            return new T();
        }
Enter fullscreen mode Exit fullscreen mode

This method will set the Authorization header (as explained later) and use a stream to deserialize the response into the specified object.

An example to how to use the universal GetJson function:

public async Task<UniversesResult> Universes(string locationType, string location, string language, string collection = "", string parent = "")
        {
            string apiURL = "...SMOODAPI_UNIVERSES_URL..."
            return await GetJson<UniversesResult>(apiURL.ToLower(), new CancellationToken());
        }
Enter fullscreen mode Exit fullscreen mode

The SetAuthorizationHeader function

This function sets the Smood security token and enables gzip compression settings.

 protected virtual void SetAuthorizationHeader()
        {

            StringWithQualityHeaderValue _gzip = new System.Net.Http.Headers.StringWithQualityHeaderValue("gzip");
            if (!_httpClient.DefaultRequestHeaders.AcceptEncoding.Contains(_gzip))
                _httpClient.DefaultRequestHeaders.AcceptEncoding.Add(_gzip);
        }

Enter fullscreen mode Exit fullscreen mode

Calling multiple API calls on loading a page

Using WhenAll to call several API calls can provide several benefits, including:

Improved performance: By calling multiple API calls concurrently, you can reduce the overall time required to complete all the requests. This can help improve the performance of your application and reduce the time required for users to receive a response.

Better resource utilization: When calling multiple API calls sequentially, the application may be idling while waiting for the response from the server. By calling multiple API calls concurrently, you can ensure that the application is using resources efficiently and maximizing its potential.

Simplification of code: By using WhenAll to call multiple API calls concurrently, you can simplify your code by removing the need for multiple nested loops or callback functions.

Better error handling: When calling multiple API calls sequentially, an error in one request can block the remaining requests from being executed. By calling multiple API calls concurrently, you can continue executing requests even if one request encounters an error, allowing for better error handling and recovery.

The following example calls the different API calls for the discovery page, including marketing banners, New on Smood, Click & Collect Store, SubUniverses of Restaurants (Food Type)
The make it easy the sort, location info is available as a property of the App class.

private async Task GetDiscoveryPage(bool takeaway)
        {
            IsRefreshing = true;

            var taskBanners = GetMarketingBanners();
            var taskStoreResults = GetStoreResults(takeaway);
            var taskNewStoreResults = GetNewStoreResults(takeaway);
            var taskRestaurantsUniverses = GetSubUniverses();

            await Task.WhenAll(taskBanners, taskStoreResults, taskNewStoreResults, taskRestaurantsUniverses);

            IsRefreshing = false;
        }
Enter fullscreen mode Exit fullscreen mode

Conclusion

It is recommended that developers continue to brainstorm and experiment with different approaches to optimize the application's speed and efficiency. With continuous effort and experimentation, we can build a fast and reliable application that meets the needs of its users.

Top comments (0)