question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

How apply serialization on custom GET collection operation

See original GitHub issue

Hi everyone!

I’m new user since few day on API Platform and i try to create a custom GET collection operation for a Station entity which has GPS coordonates attributes. The goal of the custom operation isn’t no to return all Stations but only return those in a certain distance. This is for the context.

So, my entity :

<?php

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ApiResource(attributes={"pagination_enabled"=false})
 * @ORM\Entity(repositoryClass="App\Repository\StationRepository")
 */
class Station
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="float")
     */
    private $latitude;

    /**
     * @ORM\Column(type="float")
     */
    private $longitude;

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getLatitude(): ?float
    {
        return $this->latitude;
    }

    public function setLatitude(float $latitude): self
    {
        $this->latitude = $latitude;

        return $this;
    }

    public function getLongitude(): ?float
    {
        return $this->longitude;
    }

    public function setLongitude(float $longitude): self
    {
        $this->longitude = $longitude;

        return $this;
    }
}

In my resources.yaml

App\Entity\Station:
  collectionOperations:
    get_nearby:
      method: GET
      path: /nearby_stations
      controller: App\Action\NearbyStationsAction
      normalization_context:
        groups: ["read"]
      swagger_context:
        parameters:
        - in: query
          name: latitude
          required: true
          type: string
          description: "Latitude coordonates"
          schema:
            type: float

        - in: query
          name: longitude
          required: true
          type: string
          description: "Longitude coordonates"
          schema:
            type: float
  itemOperations: []

I created an action controller App\Action\NearbyStationsAction

namespace App\Action;

use App\DataProvider\StationCollectionDataProvider;
use App\Entity\Station;

class NearbyStationsAction
{
    public function __invoke(StationCollectionDataProvider $stationCollectionDataProvider): array
    {
        return $stationCollectionDataProvider->getCollection(Station::class);
    }
}

And a dataProvider :

namespace App\DataProvider;

use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface;
use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
use App\Entity\Station;
use Doctrine\Common\Persistence\ManagerRegistry;
use Symfony\Component\HttpFoundation\RequestStack;

final class StationCollectionDataProvider implements CollectionDataProviderInterface, RestrictedDataProviderInterface
{
    private $managerRegistry;
    private $requestStack;

    public function __construct(ManagerRegistry $managerRegistry, RequestStack $requestStack)
    {
        $this->managerRegistry  = $managerRegistry;
        $this->requestStack    = $requestStack;
    }

    public function supports(string $resourceClass, string $operationName = null, array $context = []): bool
    {
        return Station::class === $resourceClass;
    }

    public function getCollection(string $resourceClass, string $operationName = null): ?array
    {
        // I will use Request to get query params for findByDistanceAndCoordonates method
        $manager = $this->managerRegistry->getManagerForClass($resourceClass);
        $repository = $manager->getRepository($resourceClass);

        return $repository->findByDistanceAndCoordonates(6, -0.863621, -108.572197);
    }
}

The result is almost pretty good… I’ve the good object returned but is returned fully… My groups serialization aren’t work (cf. resources.yaml normalization_context) My groups are defined in config/serialization/Station.yaml

App\Entity\Station:
  attributes:
    id:
      groups: ['read']
    latitude:
      groups: ['read']

If i use default GET collection operation it works well, good attributes are displayed in my result. But with my custom, i’ don’t know how apply context serialization to my result. Perhaps i’m not in the right way too… I’m loosing myself between custom operation, DTO and filters… Maybe i suppose do it by an other way.

If someone could explain me how to do with the good practice that’ll be awesome 😃

Thanks for reading me. Thanks for your help.

BenWa.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:1
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
mustapha-ghlissicommented, Feb 3, 2020

Hi,

I am facing the same issue,

A possible solution is just to focus on the custom operation so no DataProvider is needed here

Look at the following example:

class GetEventPictures extends AbstractController
{
    /**
     * @param PicturesRepository $picturesRepository
     * @param Request $request
     * @param SerializerInterface $serializer
     * @return Paginator|string
     * @Route(
     *     name="get_event_pics",
     *     path="/events/{id}/pictures",
     *     methods={"GET"},
     *     defaults={
     *         "_api_resource_class"=Pictures::class
     *     },
     *     requirements={"id"="\d+"}
     * )
     */
    public function __invoke(PicturesRepository $picturesRepository, Request $request, SerializerInterface $serializer)
    {
        $page = (int) $request->query->get('page', 1);
        $data = $picturesRepository->getPicturesByEvent((int)$request->query->get('id'), $page);
        $data = $serializer->serialize($data, 'json');
        return new Response($data, Response::HTTP_OK, ['Content-Type' => 'application/json']);
    }
}

0reactions
soyukacommented, Apr 3, 2019

I think we can close this, tell me if that’s not the case I’ll re-open.

Read more comments on GitHub >

github_iconTop Results From Across the Web

The Serialization Process - API Platform
The API Platform Serializer is extendable. You can register custom normalizers and encoders in order to support other formats.
Read more >
Custom binary serialization | Microsoft Learn
Implementing ISerializable involves implementing the GetObjectData method and a special constructor that's used when the object is deserialized.
Read more >
Configure Custom Serializers | MuleSoft Documentation
If you are going to serialize and deserialize in Mule, then you must define the getInternalProtocol() method. If you are going to use...
Read more >
API Platform Serialization issue for custom Output
I have created this resource in order to request a password reset token: POST {{api_base_url}}/users/password/reset-request Payload example ...
Read more >
Serialization Tutorial - GitHub Pages
Hence, it is possible that certain values may get applied and overwritten. ... by your custom serializer into some collection and then use...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found