phpsymfonyopenapiapi-platform

generate OpenAPI for Symfony customControllers with api platform


I just got started with Symfony (7.1) and created a Controller. Now I want to generate an OpenAPI description for the controller endpoints and I've found api_platform (4.0) for that. (https://api-platform.com/docs/core/controllers/)

I installed the api_platform package and I can't get it working. I would like to define the response to be json if possible with the properties defined in BlocDto.

What is missing to get that working, or is that not possible?

The Controller. (The endpoint works when I omit the defaults.)

<?php

namespace App\Controller;

use App\DTO\BlocDto;
use App\Repository\BlocRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Attribute\Route;

class BlocsController extends AbstractController
{
    private $blocRepository;
    public function __construct(BlocRepository $blocRepository)
    {
        $this->blocRepository = $blocRepository;
    }

    #[Route(
      path: '/blocs/{id}',
      name: 'get-bloc',
      methods: ['GET', 'HEAD'],
      defaults: [
        '_api_resource_class' => BlocDto::class,
        '_api_operation_name' => 'getBloc'
      ])]
    public function getBloc($id): JsonResponse
    {
        $bloc = $this->blocRepository->find($id);

        return $this->json([
          'id' => $bloc->getId(),
          'name' => $bloc->getName(),
          'description' => $bloc->getDescription(),
          'blocLowRes' => $bloc->getBlocLowRes(),
          'blocMedRes' => $bloc->getBlocMedRes(),
          'blocHighRes' => $bloc->getBlocHighRes(),
        ]);
    }
}

BlocDto.php

<?php

namespace App\DTO;

use Symfony\Component\Validator\Constraints as Assert;

class BlocDto
{
    public function __construct(
      #[Assert\NotBlank]
      public string $id,

      #[Assert\NotBlank]
      public string $name,

      public string $description,

      public string $blocLowRes,

      public string $blocMedRes,

      public string $blocHighRes)
    { }
}

aparently the config/packages/api_platform.yaml should look like this:

api_platform:
    title: Boulder Api
    version: 1.0.0
    use_symfony_listeners: true
    defaults:
        stateless: true
        cache_headers:
            vary: ['Content-Type', 'Authorization', 'Origin']


Solution

  • Mainly API Platform is for building a API. So it is not the best fit for the documentation of a custom build API but it should work.

    API Platform work based on entities. The entity Bloc, for wich the BlocDto is build for, should be marked as ApiResource. Then in an Get() endpoint definition give API Platform the information about the route and the Dto.

    I'm not 100% sure about which parameter the Get() endpoint need, because I did it only with Post() endpoints and Dto's. But it should be an good starting point.

    <?php
    
    namespace App\Entity;
    
    use Doctrine\ORM\Mapping as ORM;
    use ApiPlatform\Metadata\ApiResource;
    use ApiPlatform\Metadata\Get;
    use App\Controller\BlocsController;
    use App\DTO\BlocDto;
    
    #[ORM\Entity()]
    #[ApiResource(
        operations: [
            new Get(uriTemplate: 'bloc/{id}', routeName: 'get-bloc', output: BlocDto::class, outputFormat: 'json')
        ]
    )]
    class Bloc
    {
        ...
    }
    

    For further information see Using Data Transfer Object and Operations in the API Platform documentation.