symfonyapi-platform.com

Create custom Collection URI (uriTemplate) with Api Platform


With API Platform 3, I have a PHP entity called Report. I would like to offer two ways to retrieve a collection:

/reports: the standard URI generated by API Platform.
/admin/reports: an additional URI with a specific normalizationContext.

However, when I implement this code, I can only get one collection instead of both.

enter image description here

<?php

...

#[ORM\Entity(repositoryClass: ReportRepository::class)]
#[ApiResource(
    uriTemplate: '/admin/reports{._format}',
    operations: [
        new GetCollection(security: "is_granted('ROLE_ADMIN')"),
        new Get(security: "is_granted('ROLE_ADMIN')"),
        new Patch(security: "is_granted('ROLE_ADMIN')"),
    ],
    normalizationContext: [
        AbstractNormalizer::GROUPS => ['Report:read:admin'],
    ],
    denormalizationContext: [
        AbstractNormalizer::GROUPS => ['Report:write:admin'],
    ],
    order: ['createdAt' => 'DESC']
)]
#[ApiResource(
    operations: [
        new GetCollection(),
        new Post(),
        new Get(
            security: 'object.getCreatedBy() == user',
            controller: NotFoundAction::class, 
            read: false, 
            output: false
        )
    ],
    normalizationContext: [
        AbstractNormalizer::GROUPS => ['Report:read'],
    ],
    denormalizationContext: [
        AbstractNormalizer::GROUPS => ['Report:write'],
    ],
    order: ['createdAt' => 'DESC']
)]
class Report
{
    ...

Solution

  • To achieve multiple collection URIs in API Platform 3, the key lies in configuring the resources correctly to allow both /reports and /admin/reports collections to coexist with different normalization contexts.

    In your current setup, the issue is that you are defining two #[ApiResource] attributes on the same class, which API Platform interprets as conflicting configurations. To resolve this, you need to define different URIs with custom operations within a single #[ApiResource] declaration.

    That’s what I understand. Feel free to correct me and explain if I’m assuming anything incorrectly.