Treatment of generic responses in the Web API using net core

Alegria Kilanda
5 min readAug 26, 2023

In software development when we talk about productivity, there’s no way we can’t talk about generics. In this article I present one of the ways to handle responses of a web api in a generic way using .Net Core.

1 — Creating the generic structure

First starts by creating a enum called EResponse, within it we define all kinds of responses that our web API will have.

 public enum EResponse
{
OK = 200,
Created =201,
Accepted = 202,
BadRequest = 400,
Unauthorized = 401,
PaymentRequired = 402,
Forbidden = 403,
NotFound = 404,
InternalServerError = 500
}

Next we create a class called ResponseException, within it we have.

public class ResponseException: Exception
{
public EResponse Code { get; set; }

public ResponseException(EResponse code, string message) :base(message)
{
Code = code;
}
}

Now we are going to create a class called RequestResponse, we are using as auxiliary class

internal static class RequestResponse
{
public static void UnSuccess(string message)
{
ExceptionResponse(EResponse.BadRequest, message);
}
public static void UnSuccess(bool condition, string message = null)
{
if (condition)
UnSuccess(message);
}

public static void NotAuthorized(string message = "")
{
ExceptionResponse(EResponse.Unauthorized, message);
}

public static void CheckingAuthorize(bool condition, string message = "")
{
if (condition)
NotAuthorized(message);
}

private static void ExceptionResponse(EResponse response, string message)
{
throw new ResponseException(response, message);
}
}

Now we are going to create our main classe, called HandleRequestResponse, in this classe we define how we want to treat the response of our API, in our case we define like this:

[AttributeUsage(AttributeTargets.Method)]
public class HandleRequestResponse : ActionFilterAttribute
{
public ETypeRequestResponse TypeResponse { get; set; }

/// <summary>
/// After a resquest
/// </summary>
/// <param name="context"></param>
public override void OnActionExecuted(ActionExecutedContext context)
{
if (context.Exception is null)
{
object valueResult = null;

if (context.Result is OkObjectResult objectResult)
valueResult = objectResult.Value;

if (TypeResponse == ETypeRequestResponse.ResponseWithData)
{
if (!IsValue(valueResult))
context.Result = new NotFoundResult();
}
}
else if (context.Exception is ResponseException exceptionResponse)
{
context.Result = Handled(exceptionResponse);
context.ExceptionHandled = true;
}
else
{
context.Result = new InternalServerErrorObjectResult();
context.ExceptionHandled = true;
}

base.OnActionExecuted(context);
}

private static IActionResult Handled(ResponseException exceptionResponse)
{
string message = string.IsNullOrWhiteSpace(exceptionResponse.Message) ? string.Empty : exceptionResponse.Message;

switch (exceptionResponse.Code)
{
case EResponse.Accepted:
return new AcceptedResult();
case EResponse.BadRequest:
return new BadRequestObjectResult(message);
case EResponse.Unauthorized:
return new UnauthorizedObjectResult(message);
case EResponse.Forbidden:
return new ForbidResult();
case EResponse.NotFound:
return new NotFoundObjectResult(message);
case EResponse.InternalServerError:
return new InternalServerErrorObjectResult();
}

return new OkResult();
}


/// <summary>
/// Check if is value
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
private static bool IsValue(object value)
{
if (value is null) return false;

if (value is ICollection collection && collection.Count == 0) return false;

return true;
}
}

2 — Using the generic structure

Now that we have finished defining our generic structure, we are going to use it.

We’re going to create a model class called Car:

public class Car
{
/// <summary>
/// Id of Car
/// </summary>
public int Id { get; set; }

/// <summary>
/// Name of Car
/// </summary>
public string Name { get; set; }

/// <summary>
/// Brand of Car
/// </summary>
public string Brand { get; set; }

/// <summary>
/// Price of Car
/// </summary>
public decimal Price { get; set; }

}

We’re going to create a class called the CarApp,

public class CarApp : ICarApp
{
/// <summary>
/// Create a new Car
/// </summary>
/// <param name="car"></param>
public void Create(Car car)
{
RequestResponse.UnSuccess(car == null, "invalid input");
RequestResponse.UnSuccess(string.IsNullOrWhiteSpace(car.Name), "Required Name");
//Created
}

/// <summary>
/// Get cars by name
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public List<Car> GetByName(string name)
{
return carsTestes.Where(c => c.Name.Contains(name)).ToList();
}

private static List<Car> carsTestes = new List<Car>
{
new Car
{
Id = 10,
Name = "Hyundai",
Brand = "i10",
Price = 3000
},
new Car
{
Id = 20,
Name = "Hyundai",
Brand = "i20",
Price = 4000
},
new Car
{
Id = 30,
Name = "Hyundai",
Brand = "Tucson",
Price = 5000
}
};
}

Now we’re going to create our controller, it’s going call CarApp, in each action we use Annotation HandleRequestResponse

[Route("api/[controller]")]
[ApiController]
public class CarController : ControllerBase
{
private readonly ICarApp _carApp;
public CarController(ICarApp carApp)
{
_carApp = carApp;
}

[SwaggerOperation(
Summary = "Car registration",
Description = "All fields are mandatory.")
]
[HttpPost]
[HandleRequestResponse]
public ActionResult Create([FromBody] Car car)
{
_carApp.Create(car);
return Ok();
}

[SwaggerOperation(
Summary = "Listing cars by name",
Description = "the name field is mandatory.")
]
[HttpGet]
[Route("getbyname")]
[HandleRequestResponse(TypeResponse = ETypeRequestResponse.ResponseWithData)]
public ActionResult GetByName(string name)
{
return Ok(_carApp.GetByName(name));
}
}

3 — Result

1 — The route create:

Case 1: It presents a error scenario.

Input
Result

Case 2: It presents a success (200) scenario.

Input
Result

2 — The route getbyname:

Case 1: It presents a not found (404) scenario.

Input
Result

Case 2: It presents a success (200) scenario.

Input
Result

The project is available on github for contributions and improvements.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Responses (1)

Write a response

wher is ETypeRequestResponse commimg ffrom ?

Recommended from Medium

Lists

See more recommendations