0

I have a PostController looking like this:

 #[Route(name: 'add', methods: ['POST'])]
 public function addPost(Request $request): JsonResponse
 {
    /** @var PostRequestDto $postRequest */
    $postRequest = $this->serializer->deserialize(
        $request->getContent(),
        PostRequestDto::class,
        'json'
    );

    return $this->postService->addPost($postRequest);
}

PostService:

public function addPost(PostRequestDto $request): JsonResponse
{
    $errors = $this->validator->validate($request);
    if (count($errors) > 0) {
        throw new ValidationHttpException($errors);
    }

    #...

    return new JsonResponse(null, Response::HTTP_CREATED);
}

And PostRequestDto:

class PostRequestDto
{
    #[Assert\NotBlank]
    #[Assert\Length(max: 250)]
    private ?string $title;

    #[Assert\NotBlank]
    #[Assert\Length(max: 1000)]
    private ?string $article;

    #[Assert\NotBlank]
    #[Assert\Image]
    private ?File $photo;

    #[Assert\NotBlank]
    #[Assert\GreaterThanOrEqual('now', message: 'post_request_dto.publish_date.greater_than_or_equal')]
    private ?DateTimeInterface $publishDate;
}

My Postman request looks like this:

{
    "title": "Test",
    "article": "lorem ipsum....",
    "photo": "base64...",
    "publishDate": "2021-10-15 08:00:00"
}

As you can see from postman request, I'm sending base64 encoded file. Now, in the controller I want to deserialize it to match with PostRequestDto so I can validate it as a File in the PostService - how can I achieve this ?

Slimu
  • 88
  • 8

1 Answers1

1

I don't know how exactly your serializer ($this->serializer) is configured, but I think you have to adjust/add your normilizer with Symfony\Component\Serializer\Normalizer\DataUriNormalizer

// somewhere in your controller/service where serilaizer is configured/set
$normalizers = [
   //... your other normilizers if any
   new DataUriNormalizer(), // this one
   ];
$encoders = [new JsonEncoder()];

$this->serializer = new Serializer($normalizers, $encoders);

If you look inside DataUriNormalizer you'll see, it works with File which is exactly what you have in your PostRequestDto

The only thing to be aware of → format of base64. If you follow the link of denormilize() method, you will see it expects data:image/png;base64,... So it has to start with data:... and you probably have to change your postman-json-payload to

{
    "title": "Test",
    "article": "lorem ipsum....",
    "photo": "data:<your_base64_string>",
    "publishDate": "2021-10-15 08:00:00"
}

Since you work with images, I would also send the mime-type. Like:

"photo": "data:image/png;base64,<your_base64_string>",
V-Light
  • 3,065
  • 3
  • 25
  • 31
  • My serializer is injected into the constructor with `PostService` like this: `public function __construct(private SerializerInterface $serializer, private PostService $postService)` - after using the `DataUriNormalizer()` I'm getting `File could not be found` error... Any ideas why that happened ? – Slimu Oct 11 '21 at 12:09
  • I think your json-payload contains only base_64 string representation of image contents. Try to `dd($postRequest);` right after deserialization. You will notice, that `File` have no information about path. You have to do it manually... it depends on your business logic. Either in a database as a blob or somewhere on disk. – V-Light Oct 11 '21 at 12:22
  • It looks like this: `"photo": "data:image/jpeg;base64,"` – Slimu Oct 11 '21 at 12:28
  • @Slimu I don't know how your `PostService` manages and/or stores images. Maybe you could reveal more file related logic from your `PostService::addPost()` method. – V-Light Oct 11 '21 at 13:41
  • Well, the problem was with storing the image, thanks for help – Slimu Oct 12 '21 at 13:24