Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
martincostello opened this issue Jul 20, 2024 · 1 comment
Assignees
Labels
type:bug A broken experience

Comments

@martincostello
Copy link
Contributor

martincostello commented Jul 20, 2024

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).

@MaggieKimani1
Copy link
Contributor

Hi @martincostello, thanks for pointing out this issue.
This is clearly a regression bug as a result of trying to fix this issue #1526.
Let me look into it.

PS: This issue will go away in V2 as we're getting rid of the strongly typed structure during parsing examples as we'll treat them as their JSON compatible values.

@MaggieKimani1 MaggieKimani1 self-assigned this Jul 22, 2024
@MaggieKimani1 MaggieKimani1 added the type:bug A broken experience label Jul 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type:bug A broken experience
Projects
None yet
Development

No branches or pull requests

2 participants