-
-
Notifications
You must be signed in to change notification settings - Fork 159
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
Explore usage of Microsoft.AspNetCore.OpenApi #1591
Comments
These are great, thanks. The last one I don't understand, can you clarify?
See here for details.
Yes, that's a big blocker. Task<OpenApiSchema> IOpenApiSchemaFactory.GetOrCreateSchemaAsync(Type, ApiParameterDescription?, OpenApiSchemaStore) Assuming ASP.NET ships with implementation services.AddSingleton<DefaultOpenApiSchemaFactory>();
services.AddSingleton<IOpenApiSchemaFactory, CustomOpenApiSchemaFactory>(); and inject Oh, and The other big challenge is moving lots of logic from schema generators to the
I suspect dotnet/aspnetcore#56305 (comment) answers your question. To get an impression of the
We can't use attributes, the set of derived types depends on the runtime model. See here.
No, this is unrelated to var updatePersonRequest = new UpdatePersonRequestDocument
{
Data = new DataInUpdatePersonRequest
{
// omitted: Type = PersonResourceType.People,
Id = "1",
Attributes = new AttributesInUpdatePersonRequest
{
LastName = "Doe"
}
}
};
var response = await _apiClient.PatchPersonAsync(updatePersonRequest.Data.Id, updatePersonRequest); This works because NSwag generates the following: public enum PersonResourceType
{
[System.Runtime.Serialization.EnumMember(Value = @"people")]
People = 0,
}
public partial class DataInUpdatePersonRequest
{
[Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)]
[System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)]
[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
public PersonResourceType Type { get; set; } = default!;
// ...
}
We have a case where it's impossible to determine upfront whether the property is nullable, see here, handled here. So we'll still need to be able to override that from code. Perhaps it can be worked around by having an additional
Thanks for understanding. The thing is our team is very limited on resources. Everything is done in spare time. My current priority is finishing OpenAPI support, so we can release a new major version near the end of the year and drop .NET 6. I'd love to spend more time on M.A.OpenAPI, but it already comes at the cost of not being able to support the latest C# and EF Core features. These are hard tradeoffs, and nothing is set in stone. I think we'll release as I've taken a look at the preview 6 code, some remarks below.
Hope this helps. |
Regarding |
Yep, this point is heard. And it's come up in other scenarios as well. At the moment, I'm not super eager to expose too much of M.A.OpenAPI's schema generation pipeline, particularly as we look towards a future where JSON schema is more unified in the OpenAPI specification (v3.1 and v4). In the long-term, I'd hope that most of these customizations are actually exposed at the lower level by System.Text.Json and it's JsonSchemaExporter APIs -- that way schemas for types are consistent across all implementations (validators, generators, etc.) and not just OpenAPI. With that in mind...
...out of curiousity, what does your schema generation do that existing implementations don't? Is this primarily about encoding information that goes beyond how System.Text.Json serializes things? There's been discussion about exposing some sort of data-contract resolver layer in System.Text.Json where types could describe how their schemas should look. Would something like that work for you?
Hmmmm....I'd expect schemas to be an accurate reflection of the binding/serialization rules of an API. Is the most common scenario for this "hiding" priveliged schemas from non-admin users or are the mutations much more dynamic? How does this come into play if users are trying to feed the documents into spec testing/client gen tools? Do you always have to carry a user persona with the document you generate?
This seems like a good choice. It also makes it clear what implementation you're taking a dependency on for those who care. As I read more and more of the details of your implementation, I am inclined to think that exploring an implementation that leans more into ApiExplorer might be good to explore after you've completed the integration work with Swashbuckle.
Operation transformers should help with the massaging here. There's also been disucssion about adding a
The It might also be interesting to explore if we should add a property to ApiExplorer's ApiParameterDescription to help with this.
ApiExplorer captures MVC's
Similar to the above, the ApiExplorer metadata layer should map these correctly into the
The PR that you linked seems to indicate that Swashbuckle is still using |
I understand pushback on opening things up too early, which would require breaking changes later. However, I'm not convinced using
In short: adapt the schema to make it JSON:API compliant (see https://jsonapi.org/ for an example), based on the runtime entity model and startup configuration. For example, JSON:API uses HATEOAS links (which obviously don't exist in entity models). Related entities come at the end of the response in an array, instead of inline. Related data is exposed as either a single object or an array, depending on whether its parent is a to-one or to-many relationship. There are specific rules about the meaning of
Marginally. STJ is optimized for throughput and OAT, producing subtrees that are independent of their parents. In contrast, OpenAPI generation depends on runtime information and component schemas reference each other (even recursively, in the case of
The mutations are much more dynamic, because they originate from user code through our extensibility points. As far as I'm aware, it's possible in ASP.NET to add controllers at runtime (we don't use that), so I'd assume (haven't checked) that the information in ApiExplorer must be dynamic as well. But more importantly, a singleton schema store isn't thread-safe: if two concurrent requests render the openapi.json document, they'll influence each other. Our schema generators are singletons, yet they manipulate the passed-through schema store. It's not possible to add a transient dependency to a singleton, so where to store intermediate state then?
I agree, but it wouldn't help that much. We can prepare things like documentation that would otherwise be read from an attribute, but the bulk of the work needs to be done during schema generation. One case I haven't mentioned: we create a temporary schema store (not exposed to Swashbuckle) that we use internally to reuse (variants of) reference schemas. This works because the schema store holds just a simple dictionary, there are no parent/child object references.
We also use descriptions from XML comments (again, not in the regular way, because the object structure differs, so we parse the assembly.xml ourselves). The documentation I referred to doesn't exist in user code (ASP.NET controllers use a generic type parameter for You're right these can be solved using operation transformers. Additional properties to store these in
I don't think that is correct. The information is not obtained from ApiExplorer, the code literally scans for the presence of
Swashbuckle supports both, see the docs. None of the client generators I've tried work with |
@bkoelman Following up on the comment that you left in the issue on the ASP.NET Core repo here.
The
Microsoft.AspNetCore.OpenApi
implementation has evolved to cover some of the scenarios that you listed originally including:OpenApiOptions.CreateSchemaReferenceId
(in PR)The biggest gap I noticed is around your schema generation-based customizations. Our implementation currently relies on the new
JsonSchemaExporter
APIs in System.Text.Json (.NET 9 Preview 6) and that layer doesn't have as many of the customizability options that Swashbuckle has. That being said, I'd be curious to understand the details of some of the items you mentioned in your bullet list from the comment above:Do you use
allOf
to model inheritance hierarchies in your documents or is that something that you disable? This isn't an option that we currently support inM.A.OpenApi
, primarily because its iffy whether or notallOf
can be used to accuratnely model inheritance hierarchies in JSON schema.What discriminators are you referring to in the statement above? At the moment, our implementation supports STJ's polymorphism attributes by default. Does your library provide a custom set?
I assume you're doing this to work around the limitation in OpenAPI v3 that the JSON Schema
const
keyword is not supported? If so, I don't really have a good solution for that since our system has to comply with a similar constraint. We do expose a schema transformers concept (similar to schema filters) that can help here.Requiredness/nullability are modeled independently in our system so you should be able to model required properties that can be null if need be.
But to a more general point, I think your statement here:
is prudent and wise. It seems like you've done a lot of work in the area already building our Swashbuckle's model and I wouldn't through that away. In the future, it would be interesting to explore if you can extend this to support M.A.OpenAPI as well, and perhaps go even further and recommend some API changes to the underlying ApiExplorer metadata layer that both Swashbuckle/M.A.OpenAPI use for document generation to make your framework more resilient to whatever API document spec is supported.
I hope this information was helpful! If you have any inquiries about this work (particularly in regard to the more ASP.NET Core-related aspects), I'm happy to share insights.
Originally posted by @captainsafia in #1046 (comment)
The text was updated successfully, but these errors were encountered: