private async Task <TResponse> PerformHttp <TRequest, TResponse>(string path, HttpMethod method, TRequest requestBody, CancellationToken token) where TResponse : class { HttpClient httpClient = _httpClientProducer.CreateClient(); using HttpRequestMessage req = new HttpRequestMessage(method, path); if (requestBody != null) { req.Content = new JsonContent <TRequest>(_serializer, requestBody); } // Login if needed, then sign the request await _requestSigner.LoginIfNeeded(this, token); await _requestSigner.Sign(httpClient, req, token); // Issue the request using HttpResponseMessage resp = await httpClient.SendAsync(req, HttpCompletionOption.ResponseContentRead, token); if (resp.Content.Headers.ContentType.MediaType != "application/json") { throw new Exception($"API request did not result in a Json object. Path: '{path}'."); } if (_logger.IsEnabled(LogLevel.Trace)) { // Log request / Response // Note: It should be fine to read the content twice, as HttpCompletionOption.ResponseContentRead is set string responseBody = await resp.Content.ReadAsStringAsync(); _logger.LogTrace("Received {Code} for {Path}, with body: {Body}", resp.StatusCode, req.RequestUri, responseBody); } JObject obj = Parse <JObject>(await resp.Content.ReadAsStreamAsync()); if (obj.ContainsKey("errorMessage") /* && obj.ContainsKey("errorType")*/) { // This is an error, regardless of what the status code is throw new Exception($"API responded with an error: {obj.Value<string>("errorMessage")}. Path: '{path}'."); } if (resp.StatusCode == HttpStatusCode.OK) { return(obj.ToObject <TResponse>()); } // Something is wrong, try fetching a message if (obj.TryGetValue("errorMessage", out JToken errorMsg) || obj.TryGetValue("message", out errorMsg)) { throw new Exception($"API resulted in a non-success status code. Message: {errorMsg}. Path: '{path}'."); } throw new Exception($"API resulted in a non-success status code. No futher details available. Path: '{path}'."); }
/// <inheritdoc /> protected override async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { await _requestSigner.Sign(request).ConfigureAwait(false); return(await base.SendAsync(request, cancellationToken).ConfigureAwait(false)); }