2021-12-01 13:23:44 +01:00
|
|
|
using Microsoft.AspNetCore.Http;
|
2021-12-14 01:23:03 +01:00
|
|
|
using Microsoft.AspNetCore.Http.Extensions;
|
2021-12-01 13:23:44 +01:00
|
|
|
using Microsoft.AspNetCore.Mvc;
|
2021-11-30 14:32:10 +01:00
|
|
|
using Microsoft.AspNetCore.Mvc.Filters;
|
|
|
|
|
|
|
|
|
|
namespace zero.Api.Filters;
|
|
|
|
|
|
|
|
|
|
public class ApiResponseFilterAttribute : ResultFilterAttribute
|
|
|
|
|
{
|
|
|
|
|
public override void OnResultExecuting(ResultExecutingContext context)
|
|
|
|
|
{
|
2021-12-13 16:11:52 +01:00
|
|
|
if (context.Result is ObjectResult result)
|
2021-11-30 14:32:10 +01:00
|
|
|
{
|
2021-12-14 01:23:03 +01:00
|
|
|
// format paged results
|
2021-12-13 16:11:52 +01:00
|
|
|
if (result.Value is Paged paged)
|
2021-11-30 14:32:10 +01:00
|
|
|
{
|
2021-12-14 01:23:03 +01:00
|
|
|
result.Value = new PagedDataApiResponse()
|
|
|
|
|
{
|
|
|
|
|
Success = true,
|
|
|
|
|
Status = result.StatusCode.Value,
|
2021-12-14 11:54:36 +01:00
|
|
|
Paging = new()
|
|
|
|
|
{
|
|
|
|
|
Page = paged.Page,
|
|
|
|
|
PageSize = paged.PageSize,
|
|
|
|
|
TotalPages = paged.TotalPages,
|
|
|
|
|
TotalItems = paged.TotalItems
|
|
|
|
|
},
|
2021-12-14 01:23:03 +01:00
|
|
|
Data = paged.GetItems()
|
|
|
|
|
};
|
2021-11-30 14:32:10 +01:00
|
|
|
}
|
2021-12-13 16:11:52 +01:00
|
|
|
|
2021-12-14 01:23:03 +01:00
|
|
|
// format patch results
|
2021-12-14 11:25:32 +01:00
|
|
|
else if (result.Value is Result model)
|
2021-11-30 14:32:10 +01:00
|
|
|
{
|
2021-12-14 01:23:03 +01:00
|
|
|
ApiResponse response = new DataApiResponse();
|
2021-12-13 16:11:52 +01:00
|
|
|
|
2021-12-14 01:23:03 +01:00
|
|
|
if (!model.IsSuccess)
|
|
|
|
|
{
|
|
|
|
|
response = new ErrorApiResponse()
|
|
|
|
|
{
|
|
|
|
|
Errors = model.Errors.Select(x => new ErrorApiResponseError()
|
|
|
|
|
{
|
|
|
|
|
Category = ApiErrorCodes.Categories.Validation,
|
|
|
|
|
Code = "// TODO",
|
|
|
|
|
Property = x.Property,
|
|
|
|
|
Message = x.Message
|
|
|
|
|
}).ToList()
|
2021-12-14 11:25:32 +01:00
|
|
|
};
|
2021-12-14 01:23:03 +01:00
|
|
|
}
|
|
|
|
|
else if (context.HttpContext.Items.TryGetValue(ApiConstants.ChangeToken, out object tokenObj) && tokenObj is string token)
|
|
|
|
|
{
|
2021-12-14 11:25:32 +01:00
|
|
|
response = new TokenizedDataApiResponse()
|
|
|
|
|
{
|
2021-12-14 01:23:03 +01:00
|
|
|
Data = model.GetModel(),
|
2021-12-14 11:25:32 +01:00
|
|
|
ChangeToken = token
|
2021-12-14 01:23:03 +01:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
response = new DataApiResponse()
|
|
|
|
|
{
|
|
|
|
|
Data = model.GetModel()
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
response.Success = model.IsSuccess;
|
2021-12-14 11:25:32 +01:00
|
|
|
response.Status = !model.IsSuccess ? StatusCodes.Status400BadRequest : result.StatusCode.Value;
|
2021-12-14 01:23:03 +01:00
|
|
|
|
|
|
|
|
result.StatusCode = response.Status;
|
|
|
|
|
result.Value = response;
|
2021-12-13 16:11:52 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-16 16:59:27 +01:00
|
|
|
// format bulk patch results
|
|
|
|
|
else if (result.Value is IEnumerable<Result<string>> list)
|
|
|
|
|
{
|
|
|
|
|
int countSucceeded = list.Count(x => x.IsSuccess);
|
|
|
|
|
int countFailed = list.Count() - countSucceeded;
|
|
|
|
|
|
|
|
|
|
BulkOperationApiResponse response = countFailed > 0 ? new BulkOperationWithErrorsApiResponse() : new BulkOperationApiResponse();
|
|
|
|
|
|
|
|
|
|
response.CountSucceeded = countSucceeded;
|
|
|
|
|
response.CountFailed = countFailed;
|
|
|
|
|
|
|
|
|
|
if (countFailed > 0 && response is BulkOperationWithErrorsApiResponse errorResponse)
|
|
|
|
|
{
|
|
|
|
|
errorResponse.Errors = list.Where(x => !x.IsSuccess).SelectMany(x => x.Errors.Select(e => new BulkOperationErrorApiResponseError()
|
|
|
|
|
{
|
|
|
|
|
AffectedId = x.Model,
|
|
|
|
|
Category = ApiErrorCodes.Categories.Validation,
|
|
|
|
|
Code = "// TODO",
|
|
|
|
|
Property = e.Property,
|
|
|
|
|
Message = e.Message
|
|
|
|
|
})).ToList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
response.Success = countSucceeded > 0;
|
|
|
|
|
response.Status = countSucceeded < 1 ? StatusCodes.Status400BadRequest : result.StatusCode.Value;
|
|
|
|
|
result.StatusCode = response.Status;
|
|
|
|
|
result.Value = response;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-14 11:25:32 +01:00
|
|
|
// format model results
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
DataApiResponse response = new();
|
|
|
|
|
|
|
|
|
|
if (context.HttpContext.Items.TryGetValue(ApiConstants.ChangeToken, out object tokenObj) && tokenObj is string token)
|
|
|
|
|
{
|
|
|
|
|
response = new TokenizedDataApiResponse() { ChangeToken = token };
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-14 11:54:36 +01:00
|
|
|
response.Success = result.StatusCode.Value >= 200 && result.StatusCode.Value <= 299;
|
2021-12-14 11:25:32 +01:00
|
|
|
response.Status = result.StatusCode.Value;
|
|
|
|
|
response.Data = result.Value;
|
|
|
|
|
result.Value = response;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-14 01:23:03 +01:00
|
|
|
// append metadata
|
2021-12-13 16:11:52 +01:00
|
|
|
if (result.Value is ApiResponse apiResponse)
|
|
|
|
|
{
|
|
|
|
|
apiResponse.Metadata = GetMetadata(context);
|
2021-12-14 11:25:32 +01:00
|
|
|
context.HttpContext.Response.Headers["X-Variant"] = "api-response";
|
2021-11-30 14:32:10 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-12-13 16:11:52 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
ApiResponseMetadata GetMetadata(ResultExecutingContext context)
|
|
|
|
|
{
|
2021-12-18 16:24:07 +01:00
|
|
|
if (!context.HttpContext.Items.ContainsKey("zero.action.started"))
|
|
|
|
|
{
|
|
|
|
|
return new();
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-13 16:11:52 +01:00
|
|
|
DateTimeOffset started = (DateTimeOffset)context.HttpContext.Items["zero.action.started"];
|
|
|
|
|
TimeSpan duration = DateTimeOffset.Now - started;
|
|
|
|
|
|
|
|
|
|
return new()
|
|
|
|
|
{
|
|
|
|
|
Duration = duration,
|
|
|
|
|
RequestDate = started
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//if (context.Result is ObjectResult result && result.StatusCode.HasValue)
|
|
|
|
|
//{
|
|
|
|
|
// if (typeof(ZeroIdEntity).IsAssignableFrom(result.DeclaredType))
|
|
|
|
|
// {
|
|
|
|
|
// result.Value = new ModelApiResponse()
|
|
|
|
|
// {
|
|
|
|
|
// Model = result.Value,
|
|
|
|
|
// Success = true,
|
|
|
|
|
// Status = result.StatusCode.Value,
|
|
|
|
|
// ChangeToken = context.HttpContext.Items[ApiConstants.ChangeToken] as string,
|
|
|
|
|
// Metadata = new ModelApiResponseMetadata()
|
|
|
|
|
// {
|
|
|
|
|
// RequestDate = started,
|
|
|
|
|
// Duration = duration,
|
|
|
|
|
// Token = IdGenerator.Create(32)
|
|
|
|
|
// }
|
|
|
|
|
// };
|
|
|
|
|
// }
|
|
|
|
|
// else if (typeof(Paged).IsAssignableFrom(result.DeclaredType))
|
|
|
|
|
// {
|
|
|
|
|
// Paged paged = result.Value as Paged;
|
|
|
|
|
// result.Value = new PagedApiResponse()
|
|
|
|
|
// {
|
|
|
|
|
// Items = paged.GetItems(),
|
|
|
|
|
// Paging = new()
|
|
|
|
|
// {
|
|
|
|
|
// Page = paged.Page,
|
|
|
|
|
// PageSize = paged.PageSize,
|
|
|
|
|
// TotalItems = paged.TotalItems,
|
|
|
|
|
// TotalPages = paged.TotalPages,
|
|
|
|
|
// HasMore = paged.HasMore
|
|
|
|
|
// },
|
|
|
|
|
// Success = true,
|
|
|
|
|
// Status = result.StatusCode.Value,
|
|
|
|
|
// Metadata = new ModelApiResponseMetadata()
|
|
|
|
|
// {
|
|
|
|
|
// RequestDate = started,
|
|
|
|
|
// Duration = duration,
|
|
|
|
|
// Token = IdGenerator.Create(32)
|
|
|
|
|
// }
|
|
|
|
|
// };
|
|
|
|
|
// }
|
|
|
|
|
//}
|
2021-11-30 14:32:10 +01:00
|
|
|
}
|