Skip to content

Error parsing Enums for the query parameter #49

@jonathangomz

Description

@jonathangomz

Overview

Enum values are serialized incorrectly in query parameters. Passing MessageGeneralStatus.Pending results in generalStatus=Pending instead of the expected PENDING, causing API validation errors.

Package version

4.0.0

Description

When calling the GetOutboundSmsMessageLogs endpoint with the generalStatus parameter set to an enum value (e.g., MessageGeneralStatus.Pending), the generated HTTP request sends the query parameter as the enum identifier (Pending) rather than the wire value defined by EnumMember(Value = "PENDING"). The API expects uppercase values per the wire contract and responds with a validation error.

Reproducing

  • Initialize the SmsApi client as usual.
  • Invoke: api.GetOutboundSmsMessageLogs(generalStatus: MessageGeneralStatus.Pending);
  • Server responds with 400 validation error indicating Invalid value Pending.
  • Repeat with other enums having EnumMember values (ACCEPTED, DELIVERED, etc.) and observe the same behavior.

Observed server response (example)

{
    "errorCode": "E400",
    "description": "Request cannot be processed.",
    "action": "Check the syntax, violations and adjust the request.",
    "violations": [
        {
            "property": "generalStatus",
            "violation": "Invalid value Pending"
        }
    ],
    "resources": []
}

Root cause

The issue is in ClientUtils.ParameterToString, specifically at the line where Convert.ToString is used (around line 121). That path converts enums via their identifier name (e.g., “Pending”), ignoring EnumMemberAttribute and required uppercase wire values. As a result, query parameters serialize enums as “Pending” instead of “PENDING”.

Proposed fix:

Update the query parameter serialization utility (ClientUtils.ParameterToString) to detect Enum and call ToWireEnumValue.

/// <summary>
///     If parameter is DateTime, output in a formatted string (ISO 8601).
///     If parameter is a list, join the list with ",".
///     Otherwise just return the string.
/// </summary>
/// <param name="obj">The parameter (header, path, query, form).</param>
/// <returns>Formatted string.</returns>
public static string ParameterToString(object obj)
{
    if (obj is DateTime dateTime)
        // Return a formatted date string - Can be customized with Configuration.DateTimeFormat
        // Defaults to an ISO 8601, using the known as a Round-trip date/time pattern ("o")
        // https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx#Anchor_8
        // For example: 2009-06-15T13:45:30.0000000
        return dateTime.ToString(Configuration.Iso8601DateTimeFormat);
    if (obj is DateTimeOffset dateTimeOffset)
        // Return a formatted date string - Can be customized with Configuration.DateTimeFormat
        // Defaults to an ISO 8601, using the known as a Round-trip date/time pattern ("o")
        // https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx#Anchor_8
        // For example: 2009-06-15T13:45:30.0000000
        return dateTimeOffset.ToString(Configuration.Iso8601DateTimeFormat);
    if (obj is bool boolean)
        return boolean ? "true" : "false";
    if (obj is ICollection collection)
        return string.Join(",", collection.Cast<object>());
    if (obj is Enum) // <---- FIX HERE
        return ToWireEnumValue(obj);

    return Convert.ToString(obj, CultureInfo.InvariantCulture);
}
static string ToWireEnumValue(object enumValue)
{
    var type = enumValue.GetType();
    var enumType = Nullable.GetUnderlyingType(type) ?? type;

    if (!enumType.IsEnum)
        return Convert.ToString(enumValue, CultureInfo.InvariantCulture);

    var name = Convert.ToString(enumValue, CultureInfo.InvariantCulture);
    var member = enumType.GetMember(name).FirstOrDefault();
    var attr = member?.GetCustomAttribute<EnumMemberAttribute>();
    return attr?.Value ?? name.ToUpperInvariant();
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions