Alex's Coding Blog
  • Home
  • About
  • Projects
  • Contact me

Blog

How to format response data for your Web API in ASP.NET Core

  • March 28, 2020 March 29, 2020
  • by Alexander

When we develop API, we develop a user interface. Like any modern user interface, it should have a certain level of usability. Front-end developers, in most cases, your API users, should be able to work with and get proper responses. There is no industry standard or perfect response, each of us is having own vision of what to return and when.

I'm facing projects which were developed for decades, and in most cases, several different people or teams worked on it during this time. Different people - different coding styles, approaches, and understanding. In my opinion, It doesn't matter how you going to design your API responses, more important is to be consistent in your project. Consistency might help you not only avoid a coding mess but also speed up front-end development and new developers' onboarding process.

In this post, I going to share my opinion about the topic.

I would like to highlight a few usability topics each API should have:

  • It should be fast - it should be fast enough.
  • State - A developer should be aware of what happens and why.
  • Documentation - Industry-standard especially when API is shipped.

Speed

No one these days will wait for your API response. The threshold of 500-1000ms will be a good starting point. There is a variety of ways to measure execution time for your API, including saas and pass solutions.

State

It should be represented by a proper HTTP code. There are several common that can cover 95% of responses:

401

Authorization error. Addresses any problem related to tokens and token expiration. In .net world implemented with controller's/action's Authorize attribute.

400

Validation errors. Requests should must be validated and Bad Request is the correct response to notify the developer that his request is wrong.

404

Not found.

500

Server error. Addresses errors happen during the execution. You choose what details to show the world: It can be an error message as it comes from the data access layer or something generic that doesn't expose the details (more secure way).

20x

200 for ok or 201 for created as successful completion of the request.

Documentation

OpenAPI format is a great way to generate documentation for your API and swagger is the easy way to implement it, especially with XML comments. Don't forget to switch swagger off when going to production.

The problem with documentation is that there is always not enough documentation. Try to get feedback from your API clients, usually a front-end team and add the missing parts.

The response data

In my previous GetInfra WebApi Abstractions introduction, I introduced the library I use for POST, PUT and DELETE methods.

Let's take as an example simple post request handling:

[HttpPost]
public async Task<ActionResult<GenericResponse<string>>> Post(SomeRequest request)
{

    // validate 
    var r = await _someValidator.ValidateAsync(request);
    // convert to generic response
    var result = r.ToGenericResponse<string>();

    if (!result.IsValid)
        // return 400
        return BadRequest(result);

    try
    {
        // service call
        result = await _someService.CreateAsync(request);
        // return 201
        return Created(new Uri($"https://some.domain-com/path/{result.Id}"), result);
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "POST error: {0}, stack:", ex.Message, ex.StackTrace);
        result.Errors.Add(new ErrorItem(ex.Message, ex.StackTrace));
        // return 500
        return StatusCode(500, result);
    }

}

As a first step, it validates if the request is ok and we can work with it. I use IValidator<T> from GetInfra.WebApi.Abstractions for interface and abstractions with my custom SomeRequestValidator implementation to validate the request. I will provide a detailed review of request validation in my next posts. In case of a validation error, it will return status 400 along with validation error(s).

The second step is the actual call for business logic data access chain, which in case the error will be handled with try..catch statement, will log and return 500 status.

Finally, if everything goes smooth it will return status 201 with newly generated id (as an example below):

{
    "succeeded": true,
    "id": "11111111",
    "errors": [],
    "valiationErrors": [],
    "isValid": true
}

If you like my approach, you can install the NuGet package:

Install-Package GetInfra.WebApi.Abstractions

If you don't please tell me why.

The example project can be found on github

Happy coding and stay safe!

.NET Core How-to

Debugging microservices is always tricky and time consuming specially without proper code level logging in place.

Meet Konso. It's developed as a solution for this challenge and can help with saving development effort for your team up to 30%. 🎯🎉

The key functions are:

🔥 Centralized logging for your microservices
🔥 Tracing with metrics and value tracking events
🔥 Ad-Hoc events exploration
🔥 Saving your queries
🔥 Create alerts and get notified


You can start collecting you project's logs in 5 minutes. 🕐💪

To Learn more about logging tool, book a free demo.
To get started for free, Create your free account now

Alexander Lvovich

Solution Architect and Software Developer.

Share on:

No comments are allowed for this post

Recent Posts

  • Easily track and troubleshoot errors in your .NET 7 web app using Konso's logging feature
  • How to disable object model validation .NET 7
  • Keep Your Passwords Safe: 5 Tips for Protecting Yourself After the Latest LastPass Data Breach
  • How to ping from .net application container
  • Freelancing myths you should consider before dive in
  • How to set up a honey token for dotnet project with Konso

Categories

  • Azure
  • Architecture
  • .NET Core
  • Certification
  • DevOps
  • How-to
  • Azure Functions
  • Serverless
  • Cosmos DB
  • Security
  • Thoughts
© Copyright 2023, Alexander Lvovich. Theme by Colorlib