Native API Platform Resources
Edit on GitHubThis document explains how to create API Platform resources using native PHP attributes instead of Spryker’s YAML-based generation pipeline, and how to configure your project to discover these resources.
When to use native resources
Spryker’s YAML schema pipeline (resource.yml files) generates PHP resource classes automatically and provides features like multi-layer merging, validation auto-discovery, and CodeBucket support. For most use cases, the YAML approach is recommended.
Use native API Platform resources when you need features that are not yet supported by the Spryker SchemaParser and ClassGenerator, such as:
- Custom filters (search, date range, order)
- GraphQL support
- Messenger integration
- Custom operations with non-standard HTTP methods
- DTO input/output patterns
- Elasticsearch provider integration
- Any other advanced API Platform feature documented at api-platform.com/docs
Creating a native resource class
A native API Platform resource is a PHP class annotated with #[ApiResource] and related attributes. You can place it in any directory that is configured as a mapping path.
Example resource
<?php
declare(strict_types=1);
namespace Pyz\Glue\Catalog\Api\Backend\Resource;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use Pyz\Glue\Catalog\Api\Backend\Provider\CatalogSearchBackendProvider;
#[ApiResource(
operations: [
new GetCollection(),
new Get(),
],
shortName: 'catalog-search',
provider: CatalogSearchBackendProvider::class,
paginationEnabled: true,
paginationItemsPerPage: 20,
)]
class CatalogSearchBackendResource
{
#[ApiProperty(identifier: true, writable: false)]
public ?string $sku = null;
#[ApiProperty]
public ?string $name = null;
#[ApiProperty]
public ?float $price = null;
#[ApiProperty(writable: false)]
public ?string $url = null;
}
This follows the same provider/processor pattern as generated resources. For full attribute documentation, see the API Platform resource configuration reference.
Provider for the native resource
<?php
declare(strict_types=1);
namespace Pyz\Glue\Catalog\Api\Backend\Provider;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
class CatalogSearchBackendProvider implements ProviderInterface
{
public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
{
// Fetch data from your business layer and return resource objects
}
}
Configuring custom resource paths
API Platform discovers resource classes from directories listed in the mapping.paths configuration.
To make API Platform discover your native resources, add your directory to this list.
$apiPlatform->mapping()->paths([
'%kernel.project_dir%/src/Generated/Api/Backend',
'%kernel.project_dir%/src/Pyz/Glue/Catalog/Api/Backend/Resource',
]);
Adding a custom path
Edit the api_platform.php configuration file for the application where your resources should be available.
For GlueBackend resources, edit config/GlueBackend/packages/api_platform.php:
<?php
declare(strict_types=1);
use Symfony\Config\ApiPlatformConfig;
return static function (ApiPlatformConfig $apiPlatform, string $env): void {
$apiPlatform->mapping()->paths([
'%kernel.project_dir%/src/Generated/Api/Backend',
'%kernel.project_dir%/src/Pyz/Glue/*/Api/Backend/Resource',
]);
// ... rest of configuration
};
For GlueStorefront resources, edit config/GlueStorefront/packages/api_platform.php:
$apiPlatform->mapping()->paths([
'%kernel.project_dir%/src/Generated/Api/Storefront',
'%kernel.project_dir%/src/Pyz/Glue/*/Api/Storefront/Resource',
]);
Always keep the src/Generated/Api/{ApiType} path in the list. Removing it disables all YAML-generated resources.
Directory structure example
src/
├── Generated/
│ └── Api/
│ └── Backend/
│ └── CustomersBackendResource.php # Generated from YAML
├── Pyz/
│ └── Glue/
│ └── Catalog/
│ └── Api/
│ └── Backend/
│ ├── Resource/
│ │ └── CatalogSearchBackendResource.php # Native resource
│ └── Provider/
│ └── CatalogSearchBackendProvider.php
Both the generated and native resources are discovered and served by API Platform.
Coexistence with generated resources
Native resources and YAML-generated resources coexist without conflict. API Platform treats all discovered #[ApiResource] classes equally, regardless of whether they were generated or manually created.
Key points:
- shortName conflicts: There is no CI validation for duplicate
shortNamevalues. When a native resource uses the sameshortNameas a generated resource, the resource from the last path listed inmapping.pathstakes precedence and fully overwrites the earlier one. Because project paths are typically listed after the generated resource path, a project resource with a matchingshortNamereplaces the generated resource entirely. - Same provider/processor pattern: Native resources use the same
ProviderInterfaceandProcessorInterfaceas generated resources. - Same serialization: Native resources use the same JSON:API (or other configured) format.
- Same security model: Native resources can use the same
securityexpressions. See Security.
Limitations of native resources
Native resources bypass the Spryker generation pipeline, which means the following features are not available:
| Feature | Available | Alternative |
|---|---|---|
| Multi-layer schema merging (Core, Feature, Project) | No | Manage inheritance manually |
Validation auto-discovery from .validation.yml |
No | Use #[Assert\*] attributes directly on properties |
| CodeBucket support | Partial | Add the CODE_BUCKET constant manually (see below) |
api:debug command output |
No | Use glue debug:router instead |
api:generate management |
No | Manage files manually |
CodeBucket support in native resources
Generated resources automatically include a CODE_BUCKET constant when a CodeBucket is configured in the schema. For native resources, add this constant manually to enable the same CodeBucket resolution mechanism:
#[ApiResource(
operations: [
new GetCollection(),
new Get(),
],
shortName: 'catalog-search',
provider: CatalogSearchBackendProvider::class,
)]
class CatalogSearchEUBackendResource extends CatalogSearchBackendResource
{
public const string CODE_BUCKET = 'EU';
}
The API Platform CodeBucket resolver uses the same logic for both generated and native resources: it checks for the CODE_BUCKET constant on the class and matches it against the current APPLICATION_CODE_BUCKET value. For more details, see Code Buckets.
Validation on native resources
Without the YAML validation pipeline, add Symfony Validator constraints directly as attributes:
use Symfony\Component\Validator\Constraints as Assert;
#[ApiResource(/* ... */)]
class CatalogSearchBackendResource
{
#[ApiProperty(identifier: true)]
public ?string $sku = null;
#[Assert\NotBlank]
#[Assert\Length(min: 1, max: 255)]
public ?string $name = null;
#[Assert\PositiveOrZero]
public ?float $price = null;
}
For the full list of available constraints, see the Symfony Validator documentation.
Next steps
- API Platform Configuration - Full configuration reference
- Resource Schemas - YAML-based resource generation
- API Platform official documentation - Full API Platform reference
Thank you!
For submitting the form