diff options
Diffstat (limited to 'src/SendGrid/Client.cs')
-rw-r--r-- | src/SendGrid/Client.cs | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/src/SendGrid/Client.cs b/src/SendGrid/Client.cs new file mode 100644 index 0000000..2cb20a0 --- /dev/null +++ b/src/SendGrid/Client.cs @@ -0,0 +1,318 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace SendGrid +{ + public class Response + { + public HttpStatusCode StatusCode; + public HttpContent Body; + public HttpResponseHeaders Headers; + + /// <summary> + /// Holds the response from an API call. + /// </summary> + /// <param name="statusCode">https://msdn.microsoft.com/en-us/library/system.net.httpstatuscode(v=vs.110).aspx</param> + /// <param name="responseBody">https://msdn.microsoft.com/en-us/library/system.net.http.httpcontent(v=vs.118).aspx</param> + /// <param name="responseHeaders">https://msdn.microsoft.com/en-us/library/system.net.http.headers.httpresponseheaders(v=vs.118).aspx</param> + public Response(HttpStatusCode statusCode, HttpContent responseBody, HttpResponseHeaders responseHeaders) + { + StatusCode = statusCode; + Body = responseBody; + Headers = responseHeaders; + } + + /// <summary> + /// Converts string formatted response body to a Dictionary. + /// </summary> + /// <param name="content">https://msdn.microsoft.com/en-us/library/system.net.http.httpcontent(v=vs.118).aspx</param> + /// <returns>Dictionary object representation of HttpContent</returns> + public virtual Dictionary<string, dynamic> DeserializeResponseBody(HttpContent content) + { + var dsContent = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(content.ReadAsStringAsync().Result); + return dsContent; + } + + /// <summary> + /// Converts string formatted response headers to a Dictionary. + /// </summary> + /// <param name="content">https://msdn.microsoft.com/en-us/library/system.net.http.headers.httpresponseheaders(v=vs.118).aspx</param> + /// <returns>Dictionary object representation of HttpRepsonseHeaders</returns> + public virtual Dictionary<string, string> DeserializeResponseHeaders(HttpResponseHeaders content) + { + var dsContent = new Dictionary<string, string>(); + foreach (var pair in content) + { + dsContent.Add(pair.Key, pair.Value.First()); + } + return dsContent; + } + } + + public class Client + { + public string Host; + public Dictionary<string, string> RequestHeaders; + public string Version; + public string UrlPath; + public string MediaType; + public IWebProxy WebProxy; + public enum Methods + { + DELETE, GET, PATCH, POST, PUT + } + + + /// <summary> + /// REST API client. + /// </summary> + /// <param name="host">Base url (e.g. https://api.sendgrid.com)</param> + /// <param name="requestHeaders">A dictionary of request headers</param> + /// <param name="version">API version, override AddVersion to customize</param> + /// <param name="urlPath">Path to endpoint (e.g. /path/to/endpoint)</param> + /// <returns>Interface to the SendGrid REST API</returns> + public Client(IWebProxy webProxy, string apiKey, string host = "https://api.sendgrid.com", Dictionary<string, string> requestHeaders = null, string version = "v3", string urlPath = null) + : this(apiKey, host, requestHeaders, version, urlPath) + { + WebProxy = webProxy; + } + + /// <summary> + /// REST API client. + /// </summary> + /// <param name="host">Base url (e.g. https://api.sendgrid.com)</param> + /// <param name="requestHeaders">A dictionary of request headers</param> + /// <param name="version">API version, override AddVersion to customize</param> + /// <param name="urlPath">Path to endpoint (e.g. /path/to/endpoint)</param> + /// <returns>Interface to the SendGrid REST API</returns> + public Client(string apiKey, string host = "https://api.sendgrid.com", Dictionary<string, string> requestHeaders = null, string version = "v3", string urlPath = null) + { + Host = host; + this.GetType().GetTypeInfo().Assembly.GetName().Version.ToString(); + Dictionary<string, string> defaultHeaders = new Dictionary<string, string>(); + defaultHeaders.Add("Authorization", "Bearer " + apiKey); + defaultHeaders.Add("Content-Type", "application/json"); + defaultHeaders.Add("User-Agent", "sendgrid/" + Version + " csharp"); + defaultHeaders.Add("Accept", "application/json"); + AddRequestHeader(defaultHeaders); + if (requestHeaders != null) + { + AddRequestHeader(requestHeaders); + } + SetVersion(version); + SetUrlPath(urlPath); + } + + /// <summary> + /// Add requestHeaders to the API call + /// </summary> + /// <param name="requestHeaders">A dictionary of request headers</param> + public void AddRequestHeader(Dictionary<string, string> requestHeaders) + { + RequestHeaders = (RequestHeaders != null) + ? RequestHeaders.Union(requestHeaders).ToDictionary(pair => pair.Key, pair => pair.Value) : requestHeaders; + } + + /// <summary> + /// Set or update the UrlPath + /// </summary> + /// <param name="urlPath">The endpoint without a leading or trailing slash</param> + public void SetUrlPath(string urlPath) + { + UrlPath = urlPath; + } + + /// <summary> + /// Get the urlPath to the API endpoint + /// </summary> + /// <returns>Url path to the API endpoint</returns> + public string GetUrlPath() + { + return UrlPath; + } + + /// <summary> + /// Build the final URL + /// </summary> + /// <param name="queryParams">A string of JSON formatted query parameters (e.g {'param': 'param_value'})</param> + /// <returns>Final URL</returns> + private string BuildUrl(string queryParams = null) + { + string endpoint = null; + + if (GetVersion() != null) + { + endpoint = Host + "/" + GetVersion() + "/" + UrlPath; + } + else + { + endpoint = Host + UrlPath; + } + + if (queryParams != null) + { + var ds_query_params = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(queryParams); + var query = new Dictionary<string, string>(); + foreach (var pair in ds_query_params) + { + query[pair.Key] = pair.Value.ToString(); + } + string queryString = query.ToString(); + endpoint = endpoint + "?" + queryString; + } + + return endpoint; + } + + /// <summary> + /// Factory method to return the right HttpClient settings. + /// </summary> + /// <returns>Instance of HttpClient</returns> + private HttpClient BuildHttpClient() + { + // Add the WebProxy if set + if (WebProxy != null) + { + var httpClientHandler = new HttpClientHandler() + { + Proxy = WebProxy, + PreAuthenticate = true, + UseDefaultCredentials = false, + }; + + return new HttpClient(httpClientHandler); + } + + return new HttpClient(); + } + + /// <summary> + /// Add the authorization header, override to customize + /// </summary> + /// <param name="header">Authorization header</param> + /// <returns>Authorization value to add to the header</returns> + public virtual AuthenticationHeaderValue AddAuthorization(KeyValuePair<string, string> header) + { + string[] split = header.Value.Split(new char[0]); + return new AuthenticationHeaderValue(split[0], split[1]); + } + + /// <summary> + /// Add the version of the API, override to customize + /// </summary> + /// <param name="version">Version string to add to the URL</param> + public void SetVersion(string version) + { + Version = version; + } + + /// <summary> + /// Get the version of the API, override to customize + /// </summary> + /// <returns>Version of the API</param> + public string GetVersion() + { + return Version; + } + + /// <summary> + /// Make the call to the API server, override for testing or customization + /// </summary> + /// <param name="client">Client object ready for communication with API</param> + /// <param name="request">The parameters for the API call</param> + /// <returns>Response object</returns> + public async virtual Task<Response> MakeRequest(HttpClient client, HttpRequestMessage request) + { + HttpResponseMessage response = await client.SendAsync(request).ConfigureAwait(false); + return new Response(response.StatusCode, response.Content, response.Headers); + } + + /// <summary> + /// Prepare for async call to the API server + /// </summary> + /// <param name="method">HTTP verb</param> + /// <param name="requestBody">JSON formatted string</param> + /// <param name="queryParams">JSON formatted query paramaters</param> + /// <returns>Response object</returns> + public async Task<Response> RequestAsync(Client.Methods method, + string requestBody = null, + Dictionary<string, string> requestHeaders = null, + string queryParams = null, + string urlPath = null) + { + using (var client = BuildHttpClient()) + { + try + { + // Build the URL + client.BaseAddress = new Uri(Host); + if (urlPath != null) + { + SetUrlPath(urlPath); + } + string endpoint = BuildUrl(queryParams); + + // Build the request headers + if (requestHeaders != null) + { + AddRequestHeader(requestHeaders); + } + client.DefaultRequestHeaders.Accept.Clear(); + if (RequestHeaders != null) + { + foreach (KeyValuePair<string, string> header in RequestHeaders) + { + if (header.Key == "Authorization") + { + client.DefaultRequestHeaders.Authorization = AddAuthorization(header); + } + else if (header.Key == "Content-Type") + { + MediaType = header.Value; + client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(MediaType)); + } + else + { + client.DefaultRequestHeaders.Add(header.Key, header.Value); + } + } + } + + // Build the request body + StringContent content = null; + if (requestBody != null) + { + content = new StringContent(requestBody, Encoding.UTF8, MediaType); + } + + // Build the final request + HttpRequestMessage request = new HttpRequestMessage + { + Method = new HttpMethod(method.ToString()), + RequestUri = new Uri(endpoint), + Content = content + }; + return await MakeRequest(client, request).ConfigureAwait(false); + + } + catch (Exception ex) + { + HttpResponseMessage response = new HttpResponseMessage(); + string message; + message = (ex is HttpRequestException) ? ".NET HttpRequestException" : ".NET Exception"; + message = message + ", raw message: \n\n"; + response.Content = new StringContent(message + ex.Message); + return new Response(response.StatusCode, response.Content, response.Headers); + } + } + } + } +} |