Skip to content

Commit 1278e59

Browse files
laurent-bientzLaurent Bientzdunglas
authored
fix: update Souin setup (#1969)
* feat(performance): update Souin setup & enable Cache-Control public in docs * feat(performance): simplify caddy config * feat(performance): remove http_cache public directive * feat(performance): add an example to set Cache-Control per api resource * feat(performance): remove http_cache public directive for varnish * Update performance.md --------- Co-authored-by: Laurent Bientz <[email protected]> Co-authored-by: Kévin Dunglas <[email protected]>
1 parent 4292873 commit 1278e59

File tree

1 file changed

+54
-30
lines changed

1 file changed

+54
-30
lines changed

core/performance.md

Lines changed: 54 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ This means that after the first request, all subsequent requests will not hit th
1616
from the cache.
1717

1818
When a resource is modified, API Platform takes care of purging all responses containing it in the proxy’s
19-
cache. This ensures that the content served will always be fresh because the cache is purged in real-time. Support for
19+
cache. This ensures that the content served will always be fresh because the cache is purged in real time. Support for
2020
most specific cases such as the invalidation of collections when a document is added or removed or for relationships and
2121
inverse relations is built-in.
2222

2323
### Integrations
2424

25-
#### Built-in Caddy HTTP cache
25+
#### Built-in Caddy HTTP Cache
2626

2727
The API Platform distribution relies on the [Caddy web server](https://caddyserver.com) which provides an official HTTP cache module called [cache-handler](https://github.com/caddyserver/cache-handler), that is based on [Souin](https://github.com/darkweak/souin).
2828

@@ -35,31 +35,37 @@ The integration using the cache handler is quite simple. You just have to update
3535
+FROM dunglas/frankenphp:latest-builder AS builder
3636
+COPY --from=caddy:builder /usr/bin/xcaddy /usr/bin/xcaddy
3737
+
38+
+RUN apt-get update && apt-get install --no-install-recommends -y \
39+
+ git
40+
+
3841
+ENV CGO_ENABLED=1 XCADDY_SETCAP=1 XCADDY_GO_BUILD_FLAGS="-ldflags \"-w -s -extldflags '-Wl,-z,stack-size=0x80000'\""
3942
+RUN xcaddy build \
4043
+ --output /usr/local/bin/frankenphp \
4144
+ --with github.com/dunglas/frankenphp=./ \
4245
+ --with github.com/dunglas/frankenphp/caddy=./caddy/ \
4346
+ --with github.com/dunglas/mercure/caddy \
4447
+ --with github.com/dunglas/vulcain/caddy \
45-
+ # Use --with github.com/darkweak/souin for the latest improvements
48+
+ --with github.com/dunglas/caddy-cbrotli \
4649
+ --with github.com/caddyserver/cache-handler
50+
+ # Or use the following lines instead of the cache-handler one for the latest improvements
51+
+ # @65cb24114d76a7de3f4e8c7b8ef7df3efd028899 can be removed when a new release of `darkweak/souin` will be published
52+
+ #--with github.com/darkweak/souin/plugins/caddy@65cb24114d76a7de3f4e8c7b8ef7df3efd028899 \
53+
+ #--with github.com/darkweak/souin@65cb24114d76a7de3f4e8c7b8ef7df3efd028899 \
54+
+ #--with github.com/darkweak/storages/otter/caddy
4755
+
4856
+FROM dunglas/frankenphp:latest AS frankenphp_upstream
4957
+COPY --from=builder --link /usr/local/bin/frankenphp /usr/local/bin/frankenphp
5058
```
5159

5260
Update your Caddyfile with the following configuration:
61+
5362
```caddyfile
5463
{
55-
order cache before rewrite
56-
...
57-
cache {
58-
api {
59-
souin
60-
}
61-
}
64+
cache
65+
# ...
6266
}
67+
68+
# ...
6369
```
6470
This will tell to caddy to use the HTTP cache and activate the tag-based invalidation API. You can refer to the [cache-handler documentation](https://github.com/caddyserver/cache-handler) or the [souin website documentation](https://docs.souin.io) to learn how to configure the HTTP cache server.
6571

@@ -73,7 +79,25 @@ api_platform:
7379
urls: [ 'http://caddy/souin-api/souin' ]
7480
purger: api_platform.http_cache.purger.souin
7581
```
76-
And voilà, you have a fully working HTTP cache with it's own invalidation API.
82+
83+
Don't forget to set your `Cache-Control` directive to enable caching on your API resource class.
84+
This can be achieved using the `cacheHeaders` property:
85+
86+
```php
87+
use ApiPlatform\Metadata\ApiResource;
88+
89+
#[ApiResource(
90+
cacheHeaders: [
91+
'public' => true,
92+
'max_age' => 60,
93+
]
94+
)]
95+
class Book
96+
{
97+
// ...
98+
}
99+
```
100+
And voilà, you have a fully working HTTP cache with an invalidation API.
77101

78102
#### Varnish
79103

@@ -87,7 +111,6 @@ api_platform:
87111
invalidation:
88112
enabled: true
89113
varnish_urls: ['%env(VARNISH_URL)%']
90-
public: true
91114
defaults:
92115
cache_headers:
93116
max_age: 0
@@ -98,9 +121,9 @@ api_platform:
98121
## Configuration
99122

100123
Support for reverse proxies other than Varnish or Caddy with the HTTP cache module can be added by implementing the `ApiPlatform\HttpCache\PurgerInterface`.
101-
Three purgers are available, the built-in caddy http cache purger (`api_platform.http_cache.purger.souin`), the http tags (`api_platform.http_cache.purger.varnish.ban`), the surrogate key implementation
124+
Three purgers are available, the built-in caddy HTTP cache purger (`api_platform.http_cache.purger.souin`), the HTTP tags (`api_platform.http_cache.purger.varnish.ban`), the surrogate key implementation
102125
(`api_platform.http_cache.purger.varnish.xkey`). You can specify the implementation using the `purger` configuration node,
103-
for example to use the xkey implementation:
126+
for example, to use the `xkey` implementation:
104127

105128
```yaml
106129
api_platform:
@@ -125,7 +148,7 @@ to the client](push-relations.md).
125148

126149
### Extending Cache-Tags for Invalidation
127150

128-
Sometimes you need individual resources like `/me`. To work properly with Varnish, the `Cache-Tags` header needs to be
151+
Sometimes you need individual resources like `/me`. To work properly, the `Cache-Tags` header needs to be
129152
augmented with these resources. Here is an example of how this can be done:
130153

131154
```php
@@ -175,7 +198,7 @@ use ApiPlatform\Metadata\ApiResource;
175198
cacheHeaders: [
176199
'max_age' => 60,
177200
'shared_max_age' => 120,
178-
'vary' => ['Authorization', 'Accept-Language']
201+
'vary' => ['Authorization', 'Accept-Language'],
179202
]
180203
)]
181204
class Book
@@ -201,7 +224,7 @@ use ApiPlatform\Metadata\Get;
201224
#[Get(
202225
cacheHeaders: [
203226
'max_age' => 60,
204-
'shared_max_age' => 120
227+
'shared_max_age' => 120,
205228
]
206229
)]
207230
class Book
@@ -217,7 +240,8 @@ API Platform internally uses a [PSR-6](https://www.php-fig.org/psr/psr-6/) cache
217240
(the default in the API Platform distribution), it automatically enables support for the best cache adapter available.
218241

219242
Best performance is achieved using [APCu](https://github.com/krakjoe/apcu). Be sure to have the APCu extension installed
220-
on your production server. API Platform will automatically use it.
243+
on your production server (this is the case by default in the Docker image provided by the API Platform distribution).
244+
API Platform will automatically use it.
221245

222246
## Using PPM (PHP-PM)
223247

@@ -239,12 +263,12 @@ database driver.
239263

240264
### Eager Loading
241265

242-
By default Doctrine comes with [lazy loading](https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/working-with-objects.html#by-lazy-loading) - usually a killer time-saving feature but also a performance killer with large applications.
266+
By default, Doctrine comes with [lazy loading](https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/working-with-objects.html#by-lazy-loading) - usually a killer time-saving feature but also a performance killer with large applications.
243267

244268
Fortunately, Doctrine offers another approach to solve this problem: [eager loading](https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/working-with-objects.html#by-eager-loading).
245269
This can easily be enabled for a relation: `#[ORM\ManyToOne(fetch: "EAGER")]`.
246270

247-
By default in API Platform, we made the choice to force eager loading for all relations, with or without the Doctrine
271+
By default in API Platform, we chose to force eager loading for all relations, with or without the Doctrine
248272
`fetch` attribute. Thanks to the eager loading [extension](extensions.md). The `EagerLoadingExtension` will join every
249273
readable association according to the serialization context. If you want to fetch an association that is not serializable,
250274
you have to bypass `readable` and `readableLink` by using the `fetchEager` attribute on the property declaration, for example:
@@ -258,7 +282,7 @@ public $foo;
258282
...
259283
```
260284

261-
> **Warning**: in order to trigger the `EagerLoadingExtension` you must use [Serializer groups](serialization.md) on relations properties.
285+
> **Warning**: to trigger the `EagerLoadingExtension` you must use [Serializer groups](serialization.md) on relations properties.
262286

263287
#### Max Joins
264288

@@ -278,7 +302,7 @@ can be a good solution to fix this issue.
278302

279303
#### Fetch Partial
280304

281-
If you want to fetch only partial data according to serialization groups, you can enable `fetch_partial` parameter:
305+
If you want to fetch only partial data according to serialization groups, you can enable the `fetch_partial` parameter:
282306

283307
```yaml
284308
# api/config/packages/api_platform.yaml
@@ -292,8 +316,8 @@ If enabled, Doctrine ORM entities will not work as expected if any of the other
292316

293317
#### Force Eager
294318

295-
As mentioned above, by default we force eager loading for all relations. This behaviour can be modified in the
296-
configuration in order to apply it only on join relations having the `EAGER` fetch mode:
319+
As mentioned above, by default we force eager loading for all relations. This behavior can be modified in the
320+
configuration to apply it only on join relations having the `EAGER` fetch mode:
297321

298322
```yaml
299323
# api/config/packages/api_platform.yaml
@@ -341,7 +365,7 @@ class User
341365
/**
342366
* @var Group[]
343367
*/
344-
#[ORM\ManyToMany(targetEntity: 'Group', inversedBy: 'users')]
368+
#[ORM\ManyToMany(targetEntity: Group::class, inversedBy: 'users')]
345369
#[ORM\JoinTable(name: 'users_groups')]
346370
public $groups;
347371
@@ -370,14 +394,14 @@ class Group
370394
/**
371395
* @var User[]
372396
*/
373-
#[ORM\ManyToMany(targetEntity: 'User', mappedBy: 'groups')]
397+
#[ORM\ManyToMany(targetEntity: User::class, mappedBy: 'groups')]
374398
public $users;
375399
376400
// ...
377401
}
378402
```
379403

380-
Be careful, the operation level is higher priority than the resource level but both are higher priority than the global
404+
Be careful, the operation level has a higher priority than the resource level but both are higher priority than the global
381405
configuration.
382406

383407
#### Disable Eager Loading
@@ -396,7 +420,7 @@ The whole configuration described before will no longer work and Doctrine will r
396420
### Partial Pagination
397421

398422
When using the default pagination, the Doctrine paginator will execute a `COUNT` query on the collection. The result of the
399-
`COUNT` query is used to compute the last page available. With big collections this can lead to quite long response times.
423+
`COUNT` query is used to compute the last page available. With big collections, this can lead to quite long response times.
400424
If you don't mind not having the last page available, you can enable partial pagination and avoid the `COUNT` query:
401425

402426
```yaml
@@ -430,14 +454,14 @@ services:
430454

431455
2. Add your Blackfire.io ID and server token to your `.env` file at the root of your project (be sure not to commit this to a public repository):
432456

433-
```shell
457+
```console
434458
BLACKFIRE_SERVER_ID=xxxxxxxxxx
435459
BLACKFIRE_SERVER_TOKEN=xxxxxxxxxx
436460
```
437461

438462
Or set it in the console before running Docker commands:
439463

440-
```shell
464+
```console
441465
export BLACKFIRE_SERVER_ID=xxxxxxxxxx
442466
export BLACKFIRE_SERVER_TOKEN=xxxxxxxxxx
443467
```

0 commit comments

Comments
 (0)