Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HealthReport object structure produced by health checks endpoint freezes Swagger docs page

I enabled health checks for my .Net 5 Web API project

public sealed class Startup
{
    public void ConfigureServices(IServiceCollection serviceCollection)
    {
        serviceCollection.AddHealthChecks();

        // ...
    }

    public void Configure(IApplicationBuilder applicationBuilder, IWebHostEnvironment webHostEnvironment)
    {
        // ...

        applicationBuilder.UseHealthChecks("/health");

        // ...
    }
}

Unfortunately the health endpoint does not appear in the swagger docs. That's why I created an additional controller

[ApiController]
[Route("[controller]")]
public sealed class HealthController : ControllerBase
{
    private readonly HealthCheckService _healthCheckService;

    public HealthController(HealthCheckService healthCheckService)
    {
        _healthCheckService = healthCheckService;
    }

    [HttpGet]
    public async Task<ActionResult<HealthReport>> GetHealthIndication()
    {
        HealthReport healthReport = await _healthCheckService.CheckHealthAsync();

        if (healthReport.Status == HealthStatus.Healthy)
        {
            return Ok(healthReport);
        }

        int serviceUnavailableStatusCode = (int) HttpStatusCode.ServiceUnavailable;
        
        return StatusCode(serviceUnavailableStatusCode, healthReport);
    }
}

When running the application Swagger generated a lot of models. When opening the health endpoint the page freezes for multiple seconds because it has to load the HealthReport object structure.

enter image description here

  • I think it is not fine that an API with a single endpoint freezes because of this ... any suggestions for this?

enter image description here

  • Do I even have to create my own controller, aren't there any integrations yet? I'm looking for a solution like .UseHealthChecks(HealthController.GetHealthIndication)
like image 770
Question3r Avatar asked May 28 '21 21:05

Question3r


People also ask

Where are the health check endpoints created in the sample app?

In the sample app, the health check endpoints are created at: /health/ready for the readiness check. The readiness check filters health checks to the health check with the ready tag. /health/live for the liveness check.

How does ihealthcheckpublisher work in a service container?

When an IHealthCheckPublisher is added to the service container, the health check system periodically executes your health checks and calls PublishAsync with the result. This is useful in a push-based health monitoring system scenario that expects each process to call the monitoring system periodically in order to determine health.

What is a health check in ASP NET Core?

Health checks are a nice feature in ASP.NET Core that lets you create an endpoint that your load balancer or health checking systems can ping to check your service. If there is an unhealthy response then the response will have a 503 response code.

How do I add a healthcheckservice to a Swagger project?

Add a new controller e.g. HealthController and inject the HealthCheckService into the constructor. The HealthCheckService is added as a dependency when you call AddHealthChecks in Startup.cs: The HealthController should appear in Swagger when you rebuild:


1 Answers

TLDR;

Add schema mapping for the Exception class in Swagger configuration.

services.AddSwaggerGen(c =>
            {
                c.MapType<Exception>(() => new OpenApiSchema { Type = "object" });
            });

This code would convert Schema with Exception class as an object, thus the behavior you are facing at the client-side would minimize.


Explanation:

Root Cause: Swagger freezes because the swagger javascript client is trying to create a sample model based on schema fetched from swagger json.

If you look at the Exception class, it contains a large number of nested properties and types. If we instruct the swagger generator to treat the Exception class as a simple object in a created JSON file, the client would not have to spend time creating nested objects. (or you can include TimeSpan class in this conversion as well).

There are multiple ways to solve this issue:

  1. As mentioned above simply instruct the Swagger generator to map type at config level itself.
  2. If you want to create schema based on specific Action (Operation in Swagger context) or Controller (Document in Swagger context), then you can implement respective filters and modify Swagger Document content on the fly. https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/master/README.md#override-schema-for-specific-types
  3. Create your own Response model: This makes sense because over time schema of HealthReport could change and thus the output of service could change without realizing it over longer time.

Do I even have to create my own controller, aren't there any integrations yet? I'm looking for a solution.UseHealthChecks(HealthController.GetHealthIndication)

Swashbuckle (Swagger codegen and UI) uses Reflection and Assembly documentation (.xml files) to create swagger documents, thus it is won't scan other assemblies for controllers.

like image 196
mbshambharkar Avatar answered Oct 11 '22 13:10

mbshambharkar