Kontroler [ApiController] różne odpowiedzi 404

0

Mam pytanie odnośnie odpowiedzi 404. Piszę tutorialowy projekt webapi i mam kontroler [ApiController], w którym jest endpoint /api/todos/{id} zwracający zasób o podanym id. Metoda wygląda jak poniżej.

[HttpGet("{id}")]
[Produces("application/json")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<TodoDto> Get([FromRoute] int id)
{
    var todo = _context.Todos.FirstOrDefault(t => t.Id == id);
    
    if (todo == null) return NotFound();

    var todoDto = _mapper.Map<TodoDto>(todo);
    
    return Ok(todoDto);
}

No i jak wejdę pod dobry endpoint dla zasobu, który nie istnieje np. /api/todos/999, to dostaję odpowiedź 404 z JSON.
1.png

A jak wejdę pod zły endpoint, którego nie ma w API np. /api/zly, to dostaję odpowiedź 404 bez JSON.
2.png

Nie rozumiem, to jest dobrze i tak domyślnie ma być? Co to jest traceId?

Czy da się zmienić by dla 404 zasób mieć JSON:

{
    "type": "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.4",
    "title": "Not Found",
    "status": 404,
    "message": "Resource :id not found"
}

a dla nieistniejących endpoint:

{
    "type": "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.4",
    "title": "Not Found",
    "status": 404,
    "message": "Endpoint :id not found"
}

No i pytanie czy używa się tych metod typu NotFound(), Ok(), BadRequest(), Created() czy może jest coś innego?

0

jak wejdę pod dobry endpoint dla zasobu, który nie istnieje np. /api/todos/999, to dostaję odpowiedź 404
Raczej powinieneś tu zwracać BadRequest()

1

Generalnie NotFound itd. mają różne przeciążenia i ty możesz tam zwracać co chcesz.

To co tutaj dostajesz, to są automatic 400 responses, czyli po prostu jakieś tam domyślne odpowiedzi zgodne z danym standardem.

Jeżeli faktycznie chcesz nadpisać domyślne zachowanie przy 404, to m.in możesz np. zrobić sobie jakiś endpoint typu

[HttpGet("Error")]
public IActionResult Error()
{
    // wtf? 
    var obj = new
    {
        type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.4",
        title = "Not Found",
        status = "404",
        message = "Endpoint :id not found"
    };

    return NotFound(obj);
}

i na niego przekierować gdy miałby iść NotFound (url)

app.Use(async (ctx, next) =>
{
	await next();

	if (ctx.Response.StatusCode == 404 && !ctx.Response.HasStarted)
	{
		ctx.Response.Redirect("/WeatherForecast/Error");
		return;
	}
});

lub

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
    endpoints.MapFallback(x =>
    {
        x.Response.Redirect("/WeatherForecast/Error");
        return Task.CompletedTask;
    });
});

1 użytkowników online, w tym zalogowanych: 0, gości: 1