Turn off pluralisation for an endpoint in APi Platform

Viewed 692

In a Symfony 5 project we're using the APi Platform to generate a REST API.

One of the entity classes is called FarmMetadata.

<?php

namespace App\Entity;

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

/**
 * @ApiResource()
 * @ORM\Table(... some settings ...)
 * @ORM\Entity
 */
class FarmMetadata
{
    // properties and methods
}

When I run php bin/console debug:router it shows the following routes for this resource:

api_farm_metadatas_get_collection    GET      ANY      ANY    /api/farm_metadatas.{_format}        
api_farm_metadatas_post_collection   POST     ANY      ANY    /api/farm_metadatas.{_format}        
api_farm_metadatas_get_item          GET      ANY      ANY    /api/farm_metadatas/{id}.{_format}   
api_farm_metadatas_delete_item       DELETE   ANY      ANY    /api/farm_metadatas/{id}.{_format}   
api_farm_metadatas_put_item          PUT      ANY      ANY    /api/farm_metadatas/{id}.{_format}   
api_farm_metadatas_patch_item        PATCH    ANY      ANY    /api/farm_metadatas/{id}.{_format}

However the word "metadata" is already plural. There's no such thing as metadatas. How can I turn off the pluralisation for this endpoint?

I tried using shortName:

* @ApiResource(
*     shortName="FarmMetadata" // also "farm_metadata"
* )

but it doesn't change the output.

If I use:

* @ApiResource(
*     shortName="Metadata"
* )

then the route names and paths are changed:

api_metadata_get_collection         GET      ANY      ANY    /api/metadata.{_format}              
api_metadata_post_collection        POST     ANY      ANY    /api/metadata.{_format}              
api_metadata_get_item               GET      ANY      ANY    /api/metadata/{id}.{_format}         
api_metadata_delete_item            DELETE   ANY      ANY    /api/metadata/{id}.{_format}         
api_metadata_put_item               PUT      ANY      ANY    /api/metadata/{id}.{_format}         
api_metadata_patch_item             PATCH    ANY      ANY    /api/metadata/{id}.{_format}

but that's not what I want.

I know that I can declare a path for every operation, but that would hurt the DRY principle.

How can I achieve the desired behaviour?

3 Answers

I don't think this is possible by configuration: these routes are built in the private method ApiPlatform\Core\Bridge\Symfony\Routing\ApiLoader::addRoute (at least in v2.6 which I'm using), and this uses a static call to a pluralizer - so: decorating the ApiLoader is not easily possible (as the addRoute method is private), and exchanging the ways of generating the route is not possible (due to the usage of a static method call).

Looks like you need to open a feature request ticket in their bug tracker...

you can do easily as you want

api_platform:
    ...
    path_segment_name_generator: App\InfraStructure\ApiPlatform\Core\SingularPathSegmentNameGenerator
  • create SingularPathSegmentNameGenerator
<?php

declare(strict_types=1);

namespace App\InfraStructure\ApiPlatform\Core;

use ApiPlatform\Core\Operation\PathSegmentNameGeneratorInterface;
use ApiPlatform\Core\Util\Inflector;

final class SingularPathSegmentNameGenerator implements PathSegmentNameGeneratorInterface
{
    public function getSegmentName(string $name, bool $collection = true): string
    {
        return Inflector::tableize($name);
    }
}

Related