SuccessResult
Namespace: RA.Utilities.Api.Mapper
The SuccessResult static class, located in the RA.Utilities.Api package, is a set of helper methods designed to streamline the creation of standardized, successful API responses.
Its primary goals are:
1. Enforce Consistency:
It ensures that every successful response from your API (like a 200 OK or 201 Created) is wrapped in the standard SuccessResponse<T> model from RA.Utilities.Api (namespace RA.Utilities.Api.Response).
This provides a predictable JSON structure (responseCode, responseType, result, etc.) for all your API's success outcomes, which is a mirror to how errors are handled.
2. Reduce Boilerplate:
It provides simple, expressive static methods that are much cleaner to use than manually constructing the response.
For example, writing return SuccessResult.Ok(product); is more concise and readable than return Results.Ok(new SuccessResponse<Product>(product));.
3. Simplify HTTP Compliance:
It offers convenient overloads for common HTTP success statuses (200, 201, 202, 204), handling details like setting the Location header for 201 Created responses automatically.
In short, this class is a key part of the "batteries-included" developer experience, helping you write clean, consistent, and maintainable API endpoints with minimal effort.
Available Helpers
The SuccessResult class provides helpers for the most common success status codes:
Ok(): Creates a200 OKresponse.Ok<T>(T result): Creates a200 OKresponse with a payload.Created(): Creates a201 Createdresponse.Created<T>(T result): Creates a201 Createdresponse with a payload.Created<T>(string uri, T result): Creates a201 Createdresponse with aLocationheader and a payload.CreatedAtRoute<TResult>(string routeName, object routeValues): Creates a201 Createdwith the specified route name and route values.CreatedAtRoute<TResult>(string routeName, object routeValues, TResult results): Creates an HTTP201 Createdresponse with the specified route name, route values, and result.Accepted(): Creates a202 Acceptedresponse.Accepted(string route): Creates a202 Acceptedresponse with aLocationheader.Accepted<TResult>(TResult results): Creates a202 Acceptedresponse with a payload.Accepted<T>(string uri, T result): Creates a202 Acceptedresponse with aLocationheader and a payload.NoContent(): Creates a204 No Contentresponse.
🚀 Usage Guide
You can use these helpers directly in your endpoints to simplify response creation and ensure consistency.
using RA.Utilities.Api.Mapper;
// In an IEndpoint implementation or Minimal API
app.MapGet("/products/{id}", (int id) =>
{
var product = new Product { Id = id, Name = "Sample Product" };
// Instead of this:
// return Results.Ok(new SuccessResponse<Product>(product));
// You can write this:
return SuccessResult.Ok(product);
});
app.MapPost("/products", (Product product) =>
{
// Logic to save the product...
var newProduct = new Product { Id = 123, Name = product.Name };
// Creates a 201 Created response with a Location header and a structured body
return SuccessResult.Created($"/products/{newProduct.Id}", newProduct);
});
A request that returns a product would yield the following JSON body, wrapped in the standard response structure:
{
"responseCode": 200,
"responseType": 0,
"responseMessage": "Operation completed successfully.",
"result": {
"id": 1,
"name": "Sample Product"
}
}
responseType is numeric by default. Register JsonStringEnumConverter to write "Success"; see ResponseType.
Using the Result Type with Endpoints
Step 1: Create a service that returns a Result
Your application or domain layer should return a Result<T> to indicate the outcome of an operation.
// Services/ProductService.cs
using RA.Utilities.Core.Results;
using RA.Utilities.Core.Exceptions;
public class ProductService
{
public Result<Product> GetProductById(int id)
{
if (id <= 0)
{
// Return a failure Result for invalid input
return new BadRequestException("Invalid product ID.");
}
if (id != 1)
{
// Return a failure Result if the product is not found
return new NotFoundException(nameof(Product), id);
}
// Return a success Result with the product
return new Product { Id = id, Name = "Sample Product" };
}
}
Step 2: Use Match in your endpoint to return an IResult
In your IEndpoint implementation, call the service and use the Match method to map the Result to an HTTP response. This pattern forces you to handle both success and failure cases explicitly.
// Features/Products/GetProductByIdEndpoint.cs
using Microsoft.AspNetCore.Routing;
using RA.Utilities.Api.Abstractions;
internal sealed class GetProductByIdEndpoint : IEndpoint
{
public static string GroupName => "Products";
public static void MapEndpoint(RouteGroupBuilder group)
{
group.MapGet("/{id}", (int id, ProductService service) =>
{
Result<Product> result = service.GetProductById(id);
// Match the result to an appropriate HTTP response
return result.Match<IResult>(
// Use the new helper for a clean success response
success: product => SuccessResult.Ok(product),
failure: ErrorResultResponse.Result // Use the error mapper for a consistent failure response
);
});
}
}