cakephp-swagger-bake icon indicating copy to clipboard operation
cakephp-swagger-bake copied to clipboard

OpenApiSchemaProperty support array of objects

Open ChrisB85 opened this issue 2 years ago • 11 comments

Hi,

I'm reimplementing legacy API using CakePHP 5 and by the way of doing this I also want to document it with SwaggerBake.

Let's say I have controller action like:

#[OpenApiResponse(schemaType: 'array', schema: ArticlesCollectionElement::class)]
public function findArticles()
{
...
}

and the response is:

[
    {
        "Article": {
            "name": "some name",
            "id": 7204
        },
        "Producer": {
            "name": "Some name",
            "id": 325
        },
        "Language": {
            "symbol": "en",
            "id": 1
        }
    }
]

I'm using custom schema ArticlesCollectionElement as a OpenApiResponse schema:

#[OpenApiSchema(visibility: OpenApiSchema::VISIBLE_ALWAYS)]
class ArticlesCollectionElement extends DataTransferObject
{
    /**
     * @var ArticleProperties
     */
    #[OpenApiSchemaProperty(name: 'Article', type: 'object')]
    public ArticleProperties $Article;

    ...other properties

}

So here I would like to use object property of type ArticleProperties:

#[OpenApiSchema(visibility: OpenApiSchema::VISIBLE_ALWAYS)]
class ArticleProperties extends DataTransferObject
{
    #[OpenApiSchemaProperty(name: 'id', type: 'string', format: 'int32', example: '3214')]
    public string $id;
    #[OpenApiSchemaProperty(name: 'name', type: 'string', example: 'Some name')]
    public string $name;
}

I think I would need something like:

#[OpenApiSchemaProperty(name: 'Article', type: 'object', ref: ArticleProperties::class)]

The problem is that OpenApiSchemaProperty does not have ref param. Am I missing something or this is just not possible to define object properties like that? Is there any workaround for this?

ChrisB85 avatar Apr 25 '24 20:04 ChrisB85

Am I understanding the main goal is to return a custom array of objects?

cnizzardini avatar Apr 25 '24 20:04 cnizzardini

I'd have to probably dig into this one for a bit. Off the top of my head your immediate workarounds (if this indeed is not possible) are:

Events: https://github.com/cnizzardini/cakephp-swagger-bake#event-system CustomSchemaInterface: https://github.com/cnizzardini/cakephp-swagger-bake/blob/master/docs/attributes.md#schema

cnizzardini avatar Apr 25 '24 20:04 cnizzardini

Am I understanding the main goal is to return a custom array of objects?

Yes exactly. I think it's the only thing missing to get full flexibility in documenting custom code. I'll see if I can do something with Events and CustomSchemaInterface.

Thanks!

ChrisB85 avatar Apr 26 '24 16:04 ChrisB85

@ChrisB85 did this solve your needs?

cnizzardini avatar May 04 '24 02:05 cnizzardini

Unfortunately not. I tried to use events to modify the Swagger object but at some point I realized that It's just bad (to complicated) solution if I need to document many endpoints that way.

ChrisB85 avatar May 05 '24 09:05 ChrisB85

Yeah I agree, I think your use-case is reasonable. I'll note this as a feature request.

cnizzardini avatar May 05 '24 17:05 cnizzardini

I think I've actually had this need in one of my applications, but out of sheer laziness have just left that portion of the schema not documented well.

cnizzardini avatar May 05 '24 17:05 cnizzardini

I'm curious @ChrisB85, if for a more reasonable short-term work around, can you use a mixture of $ref and OpenApiSchemaProperty. Something like this:

OpenAPI Schema:

#[OpenApiSchema(visibility: OpenApiSchema::VISIBLE_ALWAYS)]
class ArticleProperties extends DataTransferObject
{
    #[OpenApiSchemaProperty(name: 'id', type: 'string', format: 'int32', example: '3214')]
    public string $id;
    #[OpenApiSchemaProperty(name: 'name', type: 'string', example: 'Some name')]
    public string $name;
}

Controller:

#[OpenApiResponse(schemaType: 'array' ,ref: '#/components/schemas/ArticlesCollection')]
public function findArticles()
{
    // controller action code...
}

OpenAPI YAML:

components:
  schemas:
    ArticlesCollection:
      properties:
                  data:
                    items:
                      type: object
                      allOf:
                        - $ref: '#/components/schemas/ArticleProperties'
                    type: array

I think something like that may be possible. The idea being, document the object in your DTO, use OpenAPI YAML to document that its part of collection and then reference the YAML ref in your controller action.

cnizzardini avatar May 05 '24 17:05 cnizzardini

Thank you very much, I will try it :)

ChrisB85 avatar May 08 '24 19:05 ChrisB85

Sorry for a delay, today I finally had some time to use your sugesstion. Unfortunatelly the ArticleProperties schema is not included into swagger.json so I get result like: image I think I need some clever way to include it.

ChrisB85 avatar May 11 '24 15:05 ChrisB85

Ah this makes sense, I think its only adding schemas when there is an associated route. You can try adding this attribute and setting visibility, but I am not sure it will work. We are in slightly uncharted territory:

https://github.com/cnizzardini/cakephp-swagger-bake/blob/master/docs/attributes.md#openapischema

cnizzardini avatar May 12 '24 15:05 cnizzardini