Skip to main content

How to Return Enums as Strings in Minimal API JSON

· 4 min read
Jagdish Kumawat
Founder @ Dewiride

By default, an enum in a minimal API's JSON is a number, and "type": 0 tells a reader nothing. One line in Program.cs makes every endpoint use the names, in both directions. It's worth knowing exactly what it accepts on the way in, too.

Prerequisites​

  • An ASP.NET Core minimal API. I used ASP.NET Core 10.

Step 1: Add the Converter​

src/Dewiride.Inventory.Api/Program.cs (excerpt)
// Enums travel as their names, such as "Receipt", not as numbers.
builder.Services.ConfigureHttpJsonOptions(options =>
options.SerializerOptions.Converters.Add(new JsonStringEnumConverter()));

This needs using System.Text.Json.Serialization;. ConfigureHttpJsonOptions sets the options minimal APIs use. It doesn't affect controllers, which have their own.

Step 2: See the Responses Change​

Before:

Response
HTTP/1.1 201 Created
Content-Type: application/json; charset=utf-8
Location: /api/v1/products/9/stock/movements

{
"movement": {
"id": 1,
"productId": 9,
"type": 0,
"quantityChange": 10,
"reason": "First delivery",
"reference": "PO-1001",
"orderId": null,
"occurredAtUtc": "2026-11-05T05:11:52.204666Z"
},
"quantityOnHand": 10
}

After:

Response
HTTP/1.1 201 Created
Content-Type: application/json; charset=utf-8
Location: /api/v1/products/9/stock/movements

{
"movement": {
"id": 2,
"productId": 9,
"type": "Receipt",
"quantityChange": 5,
"reason": "Second delivery",
"reference": "PO-1003",
"orderId": null,
"occurredAtUtc": "2026-11-05T05:12:38.543732Z"
},
"quantityOnHand": 15
}

A JSON response with type set to the string Receipt, where it was the number 0.

Step 3: See What It Accepts​

For this request type:

An endpoint
public sealed record EnumBody(StockMovementType Type, OrderStatus? Status);

g.MapPost("/enum", (EnumBody body) => Results.Ok(body));
BodyResult
{"type":"Receipt","status":"Placed"}Accepted
{"type":"receipt"}Accepted: the case doesn't matter
{"type":1,"status":2}Accepted: numbers still work
{"type":"Refund"}400: not a member

Here's the numbers row:

Response
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
"type": "Adjustment",
"status": "Cancelled"
}

And the last one:

Response
HTTP/1.1 400 Bad Request
Content-Type: application/problem+json

{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "Bad Request",
"status": 400,
"traceId": "00-48b2a0e4f443cf6adddb0732ed560e67-71a3cb1d84eaa9a3-00"
}

Step 4: Refuse Numbers​

If you want names only, say so:

src/Dewiride.Inventory.Api/Program.cs (excerpt)
builder.Services.ConfigureHttpJsonOptions(options =>
options.SerializerOptions.Converters.Add(new JsonStringEnumConverter(allowIntegerValues: false)));
Response (the type as the number 1)
HTTP/1.1 400 Bad Request
Content-Type: application/problem+json

{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "Bad Request",
"status": 400,
"traceId": "00-e141a48533df0d1680fa2f16d0f7d5cc-bc51ae9f5a2934fe-00"
}
Response (the type as a name)
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
"type": "Receipt",
"status": null
}

Common Mistakes​

MistakeWhat happensDo this instead
Expecting this to change the query stringJSON options don't apply thereHandle it separately
Renaming an enum memberClients break, since the name is now the contractAdd a new one, or map it
Adding it per propertyEasy to miss oneRegister it once

Troubleshooting​

SymptomLikely causeFix
Still numbersIt's on AddControllers, or on another options objectUse ConfigureHttpJsonOptions
400 with no explanationA JSON value that isn't a memberThe reason is in the log
?status=99 is acceptedQuery strings parse differentlyThe fix

Conclusion​

Add JsonStringEnumConverter once, in ConfigureHttpJsonOptions. Pass allowIntegerValues: false if you don't want numbers accepted.

Additional Resources​

Stay Updated

Subscribe to our newsletter for the latest tutorials, tech insights, and developer news.

By subscribing, you agree to our privacy policy. Unsubscribe at any time.