Skip to content

Data and type mismatch found if a string happens to parse as a specific type #1738

Open

Description

Describe the bug

I have a toy API that exists for testing ASP.NET Core functionality, and one of the resources describes times and acts like a clock.

The schema for the response of this endpoint is below:

"TimeResponse": {
  "type": "object",
  "properties": {
    "timestamp": {
      "type": "string",
      "description": "The timestamp for the response for which the times are generated.",
      "format": "date-time"
    },
    "rfc1123": {
      "type": "string",
      "description": "The current UTC date and time in RFC1123 format."
    },
    "unix": {
      "type": "integer",
      "description": "The number of seconds since the UNIX epoch.",
      "format": "int64"
    },
    "universalSortable": {
      "type": "string",
      "description": "The current UTC date and time in universal sortable format."
    },
    "universalFull": {
      "type": "string",
      "description": "The current UTC date and time in universal full format."
    }
  },
  "description": "Represents the response from the /time API resource."
}

This response explicitly has:

  • One date-time for ISO-8601
  • One int64 for Unix timestamps
  • Three string properties that are string representations of dates that do not conform to ISO-8601

It also contains the following JSON example for the schema:

"example": {
  "timestamp": "2016-06-03T18:44:14+00:00",
  "rfc1123": "Fri, 03 Jun 2016 18:44:14 GMT",
  "unix": 1464979454,
  "universalSortable": "2016-06-03 18:44:14Z",
  "universalFull": "Friday, 03 June 2016 18:44:14"
}

The example is valid for the moment in time that it describes.

If the schema is validated according to the validation rules with code such as the below, it generates 4 validation warnings:

[Fact]
public void SchemaGeneratesNoValidateWarnings()
{
    using var streamReader = new StreamReader("openapi.json");
    var reader = new OpenApiStreamReader();
    var document = reader.Read(streamReader.BaseStream, out var diagnostic);

    var errors = document.Validate(ValidationRuleSet.GetDefaultRuleSet());
    Assert.Empty(errors);
}
[
    Data and type mismatch found. [#/paths/~1time/get/responses/200/content/application~1json/example/rfc1123],
    Data and type mismatch found. [#/paths/~1time/get/responses/200/content/application~1json/example/unix],
    Data and type mismatch found. [#/paths/~1time/get/responses/200/content/application~1json/example/universalSortable],
    Data and type mismatch found. [#/paths/~1time/get/responses/200/content/application~1json/example/universalFull]
]

For the three "date-ish" values, this is because this line of code treats the value as an OpenApiDateTime as it happens to parse as a DateTimeOffset:

// More narrow type detection for explicit strings, only check types that are passed as strings
if (schema == null)
{
if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateTimeValue))
{
// if the time component is exactly midnight(00:00:00) meaning no time has elapsed, return a date-only value
return dateTimeValue.TimeOfDay == TimeSpan.Zero ? new OpenApiDate(dateTimeValue.Date)
: new OpenApiDateTime(dateTimeValue);
}
}

This then fires the validation warning here as the type test fails:

if (type == "string")
{
if (!(value is OpenApiString))
{
context.CreateWarning(
ruleName,
DataTypeMismatchedErrorMessage);
}
return;
}

For the int64 value, because the value is less than int.MaxValue + 1, this code treats the value as an int32:

if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
{
return new OpenApiInteger(intValue);
}
if (long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var longValue))
{
return new OpenApiLong(longValue);
}

This then causes the type test to fail in a similar fashion:

if (type == "integer" && format == "int64")
{
if (!(value is OpenApiLong))
{
context.CreateWarning(
ruleName,
DataTypeMismatchedErrorMessage);
}
return;
}

OpenApi File To Reproduce

openapi.json

Expected behavior

The example is valid according to the schema, so should not generate any validation warnings.

Screenshots/Code Snippets

N/A

Additional context

Found through use of Kiota to generate a typed C# client for the OpenAPI schema as part of dotnet/aspnetcore#56318 (comment).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

Labels

type:bugA broken experience

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions