feat(apiv2): basic error handling

This commit is contained in:
spiral 2021-10-12 03:01:02 -04:00
parent 9bafc732ab
commit 9d47bfe0d8
No known key found for this signature in database
GPG Key ID: A6059F0CA0E1BD31
3 changed files with 82 additions and 3 deletions

51
PluralKit.API/Errors.cs Normal file
View File

@ -0,0 +1,51 @@
using System;
using Newtonsoft.Json.Linq;
namespace PluralKit.API
{
public class PKError: Exception
{
public int ResponseCode { get; init; }
public int JsonCode { get; init; }
public PKError(int code, int json_code, string message) : base(message)
{
ResponseCode = code;
JsonCode = json_code;
}
public JObject ToJson()
{
var j = new JObject();
j.Add("message", this.Message);
j.Add("code", this.JsonCode);
return j;
}
}
public class ModelParseError: PKError
{
public ModelParseError() : base(400, 0, "Error parsing JSON model")
{
// todo
}
public new JObject ToJson()
{
var j = base.ToJson();
return j;
}
}
public static class APIErrors
{
public static PKError GenericBadRequest = new(400, 0, "400: Bad Request");
public static PKError SystemNotFound = new(404, 20001, "System not found.");
public static PKError MemberNotFound = new(404, 20002, "Member not found.");
public static PKError GroupNotFound = new(404, 20003, "Group not found.");
public static PKError UnauthorizedMemberList = new(403, 30001, "Unauthorized to view member list");
public static PKError UnauthorizedGroupList = new(403, 30002, "Unauthorized to view group list");
public static PKError Unimplemented = new(501, 50001, "Unimplemented");
}
}

View File

@ -7,7 +7,9 @@ using Autofac;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Versioning;
using Microsoft.Extensions.Configuration;
@ -15,6 +17,10 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json;
using Serilog;
using PluralKit.Core;
namespace PluralKit.API
@ -91,7 +97,7 @@ namespace PluralKit.API
builder.RegisterInstance(InitUtils.BuildConfiguration(Environment.GetCommandLineArgs()).Build())
.As<IConfiguration>();
builder.RegisterModule(new ConfigModule<ApiConfig>("API"));
builder.RegisterModule(new LoggingModule("api"));
builder.RegisterModule(new LoggingModule("api", cfg: new LoggerConfiguration().Filter.ByExcluding(exc => exc.Exception is PKError)));
builder.RegisterModule(new MetricsModule("API"));
builder.RegisterModule<DataStoreModule>();
builder.RegisterModule<APIModule>();
@ -124,6 +130,23 @@ namespace PluralKit.API
return next();
});
app.UseExceptionHandler(handler => handler.Run(async ctx =>
{
var exc = ctx.Features.Get<IExceptionHandlerPathFeature>();
if (exc.Error is not PKError)
{
ctx.Response.StatusCode = 500;
await ctx.Response.WriteAsync("{\"message\":\"500: Internal Server Error\",\"code\":0}");
return;
}
var err = (PKError)exc.Error;
ctx.Response.StatusCode = err.ResponseCode;
var json = JsonConvert.SerializeObject(err.ToJson());
await ctx.Response.WriteAsync(json);
}));
app.UseMiddleware<AuthorizationTokenHandlerMiddleware>();
//app.UseHttpsRedirection();

View File

@ -17,11 +17,13 @@ namespace PluralKit.Core
{
private readonly string _component;
private readonly Action<LoggerConfiguration> _fn;
private LoggerConfiguration _cfg { get; init; }
public LoggingModule(string component, Action<LoggerConfiguration> fn = null)
public LoggingModule(string component, Action<LoggerConfiguration> fn = null, LoggerConfiguration cfg = null)
{
_component = component;
_fn = fn ?? (_ => { });
_cfg = cfg ?? new LoggerConfiguration();
}
protected override void Load(ContainerBuilder builder)
@ -44,7 +46,7 @@ namespace PluralKit.Core
var consoleTemplate = "[{Timestamp:HH:mm:ss.fff}] {Level:u3} {Message:lj}{NewLine}{Exception}";
var outputTemplate = "[{Timestamp:yyyy-MM-dd HH:mm:ss.ffffff}] {Level:u3} {Message:lj}{NewLine}{Exception}";
var logCfg = new LoggerConfiguration()
var logCfg = _cfg
.Enrich.FromLogContext()
.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb)
.Enrich.WithProperty("Component", _component)
@ -53,6 +55,9 @@ namespace PluralKit.Core
// Don't want App.Metrics/D#+ spam
.MinimumLevel.Override("App.Metrics", LogEventLevel.Information)
// nor ASP.NET spam
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
// Actual formatting for these is handled in ScalarFormatting
.Destructure.AsScalar<SystemId>()
.Destructure.AsScalar<MemberId>()