Skip to content

Commit

Permalink
#255 - Throw exception when server API version is not supported.
Browse files Browse the repository at this point in the history
  • Loading branch information
maraf committed Mar 18, 2020
1 parent f445e10 commit b350cb0
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 5 deletions.
1 change: 1 addition & 0 deletions src/Money.Api/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
p.AllowCredentials();
p.AllowAnyHeader();
p.SetPreflightMaxAge(TimeSpan.FromMinutes(10));
p.WithExposedHeaders(VersionHeader.Name);
});

app.UseAuthentication();
Expand Down
1 change: 1 addition & 0 deletions src/Money.UI.Blazor/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ private static void ConfigureServices(IServiceCollection services)
.AddSingleton<AuthenticationStateProvider>(provider => provider.GetRequiredService<ApiAuthenticationStateProvider>())
.AddSingleton<SignalRListener>()
.AddSingleton<ApiHubService>()
.AddSingleton<ApiVersionChecker>()
.AddTransient<Interop>()
.AddSingleton<PwaInstallInterop>()
.AddTransient<NetworkStateInterop>()
Expand Down
25 changes: 20 additions & 5 deletions src/Money.UI.Blazor/Services/ApiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ namespace Money.Services
public class ApiClient
{
private readonly ApiClientConfiguration configuration;
private readonly ApiVersionChecker versionChecker;
private readonly HttpClient http;
private readonly CommandMapper commandMapper;
private readonly QueryMapper queryMapper;
Expand All @@ -29,9 +30,10 @@ public class ApiClient
private readonly ILog log;
private readonly Json json;

public ApiClient(IOptions<ApiClientConfiguration> configuration, HttpClient http, CommandMapper commandMapper, QueryMapper queryMapper, IExceptionHandler exceptionHandler, ApiAuthenticationStateProvider authenticationState, ILogFactory logFactory, Json json)
public ApiClient(IOptions<ApiClientConfiguration> configuration, ApiVersionChecker versionChecker, HttpClient http, CommandMapper commandMapper, QueryMapper queryMapper, IExceptionHandler exceptionHandler, ApiAuthenticationStateProvider authenticationState, ILogFactory logFactory, Json json)
{
Ensure.NotNull(configuration, "configuration");
Ensure.NotNull(versionChecker, "versionChecker");
Ensure.NotNull(http, "http");
Ensure.NotNull(commandMapper, "commandMapper");
Ensure.NotNull(queryMapper, "queryMapper");
Expand All @@ -40,6 +42,7 @@ public ApiClient(IOptions<ApiClientConfiguration> configuration, HttpClient http
Ensure.NotNull(logFactory, "logFactory");
Ensure.NotNull(json, "json");
this.configuration = configuration.Value;
this.versionChecker = versionChecker;
this.http = http;
this.commandMapper = commandMapper;
this.queryMapper = queryMapper;
Expand All @@ -61,8 +64,20 @@ private HttpContent CreateJsonContent<T>(T request)
private static StringContent CreateStringContent(string requestContent)
=> new StringContent(requestContent, Encoding.UTF8, "text/json");

private async Task EnsureStatusCodeAsync(HttpResponseMessage responseMessage)
private async Task EnsureSuccessResponseAsync(HttpResponseMessage responseMessage)
{
log.Debug($"Api headers: '{responseMessage.Headers}'.");

if (responseMessage.Headers.TryGetValues(VersionHeader.Name, out var versions))
{
var rawVersion = versions.FirstOrDefault();

log.Debug($"ApiVersion is '{rawVersion}'.");

if (!String.IsNullOrEmpty(rawVersion) && Version.TryParse(rawVersion, out var version))
versionChecker.Ensure(version);
}

if (responseMessage.StatusCode == HttpStatusCode.OK)
{
return;
Expand All @@ -84,11 +99,11 @@ private async Task EnsureStatusCodeAsync(HttpResponseMessage responseMessage)

private async Task<T> ReadJsonResponseAsync<T>(HttpResponseMessage responseMessage)
{
await EnsureSuccessResponseAsync(responseMessage);

string responseContent = await responseMessage.Content.ReadAsStringAsync();
log.Debug($"Response: '{responseContent}'.");

await EnsureStatusCodeAsync(responseMessage);

T response = json.Deserialize<T>(responseContent);
return response;
}
Expand Down Expand Up @@ -159,7 +174,7 @@ public async Task CommandAsync(Type type, string payload)
try
{
HttpResponseMessage responseMessage = await PostToUniformApiAsync(commandMapper, "/api/command", type, payload);
await EnsureStatusCodeAsync(responseMessage);
await EnsureSuccessResponseAsync(responseMessage);
}
catch (Exception e)
{
Expand Down
24 changes: 24 additions & 0 deletions src/Money.UI.Blazor/Services/ApiVersionChecker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Money.Services
{
public class ApiVersionChecker
{
public bool IsPassed(Version version)
{
// TODO: Check for compatibility.
return false;
}

public void Ensure(Version version)
{
if (!IsPassed(version))
throw new NotSupportedApiVersionException(version);
}
}
}
40 changes: 40 additions & 0 deletions src/Money.UI.Blazor/Services/NotSupportedApiVersionException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using Neptuo;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;

namespace Money.Services
{
/// <summary>
/// Exception raised when server API is not supported by the current client version.
/// </summary>
[Serializable]
public class NotSupportedApiVersionException : Exception
{
public Version ApiVersion { get; }

/// <summary>
/// Creates a new instance with server api version.
/// </summary>
/// <param name="apiVersion">The server API version.</param>
public NotSupportedApiVersionException(Version apiVersion)
: base($"Server API version is 'v{apiVersion}' which is not support by current client version.")
{
Ensure.NotNull(apiVersion, "apiVersion");
ApiVersion = apiVersion;
}

/// <summary>
/// Creates new instance for deserialization.
/// </summary>
/// <param name="info">The serialization info.</param>
/// <param name="context">The streaming context.</param>
protected NotSupportedApiVersionException(SerializationInfo info, StreamingContext context)
: base(info, context)
{ }
}
}

0 comments on commit b350cb0

Please sign in to comment.