Nested Collections: /api/projects/{id}/tasks
Nested Collections: /api/projects/{id}/tasks
~14 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026
ALONGSIDE /api/tasks (ALL tasks), a SECOND endpoint that returns ONLY the tasks of ONE specific project is often useful – EXACTLY what nested ("sub-resource") operations are for.
Defining a nested operation
use ApiPlatform\Metadata\GetCollection;
#[ApiResource(
normalizationContext: ['groups' => ['task:read']],
denormalizationContext: ['groups' => ['task:write']]
)]
#[ApiResource(
uriTemplate: '/projects/{projectId}/tasks',
uriVariables: [
'projectId' => new \ApiPlatform\Metadata\Link(
fromClass: Project::class,
toProperty: 'project',
),
],
operations: [new GetCollection()],
normalizationContext: ['groups' => ['task:read']]
)]
#[ORM\Entity(repositoryClass: TaskRepository::class)]
class Task
{
// ... unchanged
}TWO #[ApiResource] attributes on the SAME class – the FIRST defines the "flat" /api/tasks resource from chapter 37, the SECOND an ADDITIONAL, nested view on the SAME data.
Link explained
Link describes HOW the {projectId} placeholder gets connected to a real database query: fromClass: Project::class says THAT projectId is a Project ID, toProperty: 'project' says THAT the Task side gets filtered via the project property.
Testing the nested endpoint
curl -k https://localhost/api/projects/1/tasks{
"@context": "/api/contexts/Task",
"@id": "/api/projects/1/tasks",
"@type": "hydra:Collection",
"hydra:member": [
{"@id": "/api/tasks/1", "title": "Create wireframes", "done": false}
],
"hydra:totalItems": 1
}ONLY tasks belonging to project 1 – EXACTLY the same filtering as manually using ?project=/api/projects/1 (chapter 31 could also be used for that), but as its OWN, more descriptive path.
Achtung: Calling /api/projects/999/tasks with a NON-existent projectId returns 404 Not Found – API Platform AUTOMATICALLY checks whether the parent project exists BEFORE querying the task collection.
Tipp: ALL filters/pagination/sorting from block 4 ALSO work on nested collections – /api/projects/1/tasks?order[title]=asc is JUST AS valid as on the flat /api/tasks resource.