OData / AspNetCoreOData

ASP.NET Core OData: A server library built upon ODataLib and ASP.NET Core
Other
458 stars 158 forks source link

OpenApi definition for enum returning function mismatches API output #1324

Open manio143 opened 1 month ago

manio143 commented 1 month ago

Assemblies affected ASP.NET Core OData 8.x

Describe the bug When an OData Unbound Function returns an Enum value, the OpenApi definition for that function references the enum type as the schema. However, in practice the enum value is returned wrapped in a JSON object (with a value property). This means that clients generated based on the OpenApi definition expect to see a JSON string but see a JSON object and fail to parse.

Note that this may be generalized to other value types and other types of functions.

Data Model

public enum MyEnum { A }
public class FunctionController : ODataController
{
    public Task<MyEnum> Fun() => Task.FromResult(MyEnum.A);
}

// Edm
var builder = new ODataConventionModelBuilder();
builder.Function(nameof(FunctionController.Fun))
    .Returns<MyEnum>();

// DI
services
    .AddControllers()
    .AddOData(options => options.AddRouteComponents(builder.GetEdmModel()));

// Configure
app.UseODataOpenApi();

Expected behavior Calling $openapi endpoint should generate the OpenApi document according to what will be returned from the API. In this case something like:

{
  "paths": {
    "/Fun": {
      "responses": {
        "200": {
          "content": {
            "application/json": {
              "schema": {
                "title": "FunResponse"
                "type": "object",
                "properties": {
                  "value": {
                    "$ref": "#/components/schema/MyEnum"
                  }
                }

Actual behavior The OpenApi definition doesn't mention that an object is returned but rather that an enum value is returned straight away.

{
  "paths": {
    "/Fun": {
      "responses": {
        "200": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schema/MyEnum"
              }

Additional context This is handled correctly for collections where { value: [...] } is returned from the API. But for scalars the scalar type is reported rather than object which wraps the scalar value.

xuzhg commented 1 month ago

@manio143 I assume you are using codes from this folder: https://github.com/OData/AspNetCoreOData/tree/main/sample/ODataRoutingSample/OpenApi since you call app.UseODataOpenApi();

The OpenAPI conversion is based on Microsoft.OpenApi.Reader nuget package, This line (https://github.com/microsoft/OpenAPI.NET.OData/blob/master/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiEdmTypeSchemaGenerator.cs#L426) is the latest version to generate the response for the return of 'Enum type'.

So, did you try different version? I am not sure whether it's an issue at that side.

manio143 commented 1 month ago

Yes, I believe you're correct it's the Microsoft.OpenApi.OData.Reader that is responsible for generating this kind of definition.

So, did you try different version? I am not sure whether it's an issue at that side.

Can you clarify this question? If I tried to use a different version of?

Should I instead look to create an issue on the other package's repository, right?