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

openapi: support validation attributes #1477

Merged

Conversation

verdie-g
Copy link
Contributor

@verdie-g verdie-g commented Feb 24, 2024

Closes #1055

image

.NET Applicable types OpenAPI NSwag Kiota MVC EF Core Notes
[Length] string, ICollection minLength/maxLength/minItems/maxItems Y Y Y N .NET 8+
[MinLength] string, ICollection minLength/minItems Y Y Y N .NET 8+
[MaxLength] string, ICollection maxLength/maxItems Y Y Y N .NET 8+
[Compare] any - Y Y Y N Works on any type that implements Equals
[Required(AllowEmptyStrings = true)] string required: [] Y Y Y N Only applies to JSON:API create resource
[RegularExpression] string pattern: XX Y Y Y N Potential differences in regex dialects, don't care. Convert.ToString is used on the value so could theoretically be used on other types than string
[StringLength] string minLength / maxLength Y Y Y Y Omitting MinimumLength implies 0. character varying with PostgreSQL
[CreditCard] or [DataType(DataType.CreditCard)] string format: credit-card Y Y Y N
[EmailAddress] or [DataType(DataType.EmailAddress)] string format: email Y Y Y N
[Base64String] string - Y Y Y N .NET 8+
[Phone] or [DataType(DataType.PhoneNumber)] string format: tel Y Y Y N
[Range] int, double, IComparable minimum, maximum (both inclusive) Y Y Y N .NET 8 adds MinimumIsExclusive, MaximumIsExclusive but it's not supported by Swashbuckle
[Url] string format: uri Y Y Y N Only http/https/ftp, non-relative for NSwag. Kiota generates a string and any absolute or relative uris are accepted
[AllowedValues] any - Y Y Y N .NET 8+
[DeniedValues] any - Y Y Y N .NET 8+
[Required] any required: [], minLength: 1 Y Y Y Y Only applies to JSON:API create resource. Makes a db column NOT NULL, has priority over [NotNull]
[Remote] - - N N Y N Not part of System.ComponentModel.DataAnnotations. Ignored by Swashbuckle
[ValidateNever] - - N N Y N Not part of System.ComponentModel.DataAnnotations. Ignored by Swashbuckle
[DataType(DataType.Currency)] ? format: currency ? ? ? ?
[DataType(DataType.Date)] ? format: date ? ? ? ?
[DataType(DataType.DateTime)] ? format: date-time ? ? ? ?
[DataType(DataType.Duration)] ? format: duration ? ? ? ?
[DataType(DataType.Html)] ? format: html ? ? ? ?
[DataType(DataType.ImageUrl)] ? format: uri ? ? ? ?
[DataType(DataType.MultilineText)] ? format: multiline ? ? ? ?
[DataType(DataType.Password)] ? format: password ? ? ? ?
[DataType(DataType.PostalCode)] ? format: postal-code ? ? ? ?
[DataType(DataType.Time)] ? format: time ? ? ? ?
[DataType(DataType.Upload)] ? format: binary ? ? ? ?
[DataType(DataType.Url)] ? format: uri ? ? ? ?
Guid - format: uuid Y Y Y Y
HashSet - uniqueItems Y ? Y N
Uri - format: uri Y N Y Y Kiota generates a string and any absolute or relative uris are accepted. No DB constraint
DateOnly - format: date Y Y Y Y Kiota generates a Microsoft.Kiota.Abstractions.Date
TimeOnly - format: time Y Y Y Y Kiota generates a Microsoft.Kiota.Abstractions.Time
- multipleOf
- hostname
- minItems, maxItems
- ipv4, ipv6
get; - readOnly ? ? ? ?
set; - writeOnly ? ? ? ?

Legend:

  • NSwag/Kiota means a working C# client is generated (with test coverage for valid/invalid input, part of this PR).
  • MVC means the expected server-side validation error is produced. Sometimes NSwag already catches bad input, so it never hits the server. We don't need to add tests for that in this PR, but it should be tried out. For example, if adding [StringLength] does NOT validate server-side, but only NSwag catches it, we should document that. Because only client-side validation is insecure.
  • EF Core means checking what SQL data type and SQL constraints are being generated, and whether they make sense. For example, does [Required(AllowEmptyStrings = false)] generate just a non-nullable column, or does it also add the minimum length constraint? If not, should it do so, if possible at all? Google for it, are there open issues, StackOverflow questions, etc? We need to understand how it works and is supposed to be used, and reason about the feature from an API developer perspective. Is there anything to watch out for? Similar to the previous bullet, this is exploration.

QUALITY CHECKLIST

@verdie-g
Copy link
Contributor Author

verdie-g commented Feb 24, 2024

@bkoelman could you give a preliminary review on just that?

@bkoelman
Copy link
Member

@verdie-g Do you still intend to complete this?

@verdie-g
Copy link
Contributor Author

Unfortunately I don't think I'll find the time.

@verdie-g
Copy link
Contributor Author

I pushed some old changes that were still on my machine in case someone wants to continue the PR.

@verdie-g verdie-g force-pushed the 1055-openapi-model-validation branch from 3f781fb to 9dee70f Compare May 27, 2024 01:52
@verdie-g verdie-g force-pushed the 1055-openapi-model-validation branch from f46fc65 to 07c9d7d Compare May 27, 2024 21:22
@verdie-g
Copy link
Contributor Author

Hi @bkoelman, I'll try finishing that PR. Could you have a pass on its current state, I'll add tests for Kiota once the one for NSwag start looking okay. Also, is there anything worth adding to the doc regarding this change?

@bkoelman
Copy link
Member

Hi @bkoelman, I'll try finishing that PR. Could you have a pass on its current state, I'll add tests for Kiota once the one for NSwag start looking okay. Also, is there anything worth adding to the doc regarding this change?

Cool! Sure, I'll take a look. I don't expect the docs need to be updated, unless there are pitfalls users should know about. For kiota, it's worth removing the --log-level Error switch temporarily to see what comes up. However, kiota is pretty rigid and inflexible, so don't worry too much about its quirks.

Copy link
Member

@bkoelman bkoelman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added some comments on things that jumped out to me. Before focussing on kiota, we should get the proposed scope table in better shape.

@verdie-g verdie-g requested a review from bkoelman May 30, 2024 02:05
Copy link
Member

@bkoelman bkoelman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments. The test coverage needs adjustment, based on the table (that isn't finished yet). I would expect to see some net80-only tests too.

@verdie-g
Copy link
Contributor Author

verdie-g commented Jun 4, 2024

I'll resume the work in a few days

Copy link
Member

@bkoelman bkoelman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not seeing any end-to-end tests for the .NET 8 attributes.

Oh well, I expected to find #if lines, but end-to-end tests can't multi-target so it's .NET 8 only.

@bkoelman
Copy link
Member

I've completed the table except the EF Core column which I think is out-of-scope for this PR.

I've mentioned earlier that the goal of writing end-to-end tests is to assess the overall experience our users will face. This doesn't mean we need to write tests for EF Core features in this PR, but we do need to check for oddities and possibly create separate issues to address them, or document things to watch out for. So I disagree that it's out of scope. Otherwise, I wouldn't have added the EF Core column in the first place.

@verdie-g
Copy link
Contributor Author

verdie-g commented Jun 13, 2024

Here is the single SQL statement to create the table

CREATE TABLE "SocialMediaAccounts" (
    "Id" uuid NOT NULL,
    "AlternativeId" uuid,
    "FirstName" text,
    "LastName" text NOT NULL,
    "UserName" character varying(18),
    "CreditCard" text,
    "Email" text,
    "Password" text,
    "Phone" text,
    "Age" double precision,
    "ProfilePicture" text,
    "BackgroundPicture" text,
    "Tags" text[],
    "CountryCode" text,
    "Planet" text,
    "NextRevalidation" interval,
    "ValidatedAt" timestamp with time zone,
    "ValidatedAtDate" date,
    "ValidatedAtTime" time without time zone,
    CONSTRAINT "PK_SocialMediaAccounts" PRIMARY KEY ("Id")
);

I've updated the table accordingly.

Copy link

codecov bot commented Jun 15, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 91.30%. Comparing base (459ced3) to head (54fedf2).

Additional details and impacted files
@@           Coverage Diff            @@
##           openapi    #1477   +/-   ##
========================================
  Coverage    91.30%   91.30%           
========================================
  Files          396      396           
  Lines        12834    12834           
  Branches      2028     2028           
========================================
  Hits         11718    11718           
  Misses         725      725           
  Partials       391      391           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@verdie-g verdie-g requested a review from bkoelman June 15, 2024 20:58
@verdie-g verdie-g marked this pull request as ready for review June 15, 2024 21:55
Copy link
Member

@bkoelman bkoelman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work on filling out the feature table.

Please update the following entries, replacing the '?':

  • | [ValidateNever] | - | N | N | N |
  • | [Remote] | - | N | N | N |

Also, readOnly and writeOnly need to move one column to the right. I've tried adding properties for them, but set-only causes a crash inside Microsoft.AspNetCore.Mvc.ModelBinding.GetMetadataForProperty, so let's forget about them.

I'm working on a PR to support atomic:operations in OpenAPI, which has heavy changes throughout all tests that I don't want to disturb you with. So if feasible, I'd like to get this PR merged first. With some luck, mine will be completed somewhere next week. No pressure, but it would be nice if we can get this one finalized in the next few days.

@verdie-g verdie-g requested a review from bkoelman June 19, 2024 23:20
@bkoelman
Copy link
Member

bkoelman commented Jun 20, 2024

The table update isn't correct. The Y/N columns need to move.
image

The same applies to: [Compare], [AllowedValues], [DeniedValues], [Remote], and [ValidateNever].

Copy link
Member

@bkoelman bkoelman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've created domaindrivendev/Swashbuckle.AspNetCore#2957 for the missing .NET 8 entries.

@verdie-g
Copy link
Contributor Author

The Y/N columns need to move.

I used N to specify that it's not supported. I can use - instead.

@verdie-g verdie-g requested a review from bkoelman June 20, 2024 12:32
Copy link
Member

@bkoelman bkoelman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments. Not all changes have been applied yet, and unexpected parts got deleted.

@verdie-g
Copy link
Contributor Author

Both (remove culture and change assertions) haven't been addressed yet.

I'm not able to access the comment to answer but I could you clarify what you are expecting here.

@bkoelman
Copy link
Member

Both (remove culture and change assertions) haven't been addressed yet.

I'm not able to access the comment to answer but I could you clarify what you are expecting here.

Using the dollar sign and putting literal values in there, so it becomes culture-insensitive.

@verdie-g verdie-g requested a review from bkoelman June 21, 2024 18:49
Copy link
Member

@bkoelman bkoelman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this is in great shape now!

@bkoelman bkoelman merged commit e35da84 into json-api-dotnet:openapi Jun 21, 2024
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants