0

Really sorry if I've missed something here, but I have searched the issues and docs high and low, and I cannot find why this is not working. Perhaps I need another tutorial on using the internet ;)

Consider the following entity annotation, in the openapi_context section the body.description and responses.200.description have no effect at all, and its driving me slightly mad... You should know that I am using de/normalization contexts but that doesn't seem related so I have left it out.


/**
 * User entity
 *
 * @API\ApiResource(
 *  collectionOperations={
 *      "authenticate"={
 *          "method"="POST",
 *          "status"=200,
 *          "path"="/authenticate",
 *          "controller"=UserLoginController::class,
 *          "openapi_context"={
 *              "responses"={"200"={"description"="API token and secret"}},
 *              "body"={"description"="Login details"},
 *              "summary"="User authentication",
 *              "description"="Provides auth tokens on success",
 *          },
 *      },
 *  }
 * )
 *
 */
class User implements UserInterface
{
    ...
}

The result (blue blocks as expected, red blocks not working): enter image description here

I have spent way too much time on this issue as it is, I would really appreciate it if someone could help me put this to bed. I have checked/tried the following to no avail;

Composer versions (relevant parts):

{
    "require": {
        "php": ">=7.2.5",
        "api-platform/core": "^2.6",
        "symfony/framework-bundle": "5.2.*"
    }
}

1 Answer 1

2

After some experimenting, I found that the openapi_context annotation attribute does indeed seems to ignore the response documentation. It does however allow you to provide the request body description that you are missing:

#[ApiResource(
    collectionOperations: [
        'test' => [
            'method' => 'POST',
            'path' => '/test',
            'openapi_context' => [
                'summary' => 'The endpoint summary',
                'description' => 'The endpoint description',
                'requestBody' => [
                    'description' => 'The endpoint request body description', // This one
                    'content' => [
                        'application/json' => [
                            'schema' => [
                                '$ref' => '#/components/schemas/MyResource-some.group'
                            ],
                        ],
                    ],
                ],
            ],
        ]
    ],
)]

I'm using PHP 8.0.3 and API Platform 2.6.3 while writing this, changing the annotations to docblocks should result in the same outcome for you though.

In order to document the endpoint response specification however, I had to implement a custom OpenApiFactoryInterface:

<?php declare(strict_types = 1);

namespace App;

use ApiPlatform\Core\OpenApi\Factory\OpenApiFactoryInterface;
use ApiPlatform\Core\OpenApi\Model\Operation;
use ApiPlatform\Core\OpenApi\Model\PathItem;
use ApiPlatform\Core\OpenApi\Model\RequestBody;
use ApiPlatform\Core\OpenApi\OpenApi;
use ArrayObject;
use UnexpectedValueException;

class MyResourceOpenApiFactory implements OpenApiFactoryInterface
{
    private OpenApiFactoryInterface $openApiFactory;

    public function __construct(OpenApiFactoryInterface $openApiFactory)
    {
        $this->openApiFactory = $openApiFactory;
    }

    public function __invoke(array $context = []): OpenApi
    {
        $openApi = ($this->openApiFactory)($context);
        $components = $openApi->getComponents();
        $schemas = $components->getSchemas();
        if (null === $schemas) {
            throw new UnexpectedValueException('Failed to obtain OpenApi schemas');
        }

        $pathItem = new PathItem(
            'MyResource test endpoint',
            'A test summary',
            'A test description',
            null,
            null,
            // Your custom post operation
            new Operation(
                'testMyResourceCollection', // the operation route name
                [
                    'MyResource' // your resource name
                ],
                [
                    // response specifications
                    '201' => [
                        'description' => 'test endpoint 201 response description',
                        'content' => [
                            'application/json' => [
                                'schema' => [
                                    '$ref' => '#/components/schemas/MyResource-read', // your resource (read) schema
                                ],
                            ],
                        ],
                    ],
                ],
                'A test endpoint summary',
                'A test endpoint description',
                null,
                [],
                new RequestBody(
                    'A test request body description',
                    new ArrayObject([
                        'application/json' => [
                            'schema' => [
                                '$ref' => '#/components/schemas/MyResource-write', // your resource (write) schema
                            ],
                        ],
                    ]),
                ),
            ),
        );

        $paths = $openApi->getPaths();
        $paths->addPath('/my_resources/test', $pathItem);
        return $openApi;
    }
}

Have this OpenApiFactoryInterface implementation wired by the service container as a decorator to api_platform.openapi.factory:

App\MyResourceOpenApiFactory:
    decorates: 'api_platform.openapi.factory'
    autoconfigure: false

Change the references to the example MyResource name to a resource name of your choice (like User).

Sidenote: This whole process of customizing OpenApi endpoint documentation in API Platform is currently quite convoluted in my opinion. Use the implementation I provided as a reference to your own implementation, as you most likely need to make a few adjustments to it in order to make it satisfy your specific use case.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the detailed answer. I have prematurely marked it as correct as I was about to look into Open API factory (as per advice on one of their reported issues) and based on what you've explained it seems the best approach. I am assuming the interface will replace the annotation for openapi_context, thanks for this. A big +1 from me

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.