Skip to content

Instantly share code, notes, and snippets.

@Tomas-Juri
Created March 5, 2024 11:14
Show Gist options
  • Save Tomas-Juri/aaacabb4d098ea3483aac129d7bda2ff to your computer and use it in GitHub Desktop.
Save Tomas-Juri/aaacabb4d098ea3483aac129d7bda2ff to your computer and use it in GitHub Desktop.
Blazor WASM Api response handling
using System.Net;
using System.Net.Http.Json;
namespace Frontend.Shared.Services;
public sealed class HttpClientService
{
private readonly HttpClient _httpClient;
public HttpClientService(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<Response<T>> GetAsync<T>(string requestUri)
{
var response = await _httpClient.GetAsync(requestUri);
var message = await response.Content.ReadAsStringAsync();
return response.StatusCode switch
{
HttpStatusCode.OK => Response<T>.Ok((await response.Content.ReadFromJsonAsync<T>())!),
HttpStatusCode.NotFound => Response<T>.NotFound(!string.IsNullOrEmpty(message)
? message
: "This page could not be found!"),
HttpStatusCode.Forbidden => Response<T>.UnAuthorized(!string.IsNullOrEmpty(message)
? message
: "You have no permissions to see this page!"),
_ => Response<T>.Error(!string.IsNullOrEmpty(message) ? message : "Something went wrong.")
};
}
// PUT, POST and other methods can be implemented in similar way (use Unit instead of void)
}
namespace Frontend.Shared;
public abstract record Response<T>
{
public static NotFoundResponse<T> NotFound(string message) => new() { ErrorMessage = message };
public static UnauthorizedResponse<T> Unauthorized(string message) => new() { ErrorMessage = message };
public static ForbiddenResponse<T> Forbidden(string message) => new() { ErrorMessage = message };
public static ErrorResponse<T> Error(string message) => new() { ErrorMessage = message };
public static SuccessResponse<T> Ok(T data) => new() { Data = data };
}
public record ErrorResponse<T> : Response<T>
{
public required string ErrorMessage { get; init; }
}
public sealed record NotFoundResponse<T> : ErrorResponse<T>;
public sealed record UnauthorizedResponse<T> : ErrorResponse<T>;
public sealed record ForbiddenResponse<T> : ErrorResponse<T>;
public sealed record SuccessResponse<T> : Response<T>
{
public required T Data { get; init; }
}
@using Button = Frontend.Components.Ant.General.Button
@using Frontend.Shared
@typeparam T
@* This example uses custom AntDesign components *@
@switch (Response)
{
case NotFoundResponse<T> notFound:
<Result Variant="Result.ResultVariant.NotFound" Title="Data not found" Text="@notFound.ErrorMessage"/>
break;
case UnauthorizedResponse<T> unauthorized:
<Result Variant="Result.ResultVariant.Unauthorized" Title="You're not authorized to see this" Text="@unauthorized.ErrorMessage"/>
break;
case ErrorResponse<T> error:
<Result Variant="Result.ResultVariant.Error" Title="An Error happened while loading data" Text="@error.ErrorMessage">
<Actions>
<Button
Variant="Button.ButtonVariant.Primary"
Size="Button.ButtonSize.Default"
OnClick="OnRefresh"
Text="Refresh"/>
</Actions>
</Result>
break;
case SuccessResponse<T>:
@ChildContent
break;
}
using Frontend.Shared;
using Microsoft.AspNetCore.Components;
namespace Frontend.Components.Organisms;
public partial class ResponseDisplay<T>
{
[Inject]
public required NavigationManager NavigationManager { get; set; }
[Parameter]
[EditorRequired]
public required Response<T> Response { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
private void OnRefresh()
{
NavigationManager.NavigateTo(NavigationManager.Uri, true);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment