Skip to content

Commit 01ed8dd

Browse files
committed
Resource identifiers
1 parent c984ab6 commit 01ed8dd

File tree

1 file changed

+155
-0
lines changed

1 file changed

+155
-0
lines changed

docs/adr/0001-resource-identifiers.md

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
# Resource identifiers
2+
3+
* Status: proposed
4+
* Deciders: @dunglas @alanpoulain @soyuka
5+
6+
Technical Story: [#2126][pull/2126]
7+
Implementation: [#3825][pull/3825 ]
8+
9+
## Context and Problem Statement
10+
11+
In API Platform, a resource is identified by [IRIs][rfc/IRI], for example `/books/1`. Internally, this is also known as a route with an identifier parameter named `id`: `/books/{id}`. This `id` parameter is then matched to the resource identifiers, known by the `ApiProperty` metadata when `identifier` is true. When multiple identifiers are found, composite identifiers map the value of `id` to the resource identifiers (eg: `keya=value1;keyb=value2`, where `keya` and `keyb` are identifiers of the resource). This behavior is suggested by the [URI RFC][rfc/URI].
12+
Subresources IRIs have multiple parts, for example: `/books/{id}/author/{authorId}`. The router needs to know that `id` matches the `Book` resource, and `authorId` the `Author` resource. To do so, a Tuple representing the class and the property matching each parameter is linked to the route, for example: `id: [Book, id], authorId: [User, id]`.
13+
By normalizing the shape of (sub)-resources (see [0000-subresources-definition][0000-subresources-definition]), we need to normalize the resource identifiers.
14+
15+
## Decision Outcome
16+
17+
Declare explicit resource `identifiers` that will default to `id: [id, Resource]` with composite identifiers. Allow composite identifiers to be disabled if needed.
18+
19+
### Examples
20+
21+
Define a route `/users/{id}`
22+
23+
```php
24+
/**
25+
* @ApiResource
26+
*/
27+
class User {
28+
/** @ApiProperty(identifier=true) */
29+
public int $id;
30+
}
31+
```
32+
33+
Or
34+
35+
```php
36+
/**
37+
* @ApiResource(identifiers={"id": {User::class, "id"}})
38+
*/
39+
class User {
40+
/** @ApiProperty(identifier=true) */
41+
public int $id;
42+
}
43+
```
44+
45+
Define a route `/users/{username}` that uses the username identifier:
46+
47+
```php
48+
/**
49+
* @ApiResource(identifiers={"username"})
50+
*/
51+
class User {
52+
/** @ApiProperty(identifier=true) */
53+
public string $username;
54+
}
55+
```
56+
57+
Or
58+
59+
```php
60+
/**
61+
* @ApiResource(identifiers={"username": {User::class, "username"}})
62+
*/
63+
class User {
64+
/** @ApiProperty(identifier=true) */
65+
public string $username;
66+
}
67+
```
68+
69+
Define a route `/users/{username}` that uses the property shortName:
70+
71+
```php
72+
/**
73+
* @ApiResource(identifiers={"username"={User::class, "shortName"}})
74+
*/
75+
class User {
76+
/** @ApiProperty(identifier=true) */
77+
public string $shortName;
78+
}
79+
```
80+
81+
Define a route `/users/{composite}` that uses composite identifiers `/users/keya=value1;keyb=value2`:
82+
83+
```php
84+
/**
85+
* @ApiResource(identifiers={"composite"})
86+
*/
87+
class User {
88+
/** @ApiProperty(identifier=true) */
89+
public string $keya;
90+
/** @ApiProperty(identifier=true) */
91+
public string $keyb;
92+
}
93+
```
94+
95+
Define a route `/users/{keya}/{keyb}`:
96+
97+
```php
98+
/**
99+
* @ApiResource(identifiers={"keya", "keyb"}, compositeIdentifier=false)
100+
*/
101+
class User {
102+
/** @ApiProperty(identifier=true) */
103+
public string $keya;
104+
/** @ApiProperty(identifier=true) */
105+
public string $keyb;
106+
}
107+
```
108+
109+
Complex version:
110+
111+
```php
112+
/**
113+
* @ApiResource(identifiers={"keya"={User::class, "keya"}, "keyb"={User::class, "keyb"}}, compositeIdentifier=false)
114+
*/
115+
class User {
116+
/** @ApiProperty(identifier=true) */
117+
public string $keya;
118+
/** @ApiProperty(identifier=true) */
119+
public string $keyb;
120+
}
121+
```
122+
123+
Define a subresource `/companies/{companyId}/users/{id}`:
124+
125+
```php
126+
/**
127+
* @ApiResource(path="/users", identifiers={"id": {User::class, "id"}})
128+
* @ApiResource(path="/companies/{companyId}/users", identifiers={"companyId": {Company::class, "id"}, "id": {User::class, "id"}})
129+
*/
130+
class User {
131+
/** @ApiProperty(identifier=true) */
132+
public int $id;
133+
134+
/** @var Company[] */
135+
public array $companies = [];
136+
}
137+
138+
class Company {
139+
/** @ApiProperty(identifier=true) */
140+
public int $id;
141+
142+
/** @var User[] */
143+
public $users;
144+
}
145+
```
146+
147+
## Links
148+
149+
* Adds up to the [0000-subresources-definition][0000-subresources-definition] rework.
150+
151+
[0000-subresources-definition]: ./0000-subresources-definition "Subresources definition"
152+
[pull/2126]: https://github.com/api-platform/core/pull/2126 "Ability to specify identifier property of custom item operations"
153+
[pull/3825]: https://github.com/api-platform/core/pull/3825 "Rework to improve and simplify identifiers management"
154+
[rfc/IRI]: https://tools.ietf.org/html/rfc3987 "RFC3987"
155+
[rfc/URI]: https://tools.ietf.org/html/rfc3986#section-3.3 "RFC 3986"

0 commit comments

Comments
 (0)