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

Example for object does not work #209

Closed
mzielinski opened this issue Jan 29, 2024 · 3 comments
Closed

Example for object does not work #209

mzielinski opened this issue Jan 29, 2024 · 3 comments
Assignees
Labels
investigation question Further information is requested

Comments

@mzielinski
Copy link

Actual behavior (the bug)

static class Barbie {

    private String name;
    private String link;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getLink() {
        return link;
    }

    public void setLink(String link) {
        this.link = link;
    }
}

// should contain object example
@OpenApiExample(objects = {
    @OpenApiExampleProperty(name = "name", value = "Margot Robbie"),
    @OpenApiExampleProperty(name = "link", value = "https://www.youtube.com/watch?v=dQw4w9WgXcQ")
})
public @NotNull Barbie getExampleObjects() {
    return new Barbie();
}

With such configuration, at the end I do not see my examples in the OpenAPI specification

"exampleObjects": {
    "name": "string",
    "link": "string"
}

Specification which is generated is

"exampleObjects": {
    $ref": "#/components/schemas/Barbie",
    "example": {
        "name": "Margot Robbie",
        "link": "https://www.youtube.com/watch?v\u003ddQw4w9WgXcQ" 
    }
}     

....

"Barbie": {
    "type": "object",
    "additionalProperties": false,
    "properties": {
        "name": {
            "type": "string"
        },
        "link": {
            "type": "string"
        }
    }
}

Expected behavior

I would expect, that example should be injected to the openapi description like

"exampleObjects": {
    "name": "Margot Robbie",
    "link": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
}

So specification code generated should be more like

"exampleObjects": {
    "$ref": "#/components/schemas/Barbie",
},          

....
          
"Barbie": {
    "type": "object",
    "additionalProperties": false,
    "properties": {
        "name": {
            "type": "string",
            "example": "Margot Robbie"
        },
        "link": {
            "type": "string",
            "link": "https://www.youtube.com/watch?v\u003ddQw4w9WgXcQ"
        }
    }
}

Additional context

Currently, when I change type to Barbie[] (the same as we have in existing example Object[]), then it is properly injected example, but it requires to change specification, what it not acceptable.

@dzikoysk dzikoysk added question Further information is requested investigation labels Jan 29, 2024
@dzikoysk dzikoysk self-assigned this Jan 29, 2024
@dzikoysk
Copy link
Member

dzikoysk commented Jan 29, 2024

The intention behind @OpenApiExample(object = {}) is to attach an example in-place, for e.g. unknown types or this particular use-case (different examples in e.g. request body & in generic entity scheme description), so it's not leaked to referenced types. Thanks to that, we can provide such formats for e.g. Object type:

// should contain inline object example
@OpenApiExample(objects = {
    @OpenApiExampleProperty(name = "name", value = "Margot Robbie"),
    @OpenApiExampleProperty(name = "link", value = "https://www.youtube.com/watch?v=dQw4w9WgXcQ")
})
public @NotNull Object getInlinedExampleObject() {
    return new String[] { timestamp };
}

results in:

"inlinedExampleObject" : {
  "type" : "object",
  "example" : {
    "name" : "Margot Robbie",
    "link" : "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  }
}

And this:

// should contain object example
@OpenApiExample(objects = {
        @OpenApiExampleProperty(name = "Barbie", objects = {
                @OpenApiExampleProperty(name = "name", value = "Margot Robbie"),
                @OpenApiExampleProperty(name = "link", value = "https://www.youtube.com/watch?v=dQw4w9WgXcQ")
        }),
})
public @NotNull Object[] getExampleObjects() {
    return new String[] { timestamp };
}

results in:

"exampleObjects" : {
  "type" : "array",
  "items" : {
    "type" : "object"
  },
  "example" : {
    "Barbie" : {
      "name" : "Margot Robbie",
      "link" : "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
    }
  }
},

If we know the type tho, such as your Barbie type, and we want to define global example for specific fields, it should be specified directly on properties within this type, like here:

static final class Foo {
private String property;
private String link;
public String getProperty() {
return property;
}
@OpenApiExample("https://www.youtube.com/watch?v=dQw4w9WgXcQ")
public String getLink() {
return link;
}
}

So in the referenced object:

"foos" : {
  "type" : "array",
  "items" : {
    "$ref" : "#/components/schemas/Foo"
  }
},

we can see these dedicated examples:

"Foo" : {
  "type" : "object",
  "additionalProperties" : false,
  "properties" : {
    "property" : {
      "type" : "string"
    },
    "link" : {
      "type" : "string",
      "example" : "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
    }
  }
},

As far as I understand, you'd like to achieve a similar result by enforcing @OpenApiExample to override examples in referenced entities. If that's correct, then I see 3 issues:

  1. Descriptions defined on a reference side, not in the entity definition, can overlap - e.g. the same entity can be used in 2 or more places. Each of them can define a custom description, so we're ending up with an entity definition that has multiple examples.
  2. It might be a bit unclear that there are 2 approaches to do the same thing
  3. It might be a little bit painful to implement 😅

@dzikoysk
Copy link
Member

dzikoysk commented Jan 29, 2024

I've updated the example to cover this with cases we were talking about:

// should contain dedicated foo example
@OpenApiExample(objects = {
@OpenApiExampleProperty(name = "name", value = "Margot Robbie"),
@OpenApiExampleProperty(name = "link", value = "Dedicated link")
})
public @NotNull Foo getExampleFoo() {
return new Foo();
}
// should contain object example
@OpenApiExample(objects = {
@OpenApiExampleProperty(name = "name", value = "Margot Robbie"),
@OpenApiExampleProperty(name = "link", value = "https://www.youtube.com/watch?v=dQw4w9WgXcQ")
})
public @NotNull Object getExampleObject() {
return new String[] { timestamp };
}
// should contain objects example
@OpenApiExample(objects = {
@OpenApiExampleProperty(name = "Barbie", objects = {
@OpenApiExampleProperty(name = "name", value = "Margot Robbie"),
@OpenApiExampleProperty(name = "link", value = "https://www.youtube.com/watch?v=dQw4w9WgXcQ")
}),
})
public @NotNull Object[] getExampleObjects() {
return new String[] { timestamp };
}

That returns:

 "exampleFoo" : {
  "$ref" : "#/components/schemas/Foo",
  "example" : {
    "name" : "Margot Robbie",
    "link" : "Dedicated link"
  }
},
"exampleObject" : {
  "type" : "object",
  "example" : {
    "name" : "Margot Robbie",
    "link" : "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  }
},
"exampleObjects" : {
  "type" : "array",
  "items" : {
    "type" : "object"
  },
  "example" : {
    "Barbie" : {
      "name" : "Margot Robbie",
      "link" : "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
    }
  }
},

and unaffected example (as expected) in the Foo scheme:

"Foo" : {
  "type" : "object",
  "additionalProperties" : false,
  "properties" : {
    "link" : {
      "type" : "string",
      "example" : "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
    }
  }
},

If I missed the point, just let me know.

@mzielinski
Copy link
Author

It is clear. Thank you for adding additional test, and explaining about the issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
investigation question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants