QERP.Response 1.5.2

dotnet add package QERP.Response --version 1.5.2
                    
NuGet\Install-Package QERP.Response -Version 1.5.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="QERP.Response" Version="1.5.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="QERP.Response" Version="1.5.2" />
                    
Directory.Packages.props
<PackageReference Include="QERP.Response" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add QERP.Response --version 1.5.2
                    
#r "nuget: QERP.Response, 1.5.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package QERP.Response@1.5.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=QERP.Response&version=1.5.2
                    
Install as a Cake Addin
#tool nuget:?package=QERP.Response&version=1.5.2
                    
Install as a Cake Tool

Qerp.QERP.Response

Standardized API response package for ASP.NET Core with built-in global exception handler middleware and message management. Provides consistent response models, typed exceptions, W3C TraceId/SpanId correlation, application-level response codes, EF Core message lookup, optional Redis caching, and CRUD operations for response messages.

Features

  • Fluent builder pattern -- configure with AddStructuredResponse(api => api.UsePostgreSql(...).UseRedis(...).UseMessageManagement(...))
  • Simple response model -- ApiResponse<T> generic wrapper for any data type with a Status flag.
  • Global exception handler -- middleware catches all unhandled exceptions and returns standardized error responses
  • Built-in exception types -- NotFoundException, BadRequestException, ValidationException, UnauthorizedException, ForbiddenException, ConflictException, and ServiceUnavailableException
  • Message management -- opt-in CRUD service for response messages (Seed, Add, Edit, Activate, Deactivate, List)
  • W3C Trace Context -- automatic TraceId and SpanId from OpenTelemetry activities
  • Application response codes -- categorized enum (MessageCode) with ranges for Success, Client Errors, Auth Errors, and Server Errors
  • Database-driven messages -- response messages stored in PostgreSQL via EF Core
  • Optional Redis caching -- cache-aside pattern with automatic invalidation on mutations
  • Read/write DB separation -- read connection for queries, write connection for management
  • Auto-seed -- database is automatically seeded with default messages when message management is enabled
  • Audit trail -- all entities inherit AuditEntity with CreatedBy, CreatedAt, UpdatedBy, UpdatedAt
  • Multi-target -- supports net8.0, net9.0, and net10.0

Installation

dotnet add package QERP.Response

Quick Start

1. Register Services and Middleware

using QERP.Response.Extensions;

// Minimal (read-only DB, no Redis, no management)
builder.Services.AddStructuredResponse(api => api
    .UsePostgreSql("Host=localhost;Database=qerp;Username=postgres;Password=secret")
);

// Full (management + auto-seed + Redis)
builder.Services.AddStructuredResponse(api => api
    .UsePostgreSql("Host=read-replica;Database=qerp;...")
    .UseRedis("localhost:6379")
    .UseMessageManagement("Host=primary;Database=qerp;...")
);

var app = builder.Build();

app.UseStructuredResponse();  // registers exception handler and request logging

2. Use the Response Factory

using QERP.Response.Builders;
using QERP.Response.Enums;
using QERP.Response.Exceptions;

// --- Example 1: Success with default code (0 - Success) ---
app.MapGet("/api/products/{id}", async (int id, ResponseFactory response) =>
{
    var product = await productService.GetByIdAsync(id);
    if (product is null) throw new NotFoundException();

    var result = await response.SuccessAsync(product);
    return Results.Ok(result);
});

// --- Example 2: Success with custom code (1 - Created) ---
app.MapPost("/api/products", async (Product product, ResponseFactory response) =>
{
    await productService.AddAsync(product);
    var result = await response.SuccessAsync(product, MessageCode.Created);
    return Results.Json(result, statusCode: 201);
});

// --- Example 3: Manual failure with custom errors ---
app.MapPost("/api/validate", async (ValidateRequest req, ResponseFactory response) =>
{
    if (string.IsNullOrEmpty(req.Name))
    {
        var errors = new List<string> { "Name is required for validation." };
        var result = await response.FailAsync<object>(MessageCode.ValidationError, errors);
        return Results.BadRequest(result);
    }

    return Results.Ok(await response.SuccessAsync(new { Valid = true }));
});

3. Response Output

Success:

{
  "status": true,
  "code": 0,
  "traceId": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
  "spanId": "1a2b3c4d5e6f7a8b",
  "timestamp": "2026-03-03T14:10:00Z",
  "message": "Operation completed successfully.",
  "data": {
    "id": 1,
    "name": "Laptop",
    "price": 1299.99
  }
}

Exception (handled by middleware):

{
  "status": false,
  "code": 102,
  "traceId": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
  "spanId": "1a2b3c4d5e6f7a8b",
  "timestamp": "2026-03-03T14:10:05Z",
  "message": "The requested resource was not found.",
  "errors": ["Product 123 was not found."],
  "data": null
}

Builder Configuration

Method Required Description
.UsePostgreSql(readConn) Yes Read-only DB connection for message queries.
.UseRedis(conn) No Redis connection for caching. Without it, queries hit DB directly.
.UseMessageManagement(writeConn) No Enables CRUD management service + auto-seed. Requires write-capable DB connection.

Factory Methods

Inject ResponseFactory to create responses manually:

await response.SuccessAsync(data);
await response.SuccessAsync(data, MessageCode.Created);
await response.FailAsync<Product>(MessageCode.NotFound);
await response.FailAsync<Product>(MessageCode.NotFound, errors);

Message Management Service

Available when .UseMessageManagement(writeConn) is configured. Inject IApplicationMessageManagementService:

using QERP.Response.Services;
using QERP.Response.Models;

app.MapGet("/api/messages", async (IApplicationMessageManagementService mgmt) =>
{
    var messages = await mgmt.ListAsync();
    return Results.Ok(messages);
});

app.MapPost("/api/messages", async (MessageRequest req, IApplicationMessageManagementService mgmt) =>
{
    var created = await mgmt.AddAsync(req);
    return Results.Created($"/api/messages/{created.Id}", created);
});
Method Description
SeedAsync() Seeds default messages for all response codes (skips if already seeded)
AddAsync(request) Creates a new response message
EditAsync(id, request) Updates an existing message by ID
ActivateAsync(id) Sets IsActive = true
DeactivateAsync(id) Sets IsActive = false
ListAsync() Returns all messages ordered by message code

Built-in Exception Types

Throw these anywhere in your code -- the middleware catches them and returns the correct HTTP status with a standardized ApiResponse model:

Exception HTTP Status Default Mapping (MessageCode)
BadRequestException 400 BadRequest (100)
UnauthorizedException 401 AuthenticationFailed (200)
ForbiddenException 403 AuthorizationFailed (201)
NotFoundException 404 NotFound (102)
ConflictException 409 Conflict (103)
ValidationException 422 ValidationError (101)
ServiceUnavailableException 503 ServiceUnavailable (301)
Any other exception 500 InternalError (300)

Custom Exceptions

You can throw BaseException directly for custom HTTP status codes:

throw new BaseException("Rate limit exceeded", HttpStatusCode.TooManyRequests);

Message Codes (MessageCode)

Range Category Examples
0-99 Success Success(0), Created(1), Updated(2), Deleted(3)
100-199 Client Error BadRequest(100), ValidationError(101), NotFound(102)
200-299 Auth Error AuthenticationFailed(200), AuthorizationFailed(201)
300-399 Server Error InternalError(300), ServiceUnavailable(301)

Detailed Demo

For a full demo application, see the tests/response-pkg.app project. It includes:

  1. Program.cs: Full configuration with PostgreSQL, Redis, and Logging.
  2. ProductsController: Real-world CRUD examples using ResponseFactory.
  3. TestController: Demonstration of all built-in exception types.
  4. MessagesController: CRUD operations for managing response messages in the database.

Running the Demo

  1. Configure the connection strings in appsettings.json.
  2. Run the project: dotnet run --project tests/response-pkg.app.
  3. Use the response-pkg.app.http file to test endpoints.

License

This project is licensed under the MIT License. See the LICENSE file for details.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.5.2 130 5/5/2026
1.5.1 149 4/13/2026
1.5.0 110 4/13/2026
1.4.0 272 3/24/2026
1.3.0 116 2/28/2026