PageRenderTime 39ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/Atlassian.Jira/Remote/JiraRestClient.cs

https://bitbucket.org/farmas/atlassian.net-sdk
C# | 241 lines | 171 code | 24 blank | 46 comment | 35 complexity | 7a962a45db4736d87c5e55394849a23a MD5 | raw file
Possible License(s): BSD-3-Clause
  1. using System;
  2. using System.Diagnostics;
  3. using System.Net;
  4. using System.Threading;
  5. using System.Threading.Tasks;
  6. using Newtonsoft.Json;
  7. using Newtonsoft.Json.Linq;
  8. using RestSharp;
  9. using RestSharp.Authenticators;
  10. using RestSharp.Extensions;
  11. namespace Atlassian.Jira.Remote
  12. {
  13. /// <summary>
  14. /// Implements the IJiraRestClient interface using RestSharp.
  15. /// </summary>
  16. public class JiraRestClient : IJiraRestClient
  17. {
  18. private readonly RestClient _restClient;
  19. private readonly JiraRestClientSettings _clientSettings;
  20. /// <summary>
  21. /// Creates a new instance of the JiraRestClient class.
  22. /// </summary>
  23. /// <param name="url">Url to the JIRA server.</param>
  24. /// <param name="username">Username used to authenticate.</param>
  25. /// <param name="password">Password used to authenticate.</param>
  26. /// <param name="settings">Settings to configure the rest client.</param>
  27. public JiraRestClient(string url, string username = null, string password = null, JiraRestClientSettings settings = null)
  28. : this(url, new HttpBasicAuthenticator(username, password), settings)
  29. {
  30. }
  31. /// <summary>
  32. /// Creates a new instance of the JiraRestClient class.
  33. /// </summary>
  34. /// <param name="url">The url to the JIRA server.</param>
  35. /// <param name="authenticator">The authenticator used by RestSharp.</param>
  36. /// <param name="settings">The settings to configure the rest client.</param>
  37. protected JiraRestClient(string url, IAuthenticator authenticator, JiraRestClientSettings settings = null)
  38. {
  39. url = url.EndsWith("/") ? url : url += "/";
  40. _clientSettings = settings ?? new JiraRestClientSettings();
  41. _restClient = new RestClient(url)
  42. {
  43. Proxy = _clientSettings.Proxy
  44. };
  45. this._restClient.Authenticator = authenticator;
  46. }
  47. /// <summary>
  48. /// Rest sharp client used to issue requests.
  49. /// </summary>
  50. public RestClient RestSharpClient
  51. {
  52. get
  53. {
  54. return _restClient;
  55. }
  56. }
  57. /// <summary>
  58. /// Url to the JIRA server.
  59. /// </summary>
  60. public string Url
  61. {
  62. get
  63. {
  64. return _restClient.BaseUrl.ToString();
  65. }
  66. }
  67. /// <summary>
  68. /// Settings to configure the rest client.
  69. /// </summary>
  70. public JiraRestClientSettings Settings
  71. {
  72. get
  73. {
  74. return _clientSettings;
  75. }
  76. }
  77. /// <summary>
  78. /// Executes an async request and serializes the response to an object.
  79. /// </summary>
  80. public async Task<T> ExecuteRequestAsync<T>(Method method, string resource, object requestBody = null, CancellationToken token = default(CancellationToken))
  81. {
  82. var result = await ExecuteRequestAsync(method, resource, requestBody, token).ConfigureAwait(false);
  83. return JsonConvert.DeserializeObject<T>(result.ToString(), Settings.JsonSerializerSettings);
  84. }
  85. /// <summary>
  86. /// Executes an async request and returns the response as JSON.
  87. /// </summary>
  88. public async Task<JToken> ExecuteRequestAsync(Method method, string resource, object requestBody = null, CancellationToken token = default(CancellationToken))
  89. {
  90. if (method == Method.GET && requestBody != null)
  91. {
  92. throw new InvalidOperationException($"GET requests are not allowed to have a request body. Resource: {resource}. Body: {requestBody}");
  93. }
  94. var request = new RestRequest();
  95. request.Method = method;
  96. request.Resource = resource;
  97. request.RequestFormat = DataFormat.Json;
  98. if (requestBody is string)
  99. {
  100. request.AddParameter(new Parameter(name: "application/json", value: requestBody, type: ParameterType.RequestBody));
  101. }
  102. else if (requestBody != null)
  103. {
  104. request.JsonSerializer = new RestSharpJsonSerializer(JsonSerializer.Create(Settings.JsonSerializerSettings));
  105. request.AddJsonBody(requestBody);
  106. }
  107. LogRequest(request, requestBody);
  108. var response = await ExecuteRawResquestAsync(request, token).ConfigureAwait(false);
  109. return GetValidJsonFromResponse(request, response);
  110. }
  111. /// <summary>
  112. /// Executes a request with logging and validation.
  113. /// </summary>
  114. public async Task<IRestResponse> ExecuteRequestAsync(IRestRequest request, CancellationToken token = default(CancellationToken))
  115. {
  116. LogRequest(request);
  117. var response = await ExecuteRawResquestAsync(request, token).ConfigureAwait(false);
  118. GetValidJsonFromResponse(request, response);
  119. return response;
  120. }
  121. /// <summary>
  122. /// Executes a raw request.
  123. /// </summary>
  124. protected virtual Task<IRestResponse> ExecuteRawResquestAsync(IRestRequest request, CancellationToken token)
  125. {
  126. return _restClient.ExecuteTaskAsync(request, token);
  127. }
  128. /// <summary>
  129. /// Downloads file as a byte array.
  130. /// </summary>
  131. /// <param name="url">Url to the file location.</param>
  132. public byte[] DownloadData(string url)
  133. {
  134. return _restClient.DownloadData(new RestRequest(url, Method.GET));
  135. }
  136. /// <summary>
  137. /// Downloads file to the specified location.
  138. /// </summary>
  139. /// <param name="url">Url to the file location.</param>
  140. /// <param name="fullFileName">Full file name where the file will be downloaded.</param>
  141. public void Download(string url, string fullFileName)
  142. {
  143. _restClient.DownloadData(new RestRequest(url, Method.GET)).SaveAs(fullFileName);
  144. }
  145. private void LogRequest(IRestRequest request, object body = null)
  146. {
  147. if (this._clientSettings.EnableRequestTrace)
  148. {
  149. Trace.WriteLine(String.Format("[{0}] Request Url: {1}",
  150. request.Method,
  151. request.Resource));
  152. if (body != null)
  153. {
  154. Trace.WriteLine(String.Format("[{0}] Request Data: {1}",
  155. request.Method,
  156. JsonConvert.SerializeObject(body, new JsonSerializerSettings()
  157. {
  158. Formatting = Formatting.Indented,
  159. NullValueHandling = NullValueHandling.Ignore
  160. })));
  161. }
  162. }
  163. }
  164. private JToken GetValidJsonFromResponse(IRestRequest request, IRestResponse response)
  165. {
  166. var content = response.Content != null ? response.Content.Trim() : string.Empty;
  167. if (this._clientSettings.EnableRequestTrace)
  168. {
  169. Trace.WriteLine(String.Format("[{0}] Response for Url: {1}\n{2}",
  170. request.Method,
  171. request.Resource,
  172. content));
  173. }
  174. if (!string.IsNullOrEmpty(response.ErrorMessage))
  175. {
  176. throw new InvalidOperationException($"Error Message: {response.ErrorMessage}");
  177. }
  178. else if (response.StatusCode == HttpStatusCode.Forbidden || response.StatusCode == HttpStatusCode.Unauthorized)
  179. {
  180. throw new System.Security.Authentication.AuthenticationException(string.Format("Response Content: {0}", content));
  181. }
  182. else if (response.StatusCode == HttpStatusCode.NotFound)
  183. {
  184. throw new ResourceNotFoundException($"Response Content: {content}");
  185. }
  186. else if ((int)response.StatusCode >= 400)
  187. {
  188. throw new InvalidOperationException($"Response Status Code: {(int)response.StatusCode}. Response Content: {content}");
  189. }
  190. else if (string.IsNullOrWhiteSpace(content))
  191. {
  192. return new JObject();
  193. }
  194. else if (!content.StartsWith("{") && !content.StartsWith("["))
  195. {
  196. throw new InvalidOperationException(String.Format("Response was not recognized as JSON. Content: {0}", content));
  197. }
  198. else
  199. {
  200. JToken parsedContent;
  201. try
  202. {
  203. parsedContent = JToken.Parse(content);
  204. }
  205. catch (JsonReaderException ex)
  206. {
  207. throw new InvalidOperationException(String.Format("Failed to parse response as JSON. Content: {0}", content), ex);
  208. }
  209. if (parsedContent != null && parsedContent.Type == JTokenType.Object && parsedContent["errorMessages"] != null)
  210. {
  211. throw new InvalidOperationException(string.Format("Response reported error(s) from JIRA: {0}", parsedContent["errorMessages"].ToString()));
  212. }
  213. return parsedContent;
  214. }
  215. }
  216. }
  217. }