TypedResults is a static ASP.NET Core helper type for creating common HTTP responses in minimal API handlers. Its methods can return status codes such as 200, 201, 204, 400, and 404, optionally with a JSON body. section 5.3.1
Results and TypedResults perform the same response-generation work. Results methods return IResult, while TypedResults methods return concrete generic types such as Ok<T>. Those concrete types are especially useful for unit tests and OpenAPI documentation. section 5.3.1
Choose a response helper that matches the outcome of the endpoint:
- Use TypedResults.Ok(value) for a successful response containing an object. section 5.3.1
- Use TypedResults.Created(location, value) after creating an entity; it supplies a Location header and response body. section 5.3.1
- Use TypedResults.NoContent() when the operation succeeds without returning a body. section 5.3.1
- Use TypedResults or Results helpers for invalid requests and missing entities, commonly with 400 Bad Request or 404 Not Found. section 5.3.1
Fruit endpoint responses
A minimal API can return TypedResults.Ok(fruit) when a fruit is found and TypedResults.Created($"/fruit/{id}", fruit) after adding one. The same handlers can return Results.NotFound() when the identifier is missing or Results.BadRequest(...) when it already exists. section 5.3.1
Listing 5.3 Using Results and TypedResults in a minimal API
using System.Collections.Concurrent; WebApplicationBuilder builder = WebApplication.CreateBuilder(args); WebApplication app = builder.Build(); var _fruit = new ConcurrentDictionary<string, Fruit>(); #1 app.MapGet("/fruit", () => _fruit); app.MapGet("/fruit/{id}", (string id) => _fruit.TryGetValue(id, out var fruit) #2 ? TypedResults.Ok(fruit) #3 : Results.NotFound()); #4 app.MapPost("/fruit/{id}", (string id, Fruit fruit) => _fruit.TryAdd(id, fruit) #5 ? TypedResults.Created($"/fruit/{id}", fruit) #6 : Results.BadRequest(new #7 { id = "A fruit with this id already exists" })); #7 app.MapPut("/fruit/{id}", (string id, Fruit fruit) => { _fruit[id] = fruit; return Results.NoContent(); #8 }); app.MapDelete("/fruit/{id}", (string id) => { _fruit.TryRemove(id, out _); #9 return Results.NoContent(); #9 }); app.Run(); record Fruit(string Name, int stock); #1 Uses a concurrent dictionary to make the API thread-safe #2 Tries to get the fruit from the dictionary. If the ID exists in the dictionary, this returns true . . . #3 . . . and we return a 200 OK response, serializing the fruit in the body as JSON. #4 If the ID doesn’t exist, returns a 404 Not Found response #5 Tries to add the fruit to the dictionary. If the ID hasn’t been added yet. this returns true . . . #6 . . . and we return a 201 response with a JSON body and set the Location header to the given path. #7 If the ID already exists, returns a 400 Bad Request response with an error message #8 After adding or replacing the fruit, returns a 204 No Content response #9 After deleting the fruit, always returns a 204 No Content response
Use the complete fruit API listing to compare successful, creation, missing-resource, and validation responses in one runnable minimal API. section 5.3.1
For files, byte arrays, or streams, use the corresponding Results or TypedResults helpers when available. For unusual responses, inject HttpResponse and write the response manually; repeated custom behavior can become a custom IResult type. section 5.3.4
