Interview question
Test validation through the ProblemDetails contract
Verifies status, content type, stable error extensions, and field errors for an invalid API request.
TL;DR
Verifies status, content type, stable error extensions, and field errors for an invalid API request.
Model binding, validation, ValidationProblemDetails, stable error codes, content types, and client-safe contracts.
Practice the problem like a real interview: restate, reason, implement, and test.
Post a suggestion with a blank title and body exceeding the allowed length. Assert 400, application/problem+json, a stable error code, and field keys. Do not assert the full English message sentence.
The client can map errors.title and errors.body while support can correlate the response through traceId.
I deserialize ValidationProblemDetails and assert the parts clients depend on: status, media type, stable extension, trace id, and field keys. Message prose can improve without breaking the test.
[Fact]
public async Task Invalid_suggestion_returns_validation_problem_details()
{
await using var factory = new ApiTestFactory();
var client = factory.CreateAuthenticatedClient("candidate-1", "suggestions.create");
using var response = await client.PostAsJsonAsync(
"/api/suggestions",
new { Title = " ", Body = new string('x', 5001) });
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
Assert.Equal("application/problem+json", response.Content.Headers.ContentType?.MediaType);
var problem = await response.Content
.ReadFromJsonAsync<HttpValidationProblemDetails>();
Assert.Equal(400, problem!.Status);
Assert.Equal("validation.failed", problem.Extensions["code"]?.ToString());
Assert.True(problem.Errors.ContainsKey("title"));
Assert.True(problem.Errors.ContainsKey("body"));
Assert.False(string.IsNullOrWhiteSpace(problem.Extensions["traceId"]?.ToString()));
}
This is a contract test at the API boundary. It avoids a database dependency because validation must reject the request before persistence; a fake repository can additionally assert that no save method ran.
Next in API Testing Labs: Idempotent POST