Failing at API dev

I just feel like there is a lot of reinventing the wheel going on :)

want validation errors? .NET already supports that nicely.
want to handle unexpected exceptions in your controllers? .NET already provides hooks to handle them and return a consistent response, without handling them in every controller method

True that. I have just found a segment on global error handling. Could probably leave out the whole catch block entirely now.


C#:
public class ExceptionMiddleware
{
    private readonly RequestDelegate next;
    private readonly ILogger<ExceptionMiddleware> _logger;

    public ExceptionMiddleware(RequestDelegate next, ILogger<ExceptionMiddleware> logger)
    {
        this.next = next;
        _logger = logger;
    }

    public async Task Invoke(HttpContext context)
    {
        try
        {
            await next(context);
        }
        catch(Exception ex)
        {
            _logger.LogError(ex, ex.Message);
            context.Response.StatusCode = 500;
            await context.Response.WriteAsync("An unexpected error occurred.  Please try again later.");
        }
    }
}
 
I just feel like there is a lot of reinventing the wheel going on :)

want validation errors? .NET already supports that nicely.
want to handle unexpected exceptions in your controllers? .NET already provides hooks to handle them and return a consistent response, without handling them in every controller method
One of my teams will kill me but I find its most often web/frontend devs who complain about the rest practices and understanding the response codes properly.
 
One of my teams will kill me but I find its most often web/frontend devs who complain about the rest practices and understanding the response codes properly.

I'm going with that in mind, that there will always be feedback of what is happening on the api side. Whether a success or a fail the front end user can always see what happened and why. Have also been one of those frontend devs asked to use some API and both the documentation sucked and the responses themselves were vague and minimal. It was quite frustrating.
 
True that. I have just found a segment on global error handling. Could probably leave out the whole catch block entirely now.


C#:
public class ExceptionMiddleware
{
    private readonly RequestDelegate next;
    private readonly ILogger<ExceptionMiddleware> _logger;

    public ExceptionMiddleware(RequestDelegate next, ILogger<ExceptionMiddleware> logger)
    {
        this.next = next;
        _logger = logger;
    }

    public async Task Invoke(HttpContext context)
    {
        try
        {
            await next(context);
        }
        catch(Exception ex)
        {
            _logger.LogError(ex, ex.Message);
            context.Response.StatusCode = 500;
            await context.Response.WriteAsync("An unexpected error occurred.  Please try again later.");
        }
    }
}

yup, many ways to skin a cat.

you can also extend `ExceptionFilterAttribute`, which is nice because you get access to the Exception, you dont need to catch it yourself like in middleware

Code:
services.AddControllers(options =>
{
   options.Filters.Add<ApiExceptionFilterAttribute>();
})
 
I'm going with that in mind, that there will always be feedback of what is happening on the api side. Whether a success or a fail the front end user can always see what happened and why. Have also been one of those frontend devs asked to use some API and both the documentation sucked and the responses themselves were vague and minimal. It was quite frustrating.
Feedback is good but the primary feedback is in the response code type, only if really necessary does one normally add a custom message.

Oh and lets not start about a web frontend that just parrots a error vs actually handling it and showing something more humane.
 
I like to separate my backend from the controller due to SRP. IMO the controller‘s function is only
to marshall / route the HTTP request to the entry point and perform auth. The controller then uses DI‘ed services to do whatever it needs to. Back-end services should not care about the middleware protocol be it HTTP, TCP socket or whatever.

I like to return an object from my back-end service that indicates success or fail and then also error descriptions. The error description is *in the user’s language*. The language translation is done in the back end. Also in the case of a successful request you may want to pass back a notification or warning to the user. This is also included in the service’s response. The controller’s job then is to translate the service response to a sensible HTTP response. After all, that is what the controller is there for; marshalling HTTP requests and responses.

The HTTP spec makes provision for detailed additional info in any response. I posted a link to it elsewhere here.
 
Then quick one, what is the best to use in your experience in formatting eg:

Python:
print("This is a string {}".format("xxx"))

#or

print(f"This is a string {}")

f-strings for sure. You can do many interesting things with them (but take note some features only in newer versions of Python)

Python:
product = "book"
print(f"{product=}")

>> product='book'

Useful for debugging and easier to read imo!
 
Last edited:
f-strings for sure. You can do many interesting things with them (but take note some features only in newer versions of Python)

Python:
product = "book"
print(f"{product=}")

>> product='book'

Useful for debugging and easier to read imo!
In the course I'm taking, the guy presenting it prefers the .format
He says the f("xxxx") is new, I'll probably use the newer for strings.
 
In the course I'm taking, the guy presenting it prefers the .format
He says the f("xxxx") is new, I'll probably use the newer for strings.

f-strings was only added in 3.6, and some features are only available since 3.8! So agreed, we can't always have the luxury of working on the latest greatest versions! :D But as always, good to know/understand both!
 
f-strings was only added in 3.6, and some features are only available since 3.8! So agreed, we can't always have the luxury of working on the latest greatest versions! :D But as always, good to know/understand both!
Okay, so your suggestion would be to use .format for now and keep the other one in mind for future coding?
 
This is not about coffee shop scripting languages python, this is about a proper programming lang c#! Script monkeys always try to intervene when proper lang topics are discussed. Start your own script monkey threads!
 
Thats not an Api, this is an Api!
 
Feedback is good but the primary feedback is in the response code type, only if really necessary does one normally add a custom message.

Oh and lets not start about a web frontend that just parrots a error vs actually handling it and showing something more humane.

I've just come across my fair share of programmers who make massive assumptions about what the end users know/don't know. For eg assumption that if you are consuming an API that you automatically know what a status 200, 204 or even 404 means. In my career I can't tell you how many times I've seen "Bad Request" and that was all. Like I'm left sitting there wondering why it was a bad request. Even a 400 Not Found. I'll wonder why it wasn't found. Did I do something wrong? Is the server broken or what? That sort of thing.

So for now I'm taking the For Dummies approach when providing response feedback. So even a 200 can be followed by a "successful request" message. Something like this:

C#:
{
    "Version": "1.0.0.0",
    "StatusCode": 200,
    "Message": "Request successful.",
    "Result": [
        "value1",
        "value2"
    ]
}

Just experimenting at this point with something that provides feedback. I can always chop it out at any point if someone comes along and really convinces me that this is a shitty idea! :D
 
Last edited:
I've just come across my fair share of programmers who make massive assumptions about what the end users know/don't know. For eg assumption that if you are consuming an API that you automatically know what a status 200, 204 or even 404 means. In my career I can't tell you how many times I've seen "Bad Request" and that was all. Like I'm left sitting there wondering why it was a bad request. Even a 400 Not Found. I'll wonder why it wasn't found. Did I do something wrong? Is the server broken or what? That sort of thing.

So for now I'm taking the For Dummies approach when providing response feedback. So even a 200 can be followed by a "successful request" message. Something like this:

C#:
{
    "Version": "1.0.0.0",
    "StatusCode": 200,
    "Message": "Request successful.",
    "Result": [
        "value1",
        "value2"
    ]
}

Just experimenting at this point with something that provides feedback. I can always chop it out at any point if someone comes along and really convinces me that this is a shitty idea! :D

sorry but yes, yes you do know exactly what it means.

The API has contact.
you can read about this contract in the API’s documentation (this is written/generated documentation or the source code or the team knowledge or whatever.)
It tells me: when you do a GET to this endpoint you will receive status code 200, and the body will contain data in this shape.

ask yourself why you think you need to do this, while the majority of large scale HTTP API’s don’t do this
 
sorry but yes, yes you do know exactly what it means.

The API has contact.
you can read about this contract in the API’s documentation (this is written/generated documentation or the source code or the team knowledge or whatever.)
It tells me: when you do a GET to this endpoint you will receive status code 200, and the body will contain data in this shape.

ask yourself why you think you need to do this, while the majority of large scale HTTP API’s don’t do this
I think @Solarion is trying to fix a documentation problem by changing the API rather than changing the documentation.
That or create a single API for public/private use cases, which will lead only to problems due to the interface(contract) changing.

@Solarion
ActionResult allows you to have different responses based on outcome so,
Ok 200 => UserResult
Not found 404 => no content
Bad request 400 => ProblemDetails

This also makes sure Swagger generates things correctly, also because it’s an interface and I’m lazy I use the client side implementation code done by Swagger.

Now go back to post #1, the generated code wouldn’t have used POST instead of PUT.
 
Last edited:
Also do yourself a favor and run “dotnet new webapi” with the dotnet 5.0 sdk/cli

this will create a web api project preconfigured with swagger.

you can then point your postman to the
endpoint - which you can copy/paste from the swagger ui - and generate a postman collection.

everything documented - with zero effort.

adding swagger to an existing api is trivial too.

what you will then find is that the “documentation” you are trying to provide cannot easily be represented in swagger/open-api.
But, because you are using ActionResult, your can do things like this on your controller


C#:
[HttpGet("{id}")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(Product))]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public IActionResult GetById(int id)
{
    if (!_repository.TryGetProduct(id, out var product))
    {
        return NotFound();
    }

    return Ok(product);
}

now your swagger documentation shows what happens on different status codes
 
Last edited:
Note all the api devs who are awake and experimenting/teaching in the early hours of the morning :D
 
Front-end framework devs must love you lol
Why would you run a front end against a webapi vs just adding the code to the front end itself?
Unless with front end you mean an external application consuming the services?
 
@_kabal_ im on dot net 5 web api. It works lekker, ive added JWT and call limiting etc.
I don't use the built-in swagger though, i want to customize my swagger file per client, so i just create rhem in the editor.

Also something i have not found a solution for is having lots of APIs and now i need to update one. I cannot do it independently, the whole project must be deployed. I can probably split the project but each dot net 5 project in iis needs a new application pool. Haven't read up on that yet.
 
Top
Sign up to the MyBroadband newsletter
X