API Platform met Symfony in 2026: Architectuur en Sollicitatievragen voor Ontwikkelaars
Uitgebreide gids over API Platform met Symfony in 2026. Leer REST API-architectuur, State Providers, Processors en veelgestelde sollicitatievragen voor Symfony-ontwikkelaars.

API Platform heeft zich gevestigd als het toonaangevende framework voor het ontwikkelen van REST- en GraphQL-API's met Symfony. In 2026 biedt de huidige versie krachtige functionaliteiten zoals State Providers, State Processors en uitgebreide OpenAPI-documentatie. Dit artikel behandelt de moderne architectuur van API Platform en bereidt ontwikkelaars voor op technische sollicitatiegesprekken.
API Platform 4.x vereist Symfony 7.x en PHP 8.3+. De voorbeelden in dit artikel maken gebruik van de nieuwste functies en best practices voor productierijpe API's.
Installatie en Projectconfiguratie
Het opzetten van een nieuw API Platform-project gebeurt via Composer. Het framework integreert naadloos met bestaande Symfony-applicaties.
composer create-project api-platform/api-platform my-api
cd my-api
composer require api-platform/coreDe basisconfiguratie in config/packages/api_platform.yaml definieert belangrijke parameters:
api_platform:
title: "My API"
version: "1.0.0"
formats:
jsonld: ["application/ld+json"]
json: ["application/json"]
docs_formats:
jsonld: ["application/ld+json"]
jsonopenapi: ["application/vnd.openapi+json"]
html: ["text/html"]
defaults:
stateless: true
cache_headers:
vary: ["Content-Type", "Authorization", "Origin"]
extra_properties:
standard_put: true
rfc_7807_compliant_errors: trueEntiteiten Definiëren als API-Resources
API Platform gebruikt PHP-attributen voor het configureren van API-resources. Een typische entiteit combineert Doctrine-mapping met API-definities.
<?php
namespace App\Entity;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Post;
use ApiPlatform\Metadata\Put;
use ApiPlatform\Metadata\Delete;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity]
#[ApiResource(
operations: [
new GetCollection(),
new Get(),
new Post(security: "is_granted('ROLE_ADMIN')"),
new Put(security: "is_granted('ROLE_ADMIN') or object.owner == user"),
new Delete(security: "is_granted('ROLE_ADMIN')")
],
paginationItemsPerPage: 20,
order: ["createdAt" => "DESC"]
)]
class Product
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 255)]
#[Assert\NotBlank]
#[Assert\Length(min: 3, max: 255)]
private string $name;
#[ORM\Column(type: "decimal", precision: 10, scale: 2)]
#[Assert\Positive]
private string $price;
#[ORM\Column]
private \DateTimeImmutable $createdAt;
#[ORM\ManyToOne(targetEntity: User::class)]
private ?User $owner = null;
public function __construct()
{
$this->createdAt = new \DateTimeImmutable();
}
// Getters and setters...
}State Providers voor Aangepaste Datalogica
State Providers vervangen de eerdere Data Providers en bieden meer flexibiliteit bij het ophalen van gegevens. Ze maken integratie van externe databronnen of complexe bedrijfslogica mogelijk.
<?php
namespace App\State;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use App\Entity\Product;
use App\Repository\ProductRepository;
use Symfony\Component\HttpFoundation\RequestStack;
class ProductStateProvider implements ProviderInterface
{
public function __construct(
private ProductRepository $repository,
private RequestStack $requestStack
) {}
public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
{
$request = $this->requestStack->getCurrentRequest();
if ($operation instanceof GetCollection) {
$category = $request?->query->get('category');
if ($category) {
return $this->repository->findByCategory($category);
}
return $this->repository->findAllActive();
}
return $this->repository->find($uriVariables['id']);
}
}De registratie gebeurt via het provider-attribuut:
#[ApiResource(
provider: ProductStateProvider::class
)]
class Product
{
// ...
}State Processors voor Schrijfoperaties
State Processors verwerken POST-, PUT-, PATCH- en DELETE-requests. Ze encapsuleren de bedrijfslogica voor datawijzigingen.
<?php
namespace App\State;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;
use App\Entity\Product;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Email;
class ProductStateProcessor implements ProcessorInterface
{
public function __construct(
private EntityManagerInterface $entityManager,
private MailerInterface $mailer
) {}
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): Product
{
if ($data instanceof Product && $operation instanceof Post) {
$data->setCreatedAt(new \DateTimeImmutable());
$this->entityManager->persist($data);
$this->entityManager->flush();
$this->sendNotification($data);
return $data;
}
$this->entityManager->flush();
return $data;
}
private function sendNotification(Product $product): void
{
$email = (new Email())
->to('admin@example.com')
->subject('New Product Created')
->text(sprintf('Product %s was created.', $product->getName()));
$this->mailer->send($email);
}
}DTO's en Input/Output-Transformaties
Data Transfer Objects maken scheiding mogelijk tussen API-representatie en interne entiteiten. Deze architectuur verhoogt flexibiliteit en veiligheid.
<?php
namespace App\Dto;
use Symfony\Component\Validator\Constraints as Assert;
class CreateProductInput
{
#[Assert\NotBlank]
#[Assert\Length(min: 3, max: 255)]
public string $name;
#[Assert\NotBlank]
#[Assert\Positive]
public float $price;
#[Assert\NotBlank]
public string $category;
public ?string $description = null;
}<?php
namespace App\Dto;
class ProductOutput
{
public int $id;
public string $name;
public float $price;
public string $formattedPrice;
public string $category;
public string $createdAt;
}De configuratie van de transformatie gebeurt in de resource-definitie:
#[ApiResource(
operations: [
new Post(
input: CreateProductInput::class,
output: ProductOutput::class,
processor: CreateProductProcessor::class
)
]
)]
class Product
{
// ...
}Filteren en Sorteren
API Platform biedt declaratieve filters voor veelvoorkomende query-patronen. De configuratie gebeurt direct op de entiteit.
<?php
use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Doctrine\Orm\Filter\RangeFilter;
use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
use ApiPlatform\Doctrine\Orm\Filter\DateFilter;
use ApiPlatform\Metadata\ApiFilter;
#[ApiResource]
#[ApiFilter(SearchFilter::class, properties: [
'name' => 'partial',
'category.name' => 'exact'
])]
#[ApiFilter(RangeFilter::class, properties: ['price'])]
#[ApiFilter(DateFilter::class, properties: ['createdAt'])]
#[ApiFilter(OrderFilter::class, properties: ['name', 'price', 'createdAt'])]
class Product
{
// ...
}Een voorbeeld van een API-request met filters:
GET /api/products?name=laptop&price[gte]=500&order[price]=ascAuthenticatie en Autorisatie
De beveiligingsconfiguratie maakt gebruik van Symfony's Security-component. API Platform integreert Voters en expressions naadloos.
<?php
namespace App\Security\Voter;
use App\Entity\Product;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\User\UserInterface;
class ProductVoter extends Voter
{
public const EDIT = 'PRODUCT_EDIT';
public const DELETE = 'PRODUCT_DELETE';
protected function supports(string $attribute, mixed $subject): bool
{
return in_array($attribute, [self::EDIT, self::DELETE])
&& $subject instanceof Product;
}
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
{
$user = $token->getUser();
if (!$user instanceof UserInterface) {
return false;
}
/** @var Product $product */
$product = $subject;
return match($attribute) {
self::EDIT => $this->canEdit($product, $user),
self::DELETE => $this->canDelete($product, $user),
default => false,
};
}
private function canEdit(Product $product, UserInterface $user): bool
{
return $product->getOwner() === $user || in_array('ROLE_ADMIN', $user->getRoles());
}
private function canDelete(Product $product, UserInterface $user): bool
{
return in_array('ROLE_ADMIN', $user->getRoles());
}
}API-Versionering
API Platform ondersteunt verschillende versioneringsstrategieën. URL-gebaseerde versionering is het meest gangbaar.
#[ApiResource(
routePrefix: '/v1',
operations: [
new GetCollection(),
new Get()
]
)]
class Product
{
// ...
}
#[ApiResource(
routePrefix: '/v2',
operations: [
new GetCollection(),
new Get()
],
normalizationContext: ['groups' => ['product:read:v2']]
)]
class ProductV2
{
// ...
}Veelgestelde Sollicitatievragen
Vraag: Wat is het verschil tussen State Provider en State Processor?
State Providers zijn verantwoordelijk voor leesoperaties (GET-requests) en leveren data uit willekeurige bronnen. State Processors verwerken schrijfoperaties (POST, PUT, PATCH, DELETE) en implementeren persistentielogica evenals neveneffecten zoals notificaties.
Vraag: Hoe implementeer je paginering in API Platform?
API Platform biedt automatische paginering. De configuratie kan globaal of per resource:
#[ApiResource(
paginationEnabled: true,
paginationItemsPerPage: 30,
paginationMaximumItemsPerPage: 100,
paginationClientEnabled: true
)]Vraag: Welke serialisatiegroepen worden aanbevolen?
Best practices adviseren aparte groepen voor lezen en schrijven:
#[ApiResource(
normalizationContext: ['groups' => ['product:read']],
denormalizationContext: ['groups' => ['product:write']]
)]Vraag: Hoe test je API Platform-endpoints?
<?php
namespace App\Tests\Api;
use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
use App\Entity\Product;
use Hautelook\AliceBundle\PhpUnit\RefreshDatabaseTrait;
class ProductTest extends ApiTestCase
{
use RefreshDatabaseTrait;
public function testGetCollection(): void
{
$response = static::createClient()->request('GET', '/api/products');
$this->assertResponseIsSuccessful();
$this->assertJsonContains(['@type' => 'hydra:Collection']);
}
public function testCreateProduct(): void
{
$response = static::createClient()->request('POST', '/api/products', [
'json' => [
'name' => 'Test Product',
'price' => '29.99'
],
'headers' => [
'Authorization' => 'Bearer ' . $this->getToken()
]
]);
$this->assertResponseStatusCodeSame(201);
$this->assertJsonContains(['name' => 'Test Product']);
}
}Klaar om je Symfony gesprekken te halen?
Oefen met onze interactieve simulatoren, flashcards en technische tests.
Conclusie
API Platform in 2026 biedt een volwassen architectuur voor het ontwikkelen van REST-API's met Symfony. State Providers en Processors maken flexibele datatoegangspatronen mogelijk, terwijl DTO's een schone scheiding tussen API en domeinlogica garanderen. De integratie van filters, beveiliging en automatische documentatie maakt API Platform de eerste keuze voor professionele API-ontwikkeling. De behandelde concepten en sollicitatievragen bereiden ontwikkelaars optimaal voor op technische gesprekken en geven best practices mee voor productierijpe implementaties.
Zie jij de bug in Symfony?
Een echt codefragment, een verborgen bug, één poging per dag. Zonder account uit te proberen.

Geschreven door
Anthony Fillion-MailletOprichter van SharpSkill
Al meer dan 10 jaar fullstack-ontwikkelaar. Hij leidt SharpSkill en staat in voor alles wat hier verschijnt.
Bijgewerkt op 8 september 2026
Delen
Gerelateerde artikelen

Symfony REST API Beveiliging in 2026: OAuth2, Rate Limiting en Sollicitatievragen
Uitgebreide gids voor het beveiligen van Symfony REST APIs met OAuth2 Token Introspection, RateLimiter-component, Voters en beveiligingsbest practices.

API Platform GraphQL met Symfony: Schema's, Mutations en Sollicitatievragen 2026
Complete handleiding voor API Platform GraphQL met Symfony: schemageneratie, queries, mutations, custom resolvers, beveiliging en technische sollicitatievragen voor 2026.

Symfony REST API Beveiliging: JWT-Authenticatie en Best Practices 2026
Uitgebreide gids voor het beveiligen van Symfony REST APIs met JWT-authenticatie, LexikJWTAuthenticationBundle en bewezen beveiligingspraktijken voor productie-omgevingen.