SmartEnums, not string literals
When a value belongs to a known, finite set (a disruption cause, a decision type), the TS habit is a string union: type Reason = 'weather' | 'mechanical'. In Fusion that’s slop (anti-pattern #2). The set lives in the backend as a SmartEnum: an enum-shaped object that carries a stable slug, a display label, and any per-member data, with lookup and equality built in.
public class DisruptionReason : SmartEnum<DisruptionReason, string>
{
public static readonly DisruptionReason Mechanical = new(
nameof(Mechanical), "mechanical", "Mechanical / Technical", isExtraordinary: false, displayOrder: 0);
public static readonly DisruptionReason Weather = new(
nameof(Weather), "weather", "Weather", isExtraordinary: true, displayOrder: 6);
private DisruptionReason(string name, string value, string displayLabel, bool isExtraordinary, int displayOrder)
: base(name, value)
{
DisplayLabel = displayLabel;
IsExtraordinary = isExtraordinary;
DisplayOrder = displayOrder;
}
public string DisplayLabel { get; }
public bool IsExtraordinary { get; }
}The two-part identity matters. Name is the PascalCase C# identifier (nameof(Mechanical)). Value is the kebab-case slug ("mechanical") that gets persisted and sent over the wire, so it’s a public contract you don’t change casually. You get .List, .FromValue, .TryFromValue, .FromName, and value-based equality without writing any of them.
Try it yourself
Read a SmartEnum end to end
See the whole pattern: members, extra data, Parse, and the endpoint projection.
- Open
domain/Enums/DisruptionReason.csand read the static members and theirnameof/slug/labeltriples - Find
Parse(string code)and note it returnsResult<DisruptionReason>, wrappingTryFromValue - Open a
*Endpoints.csthat serves an enum list and note it projects to a small DTO (Code,DisplayLabel), never the raw member - Confirm no TypeScript union anywhere mirrors these values
Name versus Value
This distinction is a contract, so hold it exactly.
In a Fusion SmartEnum, what is the difference between the Name and the Value, and which one must you not change casually?
Reveal answer
Name is the PascalCase C# identifier (e.g. Mechanical, via nameof). Value is the kebab-case slug (e.g. "mechanical") that is persisted to the database and sent over the API. Value is a public contract, so changing it breaks stored data and clients; add a new member and deprecate instead of editing a Value.