0

I’m trying to create a getCollection route using POST with API Platform. The idea is to perform a search that takes a JSON payload to handle search conditions first, and later manage relations, sorting, etc.

I don’t want to use GET, because I might run into URL length limitations, and I also want to be able to easily work with it in tools like Postman, for example.

I’ve already tried the following:

https://api-platform.com/docs/symfony/controllers/

API Platform and custom POST operation with custom body (outdated)

https://github.com/api-platform/api-platform/issues/1976 (not hydrating)

Here’s my code:

<?php
namespace App\ApiResource\V1;

use ApiPlatform\Metadata\ApiResource;
use App\Api\Utils\ApiResourceInterface;
use App\Api\V1\State\Courses\Chapter\ChapterSearchDataProvider as ChapterChapterSearchDataProvider;
use App\Entity\Chapter as EntityChapter;
use App\Utils\Api\Operations\SearchCollection;
use DateTime;

#[ApiResource(
    routePrefix: '/v1',
    operations: [
        new SearchCollection(
            uriTemplate: '/chapters/search',
            name: 'chapter_search',
            provider: ChapterChapterSearchDataProvider::class,
            input: false,
            output: Chapter::class,
            read: false,
            write: false,
            deserialize: false,
            status: 200
        ),
    ]
)]
class Chapter implements ApiResourceInterface
{

    public string $id;
    public string $course;
    public ?string $previousChapter;
    public ?string $nextChapter;
    public string $title;
    public DateTime $createdAt;
    public DateTime $updatedAt;

    public function __construct(
        string $id,
        string $course,
        ?string $previousChapter,
        ?string $nextChapter,
        string $title,
        DateTime $createdAt,
        DateTime $updatedAt
    ) {
        $this->id = $id;
        $this->course = $course;
        $this->previousChapter = $previousChapter;
        $this->nextChapter = $nextChapter;
        $this->title = $title;
        $this->createdAt = $createdAt;
        $this->updatedAt = $updatedAt;
    }

    public static function getEntityClass() : string {
        return EntityChapter::class;
    }

}


class SearchCollection extends HttpOperation implements CollectionOperationInterface
{
    public function __construct(
        // ...
    ) {
        parent::__construct(
            method: 'POST',
            // ...
        );
    }

<?php

namespace App\Api\V1\State\Courses\Chapter;

use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use App\Api\V1\Mapper\Courses\Chapter\ChapterMapper;
use App\ApiResource\V1\Chapter;
use App\Repository\ChapterRepository;

final class ChapterSearchDataProvider implements ProviderInterface
{
    private ChapterRepository $repository;
    private ChapterMapper $mapper;

    public function __construct(
        ChapterRepository $repository,
        ChapterMapper $mapper
    ) {
        $this->repository = $repository;
        $this->mapper = $mapper;
    }

    /**
     * Provides data.
     *
     * @param array<string, mixed>                                                   $uriVariables
     * @param array<string, mixed>|array{request?: Request, resource_class?: string} $context
     *
     * @return T|PartialPaginatorInterface<T>|iterable<T>|null
     */
    public function provide(
        Operation $operation,
        array $uriVariables = [],
        array $context = []
    ): object|array|null {
        $chapters = $this->repository->findAll();
        return $this->mapper->fromArray($chapters);
    }
}

1 Answer 1

0

I have a partial solution for those who might be interested, but it’s not complete. I can’t manage to convert my data into JSON-LD for my resource links.

I created a class that inherits from HttpOperation and is handled via POST.

        new SearchCollection(
            uriTemplate: '/chapters/search',
            name: 'chapter_search',
            provider: ChapterDataProvider::class,
            controller: ChapterDebugController::class,
            input: false,
            output: Chapter::class,
        ),

And next this controller

<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;

final class ChapterSearchController extends AbstractController
{
    public function __invoke()
    {
        return new JsonResponse(['called' => true]);
    }
}

But it doesn’t use my provider, and I can’t manage to format my data in JSON-LD.

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

Comments

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.