Reputation: 3747
So far we've been struggling with Symfony, Doctrine, and Serializer depth.
I'd like to be able to provide just one-level-depth JSON REST API with Symfony, allowing me to manage my "foreign key" and relation logic directly from the view.
GET /people/1
{
id:1,
name:"theonewhoknocks",
friends: [3, 12, 25]
}
Using FosRESTBundle, we've been strugling at succeeding on that. (we've seen "depth" anotations and "groups" views for models, but none of this fit our need).
The question is simple, before we make a choice for our future API, we have to know:
is api-platform able to provide a dead simple one level (with apparent foreign keys) REST API ?
Upvotes: 4
Views: 7569
Reputation: 26331
As @leberknecht indicated, you might not get the results you are looking for using MaxDepth
.
This script:
#[ApiResource(
normalizationContext: ['enable_max_depth'=>true],
)]
class User
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private ?int $id = null;
#[ORM\Column(type: 'string', length: 180)]
private ?string $someProperty = null;
#[ORM\ManyToOne(targetEntity: UserClass::class)]
#[SymfonyMaxDepth(1)]
private ?User $createdBy = null;
}
will return:
{
"id": 123,
"someProperty": "objectProperty",
"createdBy": {
"id": 20,
"someProperty": "parentProperty",
"createdBy": "users/5"
}
}
and this script:
#[ApiResource]
class User
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private ?int $id = null;
#[ORM\Column(type: 'string', length: 180)]
private ?string $someProperty = null;
#[ORM\ManyToOne(targetEntity: UserClass::class)]
#[ApiProperty(readableLink: false, writableLink: false)]
private ?User $createdBy = null;
}
will return
{
"id": 123,
"someProperty": "objectProperty",
"createdBy": "users/20"
}
Upvotes: 3
Reputation: 1736
Be aware that the MaxDepth
on the symfony serializer might not behave as expected, see https://github.com/symfony/symfony/issues/33466
The annotation basically says "from here on, render max N instances of THE SAME CLASS into the graph"
So given a pseudo structure like
Class A:
@MaxDepth(1)
Class B:
Class C:
Class D:
would render the whole thing A.B.C.D
, while
Class A:
@MaxDepth(1)
Class B:
Class B:
Class B:
would only render A.B.B
Which is quite different from what e.g. JMS serializer is doing, where MaxDepth
really means "From here on, max N steps into the relation graph".
Bad thing is that JMS serializer is not supported by api-platform: https://github.com/api-platform/api-platform/issues/753
So the answer to your question, atm, is: no. :/
Upvotes: 3
Reputation: 3075
API Platform can handle that using the Serializer Symfony bundle and its annotation set.
To define what will be returned by an operation we use a normalizationContext
which define group(s) of property to include in result of an api operation. Property to include have then this group name linked to @Groups
serializer annotation
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* @ORM\Entity()
* @ApiResource(normalizationContext={"groups"={"read"}}
*/
class Book {
/**
* @ORM\Column()
* @Groups({"read"})
*/
private $title;
/**
* @ORM\ManyToOne(targetEntity="User", inversedBy="books")
* @Groups({"read"})
*/
private $author;
/**
* Will not be included in result
*/
private $secret_comment;
}
If a relation column is in a Group as $author
here, properties defined in a group in the child class will be included in the result
/**
* @ORM\Entity()
* @ApiResource(normalizationContext={"groups"={"read"}})
*/
class User {
/**
* @ORM\Column()
* @Groups({"read"})
*/
private $username;
}
In order to avoid cyclic recursion you can specify the max depth of child relation joins with annotation @MaxDepth(n)
where n is the max depth (1 in your case). This annotation has to be enabled with enable_max_depth
property in serializer context of the @ApiResource
annotation
/**
* @ApiPlatform(normalizationContext={"groups"={"read"}, "enable_max_depth"=true})
*/
class Book {
/**
* @ORM\ManyToOne(targetEntity="User", inversedBy="books")
* @Groups({"read"})
* @MaxDepth(1)
*/
private $author;
}
Please note that API Platform is in this case an agregation of existing bundles and features. Refer to the main bundles for detailed informations (here the Symfony Serializer bundle)
Upvotes: 4