Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic implementation of error handler #2

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 19 additions & 8 deletions src/RLSApi.Example/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using RLSApi.Data;
using RLSApi.Net.Requests;
Expand All @@ -16,20 +17,30 @@ private static async Task Run()
var apiKey = Environment.GetEnvironmentVariable("RLS_API_KEY");

// Initialize RLSClient.
var client = new RLSClient(apiKey);
var client = new RLSClient(apiKey, httpExceptionHandler: async res =>
{
Console.WriteLine(res.ToString());
});

// Retrieve a single player.
var player = await client.GetPlayerAsync(RlsPlatform.Steam, "76561198033338223");
var playerSeasonSix = player.RankedSeasons.FirstOrDefault(x => x.Key == RlsSeason.Six);
if (playerSeasonSix.Value != null)
var player = await client.GetPlayerAsync(RlsPlatform.Steam, "7656198033338223");
if (player != null)
{
Console.WriteLine($"# Player: {player.DisplayName}");

foreach (var playerRank in playerSeasonSix.Value)
var playerSeasonSix = player.RankedSeasons.FirstOrDefault(x => x.Key == RlsSeason.Six);
if (playerSeasonSix.Value != null)
{
Console.WriteLine($"{playerRank.Key}: {playerRank.Value.RankPoints} rating");
Console.WriteLine($"# Player: {player.DisplayName}");

foreach (var playerRank in playerSeasonSix.Value)
{
Console.WriteLine($"{playerRank.Key}: {playerRank.Value.RankPoints} rating");
}
}
}
else
{
Console.WriteLine("Could not find player");
}

// Retrieve multiple players.
var players = await client.GetPlayersAsync(new[]
Expand Down
10 changes: 8 additions & 2 deletions src/RLSApi.sln
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26430.15
VisualStudioVersion = 15.0.26730.12
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RLSApi", "RLSApi\RLSApi.csproj", "{75321AB1-50FE-4112-902A-C2604DDB8932}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RLSApi.Example", "RLSApi.Example\RLSApi.Example.csproj", "{CE55593F-FC7B-4DE0-A384-EAD9482C6882}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RLSApi.Example", "RLSApi.Example\RLSApi.Example.csproj", "{CE55593F-FC7B-4DE0-A384-EAD9482C6882}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -25,4 +25,10 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {556BF256-7FFC-4E2E-BDD8-7864EE452270}
EndGlobalSection
GlobalSection(CodealikeProperties) = postSolution
SolutionGuid = f2712b56-43fc-4d5f-b1bc-913862bc7876
EndGlobalSection
EndGlobal
90 changes: 47 additions & 43 deletions src/RLSApi/Net/ApiRequester.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ namespace RLSApi.Net
internal class ApiRequester : IDisposable
{
private readonly HttpClient _client;
private readonly Func<HttpResponseMessage, Task> _httpExceptionHandler;

public ApiRequester(string apiKey)
public ApiRequester(string apiKey, Func<HttpResponseMessage, Task> exceptionHandler = null)
{
_client = new HttpClient
{
Expand All @@ -25,71 +26,74 @@ public ApiRequester(string apiKey)
{ "Authorization", apiKey }
}
};

_httpExceptionHandler = exceptionHandler ?? (async response =>
{
try
{
var errorMessage = await response.Content.ReadAsStringAsync();

if (string.IsNullOrEmpty(errorMessage))
{
throw new RLSApiException($"Request failed with status code {(int)response.StatusCode} ({response.StatusCode}), there was no error message available.")
{
HttpStatusCode = (int)response.StatusCode
};
}

var error = JsonConvert.DeserializeObject<Error>(errorMessage);

throw new RLSApiException($"Request failed with status code {(int)response.StatusCode} ({response.StatusCode}), RLS: '{error.Message}'.")
{
HttpStatusCode = (int)response.StatusCode,
RlsError = error
};
}
catch (JsonException e)
{
throw new RLSApiException($"Request failed with status code {(int)response.StatusCode} ({response.StatusCode}), we were unable to parse the error message.", e)
{
HttpStatusCode = (int)response.StatusCode
};
}
});
}

public async Task<T> Get<T>(string relativeUrl)
{
using (var request = new HttpRequestMessage(HttpMethod.Get, relativeUrl))
using (var response = await SendAsync(request))
{
var result = await response.Content.ReadAsStringAsync();
return await SendAndReceiveAsync<T>(request);

return JsonConvert.DeserializeObject<T>(result);
}
}



public async Task<T> Post<T>(string relativeUrl, object data)
{
using (var request = new HttpRequestMessage(HttpMethod.Post, relativeUrl))
{
var requestData = JsonConvert.SerializeObject(data, Formatting.None);
request.Content = new StringContent(requestData, Encoding.UTF8, "application/json");
return await SendAndReceiveAsync<T>(request);

using (var response = await SendAsync(request))
{
var result = await response.Content.ReadAsStringAsync();

return JsonConvert.DeserializeObject<T>(result);
}
}
}

protected virtual async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request)
private async Task<T> SendAndReceiveAsync<T>(HttpRequestMessage request)
{
var response = await _client.SendAsync(request);
var response = await SendAsync(request);
if (response.IsSuccessStatusCode)
{
return response;
}

try
{
var errorMessage = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<T>(await response.Content.ReadAsStringAsync());
await _httpExceptionHandler.Invoke(response);
return default(T);
}

if (string.IsNullOrEmpty(errorMessage))
{
throw new RLSApiException($"Request failed with status code {(int)response.StatusCode} ({response.StatusCode}), there was no error message available.")
{
HttpStatusCode = (int)response.StatusCode
};
}
protected virtual async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request)
{
return await _client.SendAsync(request);
}

var error = JsonConvert.DeserializeObject<Error>(errorMessage);

throw new RLSApiException($"Request failed with status code {(int)response.StatusCode} ({response.StatusCode}), RLS: '{error.Message}'.")
{
HttpStatusCode = (int)response.StatusCode,
RlsError = error
};
}
catch (JsonException e)
{
throw new RLSApiException($"Request failed with status code {(int)response.StatusCode} ({response.StatusCode}), we were unable to parse the error message.", e)
{
HttpStatusCode = (int)response.StatusCode
};
}
}

public void Dispose()
{
Expand Down
10 changes: 5 additions & 5 deletions src/RLSApi/Net/ApiRequesterThrottle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ internal class ApiRequesterThrottle : ApiRequester

private DateTime _rateLimitResetRemaining;

public ApiRequesterThrottle(string apiKey) : base(apiKey)
public ApiRequesterThrottle(string apiKey, Func<HttpResponseMessage, Task> exceptionHandler = null) : base(apiKey, exceptionHandler)
{
_queue = new Semaphore(1, 1);
_rateLimitRemaining = 2;
Expand All @@ -45,11 +45,11 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage

var response = await base.SendAsync(request);

if (response.Headers.TryGetValues("x-rate-limit-remaining", out IEnumerable<string> rateLimitRemainingValues) &&
response.Headers.TryGetValues("x-rate-limit-reset-remaining", out IEnumerable<string> rateLimitResetValues))
if (response.Headers.TryGetValues("x-rate-limit-remaining", out var rateLimitRemainingValues) &&
response.Headers.TryGetValues("x-rate-limit-reset-remaining", out var rateLimitResetValues))
{
if (int.TryParse(rateLimitRemainingValues.First(), out int rateLimitRemaining) &&
int.TryParse(rateLimitResetValues.First(), out int rateLimitResetRemaining))
if (int.TryParse(rateLimitRemainingValues.First(), out var rateLimitRemaining) &&
int.TryParse(rateLimitResetValues.First(), out var rateLimitResetRemaining))
{
_rateLimitRemaining = rateLimitRemaining;
_rateLimitResetRemaining = DateTime.UtcNow.AddMilliseconds(rateLimitResetRemaining);
Expand Down
5 changes: 3 additions & 2 deletions src/RLSApi/RLSClient.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using RLSApi.Data;
using RLSApi.Net;
Expand All @@ -13,9 +14,9 @@ public class RLSClient : IDisposable
{
private readonly ApiRequester _api;

public RLSClient(string apiKey, bool throttle = true)
public RLSClient(string apiKey, bool throttle = true, Func<HttpResponseMessage, Task> httpExceptionHandler = null)
{
_api = throttle ? new ApiRequesterThrottle(apiKey) : new ApiRequester(apiKey);
_api = throttle ? new ApiRequesterThrottle(apiKey, httpExceptionHandler) : new ApiRequester(apiKey, httpExceptionHandler);
}

/// <summary>
Expand Down