Skip to content

Commit c7892af

Browse files
committed
laravel json api sparse fieldset + sort
1 parent 6adbf54 commit c7892af

File tree

1 file changed

+158
-65
lines changed

1 file changed

+158
-65
lines changed

core/content-negotiation.md

Lines changed: 158 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,103 +1,134 @@
11
# Content Negotiation
22

3-
The API system has built-in [content negotiation](https://en.wikipedia.org/wiki/Content_negotiation) capabilities.
3+
The API system has built-in
4+
[content negotiation](https://en.wikipedia.org/wiki/Content_negotiation)
5+
capabilities.
46

5-
By default, only the [JSON-LD](https://json-ld.org) format is enabled. However API Platform supports many more formats and can be extended.
7+
By default, only the [JSON-LD](https://json-ld.org) format is enabled. However
8+
API Platform supports many more formats and can be extended.
69

7-
The framework natively supports JSON-LD (and Hydra), GraphQL, JSON:API, HAL, YAML, CSV, HTML (API docs), raw JSON and raw XML.
8-
Using the raw JSON or raw XML formats is discouraged, prefer using JSON-LD instead, which provides more feature and is as easy to use.
10+
The framework natively supports JSON-LD (and Hydra), GraphQL, JSON:API, HAL,
11+
YAML, CSV, HTML (API docs), raw JSON and raw XML. Using the raw JSON or raw XML
12+
formats is discouraged, prefer using JSON-LD instead, which provides more
13+
feature and is as easy to use.
914

10-
API Platform also supports [JSON Merge Patch (RFC 7396)](https://tools.ietf.org/html/rfc7396) the JSON:API [`PATCH`](https://jsonapi.org/format/#crud-updating) formats, as well as [Problem Details (RFC 7807)](https://tools.ietf.org/html/rfc7807), [Hydra](https://www.hydra-cg.com/spec/latest/core/#description-of-http-status-codes-and-errors) and [JSON:API](https://jsonapi.org/format/#errors) error formats.
15+
API Platform also supports
16+
[JSON Merge Patch (RFC 7396)](https://tools.ietf.org/html/rfc7396) the JSON:API
17+
[`PATCH`](https://jsonapi.org/format/#crud-updating) formats, as well as
18+
[Problem Details (RFC 7807)](https://tools.ietf.org/html/rfc7807),
19+
[Hydra](https://www.hydra-cg.com/spec/latest/core/#description-of-http-status-codes-and-errors)
20+
and [JSON:API](https://jsonapi.org/format/#errors) error formats.
1121

1222
<p align="center" class="symfonycasts"><a href="https://symfonycasts.com/screencast/api-platform/formats?cid=apip"><img src="../symfony/images/symfonycasts-player.png" alt="Formats screencast"><br>Watch the Formats screencast</a></p>
1323

1424
API Platform will automatically detect the best resolving format depending on:
1525

1626
- enabled formats (see below)
17-
- the requested format, specified in either [the `Accept` HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept) or as an extension appended to the URL
27+
- the requested format, specified in either
28+
[the `Accept` HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept)
29+
or as an extension appended to the URL
1830

1931
Available formats are:
2032

2133
| Format | Format name | MIME types | Backward Compatibility guaranteed |
22-
|-------------------------------------------------------|-------------|-------------------------------|-----------------------------------|
34+
| ----------------------------------------------------- | ----------- | ----------------------------- | --------------------------------- |
2335
| [JSON-LD](https://json-ld.org) | `jsonld` | `application/ld+json` | yes |
2436
| [GraphQL](graphql.md) | n/a | n/a | yes |
2537
| [JSON:API](https://jsonapi.org/) | `jsonapi` | `application/vnd.api+json` | yes |
2638
| [HAL](https://stateless.group/hal_specification.html) | `jsonhal` | `application/hal+json` | yes |
27-
| [YAML](https://yaml.org/) | `yaml` | `application/yaml` | no |
39+
| [YAML](https://yaml.org/) | `yaml` | `application/yaml` | no |
2840
| [CSV](https://tools.ietf.org/html/rfc4180) | `csv` | `text/csv` | no |
2941
| [HTML](https://whatwg.org/) (API docs) | `html` | `text/html` | no |
3042
| [XML](https://www.w3.org/XML/) | `xml` | `application/xml`, `text/xml` | no |
3143
| [JSON](https://www.json.org/) | `json` | `application/json` | no |
3244

33-
If the client's requested format is not specified, the response format will be the first format defined in the `formats` configuration key (see below).
34-
If the request format is not supported, an [Unsupported Media Type](https://developer.mozilla.org/fr/docs/Web/HTTP/Status/415) error will be returned.
45+
If the client's requested format is not specified, the response format will be
46+
the first format defined in the `formats` configuration key (see below). If the
47+
request format is not supported, an
48+
[Unsupported Media Type](https://developer.mozilla.org/fr/docs/Web/HTTP/Status/415)
49+
error will be returned.
3550

36-
Examples showcasing how to use the different mechanisms are available [in the API Platform test suite](https://github.com/api-platform/core/blob/main/features/main/content_negotiation.feature).
51+
Examples showcasing how to use the different mechanisms are available
52+
[in the API Platform test suite](https://github.com/api-platform/core/blob/main/features/main/content_negotiation.feature).
3753

3854
## Configuring Formats Globally
3955

40-
The first required step is to configure allowed formats. The following configuration will enable the support of XML (built-in)
41-
and of a custom format called `myformat` and having `application/vnd.myformat` as [MIME type](https://en.wikipedia.org/wiki/Media_type).
56+
The first required step is to configure allowed formats. The following
57+
configuration will enable the support of XML (built-in) and of a custom format
58+
called `myformat` and having `application/vnd.myformat` as
59+
[MIME type](https://en.wikipedia.org/wiki/Media_type).
4260

4361
```yaml
4462
# api/config/packages/api_platform.yaml
4563
api_platform:
4664
formats:
47-
jsonld: ['application/ld+json']
48-
jsonhal: ['application/hal+json']
49-
jsonapi: ['application/vnd.api+json']
50-
json: ['application/json']
51-
xml: ['application/xml', 'text/xml']
52-
yaml: ['application/x-yaml']
53-
csv: ['text/csv']
54-
html: ['text/html']
55-
myformat: ['application/vnd.myformat']
65+
jsonld: ["application/ld+json"]
66+
jsonhal: ["application/hal+json"]
67+
jsonapi: ["application/vnd.api+json"]
68+
json: ["application/json"]
69+
xml: ["application/xml", "text/xml"]
70+
yaml: ["application/x-yaml"]
71+
csv: ["text/csv"]
72+
html: ["text/html"]
73+
myformat: ["application/vnd.myformat"]
5674
```
5775
5876
To enable GraphQL support, [read the dedicated chapter](graphql.md).
5977
60-
Because the Symfony Serializer component is able to serialize objects in XML, sending an `Accept` HTTP header with the
61-
`text/xml` string as value is enough to retrieve XML documents from our API. However API Platform knows nothing about the
62-
`myformat` format. We need to register an encoder and optionally a normalizer for this format.
78+
Because the Symfony Serializer component is able to serialize objects in XML,
79+
sending an `Accept` HTTP header with the `text/xml` string as value is enough to
80+
retrieve XML documents from our API. However API Platform knows nothing about
81+
the `myformat` format. We need to register an encoder and optionally a
82+
normalizer for this format.
6383

6484
## Configuring PATCH Formats
6585

6686
By default, API Platform supports JSON Merge Patch and JSON:API PATCH formats.
67-
Support for the JSON:API PATCH format is automatically enabled if JSON:API support is enabled.
68-
JSON Merge Patch support must be enabled explicitly:
87+
Support for the JSON:API PATCH format is automatically enabled if JSON:API
88+
support is enabled. JSON Merge Patch support must be enabled explicitly:
6989

7090
```yaml
7191
# api/config/packages/api_platform.yaml
7292
api_platform:
7393
patch_formats:
74-
json: ['application/merge-patch+json']
75-
jsonapi: ['application/vnd.api+json']
94+
json: ["application/merge-patch+json"]
95+
jsonapi: ["application/vnd.api+json"]
7696
```
7797

78-
When support for at least one PATCH format is enabled, [an `Accept-Patch` HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Patch) containing the list of supported patch formats is automatically added to all HTTP responses for items.
98+
When support for at least one PATCH format is enabled,
99+
[an `Accept-Patch` HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Patch)
100+
containing the list of supported patch formats is automatically added to all
101+
HTTP responses for items.
79102

80103
## Configuring Error Formats
81104

82-
API Platform will try to send to the client the error format matching with the format request with the `Accept` HTTP headers (or the URL extension). For instance, if a client request a JSON-LD representation of a resource, and an error occurs, then API Platform will serialize this error using the Hydra format (Hydra is a vocabulary for JSON-LD containing a standard representation of API errors).
105+
API Platform will try to send to the client the error format matching with the
106+
format request with the `Accept` HTTP headers (or the URL extension). For
107+
instance, if a client request a JSON-LD representation of a resource, and an
108+
error occurs, then API Platform will serialize this error using the Hydra format
109+
(Hydra is a vocabulary for JSON-LD containing a standard representation of API
110+
errors).
83111

84112
Available formats can also be configured:
85113

86114
```yaml
87115
# api/config/packages/api_platform.yaml
88116
api_platform:
89117
error_formats:
90-
jsonproblem: ['application/problem+json']
91-
jsonld: ['application/ld+json'] # Hydra error formats
92-
jsonapi: ['application/vnd.api+json']
118+
jsonproblem: ["application/problem+json"]
119+
jsonld: ["application/ld+json"] # Hydra error formats
120+
jsonapi: ["application/vnd.api+json"]
93121
```
94122

95123
## Configuring Formats For a Specific Resource or Operation
96124

97-
Support for specific formats can also be configured at resource and operation level using the `inputFormats` and `outputFormats` attributes.
98-
`inputFormats` controls the formats accepted in request bodies while `outputFormats` controls formats available for responses.
125+
Support for specific formats can also be configured at resource and operation
126+
level using the `inputFormats` and `outputFormats` attributes. `inputFormats`
127+
controls the formats accepted in request bodies while `outputFormats` controls
128+
formats available for responses.
99129

100-
The `format` attribute can be used as a shortcut, it sets both the `inputFormats` and `outputFormats` in one time.
130+
The `format` attribute can be used as a shortcut, it sets both the
131+
`inputFormats` and `outputFormats` in one time.
101132

102133
```php
103134
<?php
@@ -113,13 +144,16 @@ class Book
113144
}
114145
```
115146

116-
In the example above, `xml` or `jsonld` will be allowed and there is no need to specify the MIME types as they are already defined in the configuration.
147+
In the example above, `xml` or `jsonld` will be allowed and there is no need to
148+
specify the MIME types as they are already defined in the configuration.
117149
Additionally the `csv` format is added with the MIME type `text/csv`.
118150

119-
It is also important to notice that the usage of this attribute will override the formats defined in the configuration, therefore
120-
this configuration might disable the `json` or the `html` on this resource for example.
151+
It is also important to notice that the usage of this attribute will override
152+
the formats defined in the configuration, therefore this configuration might
153+
disable the `json` or the `html` on this resource for example.
121154

122-
You can specify different accepted formats at operation level too, it's especially convenient to configure formats available for the `PATCH` method:
155+
You can specify different accepted formats at operation level too, it's
156+
especially convenient to configure formats available for the `PATCH` method:
123157

124158
<code-selector>
125159

@@ -148,12 +182,14 @@ class Book
148182
resources:
149183
App\Entity\Book:
150184
formats:
151-
0: 'jsonld' # format already defined in the config
152-
csv: 'text/csv'
185+
0: "jsonld" # format already defined in the config
186+
csv: "text/csv"
153187
operations:
154188
ApiPlatform\Metadata\Get:
155189
formats:
156-
json: ['application/merge-patch+json'] # works also with "application/merge-patch+json"
190+
json: [
191+
"application/merge-patch+json",
192+
] # works also with "application/merge-patch+json"
157193
```
158194

159195
```xml
@@ -182,9 +218,10 @@ resources:
182218

183219
## Supporting Custom Formats
184220

185-
The API Platform content negotiation system is extendable.
186-
You can add support for formats not available by default by creating custom normalizers and encoders.
187-
Refer to the Symfony documentation to learn [how to create and register such classes](https://symfony.com/doc/current/serializer.html#adding-normalizers-and-encoders).
221+
The API Platform content negotiation system is extendable. You can add support
222+
for formats not available by default by creating custom normalizers and
223+
encoders. Refer to the Symfony documentation to learn
224+
[how to create and register such classes](https://symfony.com/doc/current/serializer.html#adding-normalizers-and-encoders).
188225

189226
Then, register the new format in the configuration:
190227

@@ -193,36 +230,39 @@ Then, register the new format in the configuration:
193230
api_platform:
194231
formats:
195232
# ...
196-
myformat: ['application/vnd.myformat']
233+
myformat: ["application/vnd.myformat"]
197234
```
198235

199236
You will also need to declare an encoder which supports the new format:
200237

201238
```yaml
202239
services:
203-
app.api-platform.myformat.encoder:
204-
class: ApiPlatform\Serializer\JsonEncoder
205-
arguments:
206-
$format: 'myformat'
207-
# The following lines are only needed if autoconfigure is disabled
208-
# tags:
209-
# - { name: 'serializer.encoder' }
240+
app.api-platform.myformat.encoder:
241+
class: ApiPlatform\Serializer\JsonEncoder
242+
arguments:
243+
$format: "myformat"
244+
# The following lines are only needed if autoconfigure is disabled
245+
# tags:
246+
# - { name: 'serializer.encoder' }
210247
```
211248

212-
API Platform will automatically call the serializer with your defined format name as `format` parameter during the deserialization process (`myformat` in the example).
213-
It will then return the result to the client with the requested MIME type using its built-in responder.
214-
For non-standard formats, [a vendor, vanity or unregistered MIME type should be used](https://en.wikipedia.org/wiki/Media_type#Vendor_tree).
249+
API Platform will automatically call the serializer with your defined format
250+
name as `format` parameter during the deserialization process (`myformat` in the
251+
example). It will then return the result to the client with the requested MIME
252+
type using its built-in responder. For non-standard formats,
253+
[a vendor, vanity or unregistered MIME type should be used](https://en.wikipedia.org/wiki/Media_type#Vendor_tree).
215254

216255
### Reusing the API Platform Infrastructure
217256

218-
Using composition is the recommended way to implement a custom normalizer. You can use the following template to start your
219-
own implementation of `CustomItemNormalizer`:
257+
Using composition is the recommended way to implement a custom normalizer. You
258+
can use the following template to start your own implementation of
259+
`CustomItemNormalizer`:
220260

221261
```yaml
222262
# api/config/services.yaml
223263
services:
224264
'App\Serializer\CustomItemNormalizer':
225-
arguments: ['@api_platform.serializer.normalizer.item']
265+
arguments: ["@api_platform.serializer.normalizer.item"]
226266
# Uncomment if you don't use the autoconfigure feature
227267
#tags: [ 'serializer.normalizer' ]
228268
@@ -272,8 +312,8 @@ final class CustomItemNormalizer implements NormalizerInterface, DenormalizerInt
272312
}
273313
```
274314

275-
For example if you want to make the `csv` format work for even complex entities with a lot of hierarchy, you have to
276-
flatten or remove overly complex relations:
315+
For example if you want to make the `csv` format work for even complex entities
316+
with a lot of hierarchy, you have to flatten or remove overly complex relations:
277317

278318
```php
279319
<?php
@@ -310,5 +350,58 @@ class CustomItemNormalizer implements NormalizerInterface, DenormalizerInterface
310350

311351
### Contributing Support for New Formats
312352

313-
Adding support for **standard** formats upstream is welcome!
314-
We'll be glad to merge new encoders and normalizers in API Platform.
353+
Adding support for **standard** formats upstream is welcome! We'll be glad to
354+
merge new encoders and normalizers in API Platform.
355+
356+
## JSON:API sparse fieldset and sort parameters
357+
358+
When working with JSON:API you may want to declare the `SparseFieldset` and the
359+
`SortFilter` globally:
360+
361+
```php
362+
<?php
363+
// config/api-platform.php
364+
365+
use ApiPlatform\Metadata\QueryParameter;
366+
use ApiPlatform\JsonApi\Filter\SparseFieldset;
367+
use ApiPlatform\Laravel\Eloquent\Filter\JsonApi\SortFilter;
368+
369+
return [
370+
// ...
371+
'parameters' => [
372+
new QueryParameter(key: 'fields', filter: SparseFieldset::class),
373+
new QueryParameter(key: 'sort', filter: SortFilter::class),
374+
],
375+
];
376+
```
377+
378+
It's also possible to declare this per-resource such as:
379+
380+
```php
381+
use ApiPlatform\Metadata\ApiResource;
382+
use ApiPlatform\Metadata\QueryParameter;
383+
use ApiPlatform\JsonApi\Filter\SparseFieldset;
384+
use ApiPlatform\Laravel\Eloquent\Filter\JsonApi\SortFilter;
385+
386+
#[ApiResource]
387+
#[QueryParameter(key: 'fields', filter: SparseFieldset::class)]
388+
#[QueryParameter(key: 'sort', filter: SortFilter::class)]
389+
class Book extends Model {}
390+
```
391+
392+
or per-operation:
393+
394+
```php
395+
use ApiPlatform\Metadata\GetCollection;
396+
use ApiPlatform\Metadata\QueryParameter;
397+
use ApiPlatform\JsonApi\Filter\SparseFieldset;
398+
use ApiPlatform\Laravel\Eloquent\Filter\JsonApi\SortFilter;
399+
400+
#[GetCollection(
401+
parameters: [
402+
new QueryParameter(key: 'fields', filter: SparseFieldset::class),
403+
new QueryParameter(key: 'sort', filter: SortFilter::class)
404+
]
405+
)]
406+
class Book extends Model {}
407+
```

0 commit comments

Comments
 (0)