C# RestApiClient

Date: 2019-10-16
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace Helpers
{
    public class RestApiResponse<T>
    {
        public RestApiResponse(string url, HttpResponseMessage response, TimeSpan duration, string content, T result)
        {
            Url = url;
            Response = response;
            Duration = duration;
            Content = content;
            Result = result;
        }
        public readonly string Url;
        public readonly HttpResponseMessage Response;
        public readonly TimeSpan Duration;
        public HttpStatusCode Status => Response.StatusCode;
        public bool Success => Response.IsSuccessStatusCode;
        public readonly string Content;
        public readonly T Result;
    }

    public class RequestSettings {
        public RequestSettings() { }
        public RequestSettings(HttpMethod method, object content = null, string contentType = "application/json") {
            Method = method;
            Content = content;
            ContentType = contentType;
        }
        public HttpMethod Method { get; set; } = HttpMethod.Get;
        public object Content { get; set; } = null;
        public string ContentType { get; set; } = "application/json";
        public Dictionary<string, string> Headers { get; set; } = new Dictionary<string, string>();
        public bool ThrowOnErrorStatus { get; set; } = false;
    }

   public class RestApiClient
    {
        private const string AuthorizationHeader = "Authorization";
        public string BearerToken { get; set; }
        private static readonly HttpClientHandler _httpClientHandler = new HttpClientHandler { UseCookies = false };
        private static readonly HttpClient _httpClient = new HttpClient(_httpClientHandler);
        public RestApiClient(string apiAddress)
        {
            this.apiAddress = apiAddress;
        }
        private readonly string apiAddress;
       
        private string GetUrl(params string[] parts)
        {
            var partList = new List<string> { apiAddress.TrimEnd('/') };
            partList.AddRange(parts.Where(part => !string.IsNullOrEmpty(part)).Select(part => part.TrimStart('/')));
            return string.Join("/", partList);
        }
        public async Task<RestApiResponse<T>> Request<T>(RequestSettings requestSettings, params string[] parts)
        {
            var uri = GetUrl(parts);
            var requestMessage = new HttpRequestMessage(requestSettings.Method, uri);
            if (!string.IsNullOrEmpty(BearerToken))
            {
                requestMessage.Headers.Add(AuthorizationHeader, $"Bearer {BearerToken}");
            }
            foreach (var header in requestSettings.Headers)
            {
                requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value);
            }

            if (requestSettings.Content != null) { 
                var contentString = (requestSettings.Content is string) ? requestSettings.Content as string : JsonConvert.SerializeObject(requestSettings.Content);
                if (!string.IsNullOrEmpty(contentString))
                {
                    requestMessage.Content = new StringContent(contentString, Encoding.UTF8, requestSettings.ContentType);
                }
            }
            var startTime = DateTime.Now;
            var responseMessage = await _httpClient.SendAsync(requestMessage);
            var responseContent = await responseMessage.Content.ReadAsStringAsync();
            var duration = DateTime.Now - startTime;
            if (responseMessage.StatusCode == HttpStatusCode.Unauthorized)
            {
                throw new UnauthorizedAccessException($"Unauthorized; Url: {uri}");
            }
            else if (requestSettings.ThrowOnErrorStatus && !responseMessage.IsSuccessStatusCode)
            {
                throw new Exception($"[{uri}]\r\n[Error, status not expected: {responseMessage.StatusCode}]\r\n{responseContent}");
            }
            if (typeof(T) != typeof(string))
            {
                T result = default;
                try {
                    result = JsonConvert.DeserializeObject<T>(responseContent);
                } catch (Exception) { /* ignore */ }
                return new RestApiResponse<T>(uri, responseMessage, duration, responseContent, result);
            }
            // Return the request content as string
            return new RestApiResponse<T>(uri, responseMessage, duration, responseContent, (T)Convert.ChangeType(responseContent, typeof(T)));
        }
        public async Task<RestApiResponse<T>> Do<T>(RequestSettings requestSettings, params string[] parts)
            => await Request<T>(requestSettings, parts);
        public async Task<RestApiResponse<T>> Get<T>(params string[] parts)
            => await Request<T>(new RequestSettings(HttpMethod.Get), parts);
        public async Task<RestApiResponse<T>> Post<T>(object content, params string[] parts)
            => await Request<T>(new RequestSettings(HttpMethod.Post, content), parts);
        public async Task<RestApiResponse<T>> Put<T>(object content, params string[] parts)
            => await Request<T>(new RequestSettings(HttpMethod.Put, content), parts);
        public async Task<RestApiResponse<T>> Delete<T>(params string[] parts)
            => await Request<T>(new RequestSettings(HttpMethod.Delete), parts);
    }
}
26810cookie-checkC# RestApiClient