nelmio / NelmioApiDocBundle

Generates documentation for your REST API from annotations
MIT License
2.23k stars 834 forks source link

[Bug]: Symfony Assert NotBlank 'groups' options is ignored #2350

Closed HercDotMe closed 5 days ago

HercDotMe commented 5 days ago

Version

v4.32.0

Description

The Assert\NotBlank is an alias for Symfony\Component\Validator\Constraints\NotBlank. This constraint has the groups option which works correctly in the Symfony Validator. However, the documentation generated by Nelmio with the Swagger UI frontend wrongly depicts the property as required regardless of the group.

I have the following code in my DTO class:

#[Groups(['create', 'update'])]
#[Assert\NotBlank(groups: ['create'])]
#[OA\Property(type: 'string', format: 'password', nullable: true)]
public ?string $password;

And in my Controller class:

#[OA\Put(
    description: 'Update an existing user',
    summary: 'Update user',
    requestBody: new OA\RequestBody(
        content: new OA\JsonContent(
            ref: new Model(type: UserUpdate::class, groups: ['update'])
        )
    )
)]

The resulting rendering of the docs shows the password field as required for the Update call although it should not as it does not use the create group when building the schema.

Functionally everything works, the schema built by the Nelmio bundle incorrectly shows the call requirements. The JSON Schema built is also incorrect as the UserUpdate

JSON OpenApi

JSON OpenApi ```json { "openapi": "3.0.0", "info": { "title": "User Manager API", "description": "An API that allows for user management", "version": "1.0.0" }, "paths": { "/api/v1/user/": { "post": { "tags": [ "User" ], "summary": "Create user", "description": "Create a new user", "operationId": "post_api_v1_user_create", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserCreate" } } } }, "responses": { "200": { "description": "Returns the created user", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/User" } } } } } } }, "/api/v1/user/{id}": { "get": { "tags": [ "User" ], "summary": "Read user", "description": "Read a user", "operationId": "get_api_v1_user_read", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Returns an existing user", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/User" } } } } } }, "put": { "tags": [ "User" ], "summary": "Update user", "description": "Update an existing user", "operationId": "put_api_v1_user_update", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserUpdate" } } } }, "responses": { "200": { "description": "Returns the updated user", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/User" } } } } } }, "delete": { "tags": [ "User" ], "summary": "Delete user", "description": "Delete an existing user", "operationId": "delete_api_v1_user_delete", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "Returns the deleted user", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/User" } } } } } } } }, "components": { "schemas": { "UserCreate": { "required": [ "emailConfirm", "passwordConfirm", "email", "password" ], "properties": { "emailConfirm": { "type": "string", "format": "email" }, "passwordConfirm": { "type": "string", "format": "password" }, "email": { "type": "string", "format": "email" }, "password": { "type": "string", "format": "password" } }, "type": "object" }, "User": { "required": [ "email", "password" ], "properties": { "id": { "type": "integer", "readOnly": true }, "email": { "type": "string", "maxLength": 255 }, "password": { "type": "string", "maxLength": 255, "writeOnly": true }, "createdAt": { "type": "string", "format": "date-time", "readOnly": true }, "updatedAt": { "type": "string", "format": "date-time", "readOnly": true } }, "type": "object" }, "UserUpdate": { "required": [ "email", "password" ], "properties": { "email": { "type": "string", "format": "email" }, "password": { "type": "string", "format": "password" } }, "type": "object" } } }, "tags": [ { "name": "User" } ] } ```

Additional context

No response

HercDotMe commented 5 days ago

Sorry for the bug report, it looks like setting use_validation_groups: true fixes this issue! I think that this should be added somewhere more visibly in the Symfony Docs for the bundle.