Search code examples
restfilesymfonybase64dto

Symfony 5 Rest, Base64 encoded file to DTO with validation as File object


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 ?


Solution

  • 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>",