Skip to content

Commit a90e5e7

Browse files
committed
Fix setting cache headers to no cache for me endpoint
1 parent c77b313 commit a90e5e7

File tree

7 files changed

+69
-48
lines changed

7 files changed

+69
-48
lines changed

features/user/me.feature

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Feature: Add a /me endpoint
1414
And the JSON should be valid according to the schema file "user.schema.json"
1515
And the JSON node "@id" should be equal to the IRI of the resource "login_user"
1616
And the JSON node "_metadata.mercureSubscribeTopics[0]" should be equal to "http://example.com/_/component_groups/{id}{._format}"
17+
And the header "cache-control" should be equal to "max-age=0, private"
1718

1819
@loginUser
1920
Scenario: I can retrieve the current logged in user object
@@ -22,6 +23,7 @@ Feature: Add a /me endpoint
2223
And the JSON should be valid according to the schema file "user.schema.json"
2324
And the JSON node "@id" should be equal to the IRI of the resource "login_user"
2425
And the JSON node "_metadata.mercureSubscribeTopics[0]" should be equal to "http://example.com/_/component_groups/{id}{._format}"
26+
And the header "cache-control" should be equal to "max-age=0, private"
2527

2628
Scenario: I can retrieve the current logged in user object
2729
When I send a "GET" request to "/me"

src/ApiPlatform/Api/IriConverter.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ private function getUserGetOperation(?Operation $operation = null): Operation
6666
// We want relations when they are found, to use the IRI with the path
6767
public function getIriFromResource($resource, int $referenceType = UrlGeneratorInterface::ABS_PATH, ?Operation $operation = null, array $context = []): ?string
6868
{
69-
if ('me' === $operation?->getName()) {
69+
if ('_api_me' === $operation?->getName()) {
7070
$checkOperation = $this->getUserGetOperation($operation);
7171
$operation = $checkOperation;
7272
$context['operation'] = $checkOperation;

src/ApiPlatform/Metadata/Resource/UserResourceMetadataCollectionFactory.php

Lines changed: 43 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,8 @@
1313

1414
namespace Silverback\ApiComponentsBundle\ApiPlatform\Metadata\Resource;
1515

16-
use ApiPlatform\Metadata\ApiResource;
1716
use ApiPlatform\Metadata\Get;
18-
use ApiPlatform\Metadata\HttpOperation;
1917
use ApiPlatform\Metadata\Operation;
20-
use ApiPlatform\Metadata\Operations;
2118
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
2219
use ApiPlatform\Metadata\Resource\ResourceMetadataCollection;
2320
use Silverback\ApiComponentsBundle\DataProvider\StateProvider\UserStateProvider;
@@ -28,58 +25,65 @@
2825
*
2926
* @author Daniel West <[email protected]>
3027
*/
31-
class UserResourceMetadataCollectionFactory implements ResourceMetadataCollectionFactoryInterface
28+
readonly class UserResourceMetadataCollectionFactory implements ResourceMetadataCollectionFactoryInterface
3229
{
33-
public function __construct(private readonly ResourceMetadataCollectionFactoryInterface $decorated)
30+
public function __construct(private ResourceMetadataCollectionFactoryInterface $decorated)
3431
{
3532
}
3633

3734
public function create(string $resourceClass): ResourceMetadataCollection
3835
{
39-
$resourceMetadata = $this->decorated->create($resourceClass);
36+
$resourceMetadataCollection = $this->decorated->create($resourceClass);
37+
4038
if (!is_a($resourceClass, AbstractUser::class, true)) {
41-
return $resourceMetadata;
39+
return $resourceMetadataCollection;
4240
}
4341

44-
$input = [];
45-
/** @var ApiResource $resourceMetadatum */
46-
foreach ($resourceMetadata as $resourceMetadatum) {
47-
$operations = $resourceMetadatum->getOperations();
48-
if ($operations) {
49-
$getOperation = $this->findGetOperation($operations);
50-
if ($getOperation) {
51-
$newOperations = [
52-
$this->createMeOperation($getOperation),
53-
];
54-
foreach ($newOperations as $newOperation) {
55-
$operations->add($newOperation->getName(), $newOperation);
56-
}
42+
foreach ($resourceMetadataCollection as $i => $resource) {
43+
$resource = $resource->withCacheHeaders([
44+
'public' => false,
45+
'shared_max_age' => 0,
46+
'max_age' => 0,
47+
]);
48+
$operations = $resource->getOperations();
49+
foreach ($operations as $key => $operation) {
50+
if ($operation instanceof Get) {
51+
$meOperation = $this->createMeOperation($operation);
52+
$operations->add(
53+
'_api_me',
54+
$meOperation
55+
);
5756
}
57+
$operations->add(
58+
$key,
59+
$operation->withCacheHeaders([
60+
'public' => false,
61+
'shared_max_age' => 0,
62+
'max_age' => 0,
63+
])
64+
);
5865
}
59-
$input[] = $resourceMetadatum;
60-
}
61-
62-
return new ResourceMetadataCollection($resourceClass, $input);
63-
}
64-
65-
private function findGetOperation(Operations $operations): ?Get
66-
{
67-
foreach ($operations as $operation) {
68-
if ($operation instanceof Get) {
69-
return $operation;
70-
}
66+
$resourceMetadataCollection[$i] = $resource->withOperations($operations);
7167
}
7268

73-
return null;
69+
return $resourceMetadataCollection;
7470
}
7571

7672
private function createMeOperation(Get $operation): Operation
7773
{
78-
return (new HttpOperation(HttpOperation::METHOD_GET, '/me{._format}'))
79-
->withName('me')
80-
->withShortName($operation->getShortName())
81-
->withClass($operation->getClass())
82-
->withSecurity('is_granted("IS_AUTHENTICATED_FULLY")')
83-
->withProvider(UserStateProvider::class);
74+
return new Get(
75+
uriTemplate: '/me{._format}',
76+
routePrefix: $operation->getRoutePrefix(),
77+
cacheHeaders: [
78+
'public' => false,
79+
'shared_max_age' => 0,
80+
'max_age' => 0,
81+
],
82+
shortName: '__api_me',
83+
class: $operation->getClass(),
84+
security: 'is_granted("IS_AUTHENTICATED_FULLY")',
85+
name: '_api_me',
86+
provider: UserStateProvider::class
87+
);
8488
}
8589
}

src/EventListener/Api/UserEventListener.php

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@
2424
/**
2525
* @author Daniel West <[email protected]>
2626
*/
27-
class UserEventListener
27+
readonly class UserEventListener
2828
{
2929
public function __construct(
30-
private readonly UserMailer $userMailer,
31-
private readonly Security $security,
30+
private UserMailer $userMailer,
31+
private Security $security,
3232
) {
3333
}
3434

@@ -42,7 +42,7 @@ public function onPreRead(RequestEvent $event): void
4242
if (
4343
empty($resourceClass)
4444
|| !is_a($resourceClass, AbstractUser::class, true)
45-
|| 'me' !== $request->attributes->get('_api_operation_name')
45+
|| '_api_me' !== $request->attributes->get('_api_operation_name')
4646
) {
4747
return;
4848
}
@@ -62,6 +62,20 @@ public function onPreRead(RequestEvent $event): void
6262
$request->attributes->set('id', $user->getUsername());
6363
}
6464

65+
public function onPostRead(RequestEvent $event): void
66+
{
67+
$request = $event->getRequest();
68+
$class = $request->attributes->get('_api_resource_class');
69+
70+
if ($class === AbstractUser::class) {
71+
$resources = [
72+
'/me'
73+
];
74+
75+
$request->attributes->set('_resources', $request->attributes->get('_resources', []) + $resources);
76+
}
77+
}
78+
6579
public function onPostWrite(ViewEvent $event): void
6680
{
6781
$request = $event->getRequest();

src/Resources/config/api_platform/form/resource.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<operation class="ApiPlatform\Metadata\Put" />
1212
<operation class="ApiPlatform\Metadata\Patch" />
1313
<operation class="ApiPlatform\Metadata\Patch"
14-
name="submit_patch"
14+
name="_api_/forms/{id}/submit{._format}"
1515
method="PATCH"
1616
uriTemplate="/forms/{id}/submit{._format}"
1717
read="true"
@@ -24,7 +24,7 @@
2424
</requirements>
2525
</operation>
2626
<operation class="ApiPlatform\Metadata\Put"
27-
name="submit_post"
27+
name="_api_/forms/{id}/submit{._format}"
2828
method="POST"
2929
uriTemplate="/forms/{id}/submit{._format}"
3030
read="true"

src/Resources/config/services.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1160,7 +1160,8 @@
11601160
]
11611161
)
11621162
->tag('kernel.event_listener', ['event' => ViewEvent::class, 'priority' => EventPriorities::POST_WRITE, 'method' => 'onPostWrite'])
1163-
->tag('kernel.event_listener', ['event' => RequestEvent::class, 'priority' => EventPriorities::PRE_READ, 'method' => 'onPreRead']);
1163+
->tag('kernel.event_listener', ['event' => RequestEvent::class, 'priority' => EventPriorities::PRE_READ, 'method' => 'onPreRead'])
1164+
->tag('kernel.event_listener', ['event' => RequestEvent::class, 'priority' => EventPriorities::POST_READ, 'method' => 'onPostRead']);
11641165

11651166
$services
11661167
->set(UserFactory::class)

src/Security/EventListener/AccessDeniedListener.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public function onPostRespond(ResponseEvent $event): void
3333
$attributes = $this->getAttributes($request);
3434
if (
3535
!($operation = $attributes['operation'] ?? null)
36-
|| 'me' !== $operation->getName()
36+
|| '_api_me' !== $operation->getName()
3737
|| !($response = $event->getResponse()) instanceof JWTAuthenticationFailureResponse) {
3838
return;
3939
}

0 commit comments

Comments
 (0)