Errors and Validation
How the Wrapsfer API responds to invalid requests today, and how unhandled exceptions are translated into HTTP responses. Both flows return RFC 7807 application/problem+json bodies but come from different layers — model validation is provided by ASP.NET Core, and the 500 fallback is provided by ExceptionHandlingMiddleware.
Summary
| Failure | Source | Status | Content-Type |
|---|---|---|---|
| Request fails model validation | [ApiController] automatic 400 | 400 | application/problem+json |
| Unhandled exception during a request | ExceptionHandlingMiddleware | 500 | application/problem+json |
Endpoints today do not throw 4xx for business reasons (no authentication, no authorization policies, no domain validation surfaces beyond what StringLength covers). When such cases are added, document them then — see Recommendations at the bottom of this page.
Model Validation
GreetingsController is annotated with [ApiController], which enables ASP.NET Core's automatic model-state validation. When binding produces any ModelState errors, the framework short-circuits the action and returns 400 Bad Request with a ValidationProblemDetails body — the action method is never invoked.
The only validated input today is the greeting endpoint's name query parameter, decorated with [StringLength(80, MinimumLength = 1)]. This means:
?name=(empty string) — failsMinimumLength = 1.?name=followed by 81+ characters — failsMaximumLength = 80.?name=1–80 characters — passes.- Omitted entirely — uses the controller default
"World"and passes.
Example: empty name
curl -i "http://localhost:8080/api/greetings?name="
HTTP/1.1 400 Bad Request
Content-Type: application/problem+json; charset=utf-8
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"errors": {
"name": [
"The field name must be a string with a minimum length of 1 and a maximum length of 80."
]
},
"traceId": "00-..."
}
Notes on the response
- Body shape is
ValidationProblemDetails— the standard ASP.NET Core 400 problem-details document with anerrorsmap keyed by the offending parameter name. - Error message wording is the framework default for
StringLengthAttributeand is not customized in the codebase. Treat the exact text as informational only; the structure is the contract. typeURI points at the relevant RFC section, again ASP.NET Core's default.traceIdis the current activity trace identifier when one is available. The exact value will differ per request.- The middleware pipeline runs before automatic validation, so
ExceptionHandlingMiddlewareis not involved in this path.
Unhandled Exceptions — ExceptionHandlingMiddleware
Wrapsfer.Api.Middleware.ExceptionHandlingMiddleware wraps the rest of the pipeline. If any downstream code (controller, application service, domain) throws an exception that nothing else catches, the middleware:
- Logs the exception via
ILogger<ExceptionHandlingMiddleware>.LogErrorwith message"Unhandled exception occurred while processing the request.". - Constructs a
ProblemDetailsdocument and serializes it asapplication/problem+jsonwith HTTP500.
The middleware is registered first in the pipeline (app.UseMiddleware<ExceptionHandlingMiddleware>(); before any other Use* call in Program.cs), so it sees exceptions from CORS, authorization, controllers, and any other middleware that runs after it.
Response shape
| Field | Value |
|---|---|
status | 500 |
title | "An unexpected error occurred." |
detail | "Contact support if the problem persists." |
instance | context.Request.Path — the request path that threw |
type is not set by the middleware (the ProblemDetails default applies). No exception type, message, or stack trace is leaked to the response body — those go to logs only.
Example
HTTP/1.1 500 Internal Server Error
Content-Type: application/problem+json
{
"title": "An unexpected error occurred.",
"status": 500,
"detail": "Contact support if the problem persists.",
"instance": "/api/greetings"
}
There is no current endpoint that intentionally produces this response — it is the safety net for unanticipated failures.
Other HTTP Responses
Behaviors that are part of the framework but not customized in source:
404 Not Foundfor any unmapped route (e.g./openapi/v1.jsonoutsideDevelopment, or any path other than/health,/api/greetings, and the OpenAPI document). ASP.NET Core endpoint routing handles this; no custom 404 response is configured.405 Method Not Allowedif a method other thanGETis sent to aGET-only endpoint. This is the framework default.- HTTPS redirect (
UseHttpsRedirection) may issue a redirect for HTTP requests when an HTTPS port is configured (e.g. when running with thehttpslaunch profile).
These are not implemented behaviors of the API per se — they fall out of ASP.NET Core defaults.
Recommendations For Future Errors
These are guidance for future work, not current behavior:
- Expected validation and domain errors (e.g. "name conflict", "resource not found", "insufficient permissions") should be handled explicitly — typically returning
400,404, or409with their own problem-details documents — rather than being allowed to throw and reachExceptionHandlingMiddleware. The 500 path should remain the unanticipated case. - Domain
ArgumentExceptionfromGreeting.Createis currently shielded by the controller's[StringLength(MinimumLength = 1)], which rejects whitespace/empty values before they reach the application or domain layer. If a future controller bypasses that validation, the exception will propagate and surface as a500— wire explicit handling at the application or controller layer when that becomes relevant. - New problem types should keep using
application/problem+jsonfor error responses to remain consistent with both existing flows. - Authentication and authorization failures are not implemented today; when added, they will produce
401and403from the auth middleware — document those at that point.
See Also
- Endpoint Reference — successful request/response shapes.
- Business Rules — what
namemeans, what is and is not validated as a business rule. - Architecture — where validation, exception handling, and domain rules live.