@@ -22,8 +22,9 @@ server to clients. It is a modern and efficient alternative to timer-based
22
22
polling and to WebSocket.
23
23
24
24
Because it is built on top `Server-Sent Events (SSE) `_, Mercure is supported
25
- out of the box in most modern browsers (Edge and IE require `a polyfill `_) and
26
- has `high-level implementations `_ in many programming languages.
25
+ out of the box in most modern browsers (old versions of Edge and IE require
26
+ `a polyfill `_) and has `high-level implementations `_ in many programming
27
+ languages.
27
28
28
29
Mercure comes with an authorization mechanism,
29
30
automatic re-connection in case of network issues
@@ -65,34 +66,19 @@ clients.
65
66
66
67
.. image :: /_images/mercure/schema.png
67
68
68
- An official and open source (AGPL) implementation of a Hub can be downloaded
69
- as a static binary from ` Mercure.rocks `_ .
69
+ If you use the ` Symfony Local Web Server < /setup/symfony_server >`_ or ` Symfony Docker `_,
70
+ a Mercure Hub is automatically available .
70
71
71
- If you use `Symfony Docker `_,
72
- a Mercure Hub is already included and you can skip straight to the next section.
73
-
74
- On Linux and Mac, run the following command to start it:
75
-
76
- .. rst-class :: command-linux
77
-
78
- $ SERVER_NAME=:3000 MERCURE_PUBLISHER_JWT_KEY='!ChangeMe!' MERCURE_SUBSCRIBER_JWT_KEY='!ChangeMe!' ./mercure run -config Caddyfile.dev
79
-
80
- On Windows run:
81
-
82
- .. rst-class: command-windows
83
-
84
- > $env:SERVER_NAME=':3000'; $env:MERCURE_PUBLISHER_JWT_KEY='!ChangeMe!'; $env:MERCURE_SUBSCRIBER_JWT_KEY='!ChangeMe!'; .\mercure.exe run -config Caddyfile.dev
85
-
86
- .. note ::
87
-
88
- Alternatively to the binary, a Docker image, a Helm chart for Kubernetes
89
- and a managed, High Availability Hub are also provided by Mercure.rocks.
72
+ For production usage, an official and open source (AGPL) Hub based on the Caddy web server
73
+ can be downloaded as a static binary from `Mercure.rocks `_.
74
+ Alternatively to the binary, a Docker image, a Helm chart for Kubernetes
75
+ and a managed, High Availability Hub are also provided.
90
76
91
77
.. tip ::
92
78
93
79
The `API Platform distribution `_ comes with a Docker Compose configuration
94
80
as well as a Helm chart for Kubernetes that are 100% compatible with Symfony,
95
- and contain a Mercure hub.
81
+ and contain a build of the Caddy web server including a Mercure hub.
96
82
You can copy them in your project, even if you don't use API Platform.
97
83
98
84
Configuration
@@ -101,18 +87,30 @@ Configuration
101
87
The preferred way to configure the MercureBundle is using
102
88
:doc: `environment variables </configuration >`.
103
89
104
- Set the URL of your hub as the value of the ``MERCURE_PUBLISH_URL `` env var.
105
- The ``.env `` file of your project has been updated by the Flex recipe to
106
- provide example values.
107
- Set it to the URL of the Mercure Hub (``http://localhost:3000/.well-known/mercure `` by default).
90
+ When MercureBundle has been installed, the ``.env `` file of your project
91
+ has been updated by the Flex recipe to include the available env vars.
92
+
93
+ If you use the Symfony Local Web Server or Symfony Docker,
94
+ the default values are compatible with the provided Hub
95
+ and you can skip straight to the next section.
108
96
109
- In addition, the Symfony application must bear a `JSON Web Token `_ (JWT)
110
- to the Mercure Hub to be authorized to publish updates.
97
+ Otherwise, set the URL of your hub as the value of the ``MERCURE_URL ``
98
+ and ``MERCURE_PUBLIC_URL `` env vars.
99
+ Sometimes a different URL must be called by the Symfony app (usually to publish),
100
+ and the JavaScript client (usually to subscrribe). It's especially common when
101
+ the Symfony app must use a local URL and the client-side JavaScript code a public one.
102
+ In this case, ``MERCURE_URL `` must contain the local URL that will be used by the
103
+ Symfony app (e.g. ``https://mercure/.well-known/mercure ``), and ``MERCURE_PUBLIC_URL ``
104
+ the publicly available URL (e.g. ``https://example.com/.well-known/mercure ``).
111
105
112
- This JWT should be stored in the ``MERCURE_JWT_TOKEN `` environment variable.
106
+ The clients must also bear a `JSON Web Token `_ (JWT)
107
+ to the Mercure Hub to be authorized to publish updates and, sometimes, to subscribe.
108
+
109
+ This JWT should be stored in the ``MERCURE_JWT_SECRET `` environment variable.
113
110
114
111
The JWT must be signed with the same secret key as the one used by
115
- the Hub to verify the JWT (``!ChangeMe! `` in our example).
112
+ the Hub to verify the JWT (``!ChangeMe! `` in you use the Local Web Server or
113
+ Symfony Docker).
116
114
Its payload must contain at least the following structure to be allowed to
117
115
publish:
118
116
@@ -136,7 +134,7 @@ public updates (see the authorization_ section for further information).
136
134
137
135
.. caution ::
138
136
139
- Don't put the secret key in ``MERCURE_JWT_TOKEN ``, it will not work!
137
+ Don't put the secret key in ``MERCURE_JWT_SECRET ``, it will not work!
140
138
This environment variable must contain a JWT, signed with the secret key.
141
139
142
140
Also, be sure to keep both the secret key and the JWTs... secrets!
@@ -158,13 +156,14 @@ service, including controllers::
158
156
// src/Controller/PublishController.php
159
157
namespace App\Controller;
160
158
159
+ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
161
160
use Symfony\Component\HttpFoundation\Response;
162
161
use Symfony\Component\Mercure\HubInterface;
163
162
use Symfony\Component\Mercure\Update;
164
163
165
- class PublishController
164
+ class PublishController extends AbstractController
166
165
{
167
- public function __invoke (HubInterface $hub): Response
166
+ public function publish (HubInterface $hub): Response
168
167
{
169
168
$update = new Update(
170
169
'http://example.com/books/1',
@@ -198,7 +197,7 @@ Subscribing to updates in JavaScript is straightforward:
198
197
199
198
.. code-block :: javascript
200
199
201
- const eventSource = new EventSource (' http://localhost:3000 /.well-known/mercure?topic=' + encodeURIComponent (' http://example.com/books/1' ));
200
+ const eventSource = new EventSource (' /.well-known/mercure?topic=' + encodeURIComponent (' http://example.com/books/1' ));
202
201
eventSource .onmessage = event => {
203
202
// Will be called every time an update is published by the server
204
203
console .log (JSON .parse (event .data ));
@@ -211,7 +210,7 @@ as patterns:
211
210
.. code-block :: javascript
212
211
213
212
// URL is a built-in JavaScript class to manipulate URLs
214
- const url = new URL (' http://localhost:3000/ .well-known/mercure' );
213
+ const url = new URL (' / .well-known/mercure' , window . origin );
215
214
url .searchParams .append (' topic' , ' http://example.com/books/1' );
216
215
// Subscribe to updates of several Book resources
217
216
url .searchParams .append (' topic' , ' http://example.com/books/2' );
@@ -241,43 +240,6 @@ as patterns:
241
240
242
241
Test if a URI Template match a URL using `the online debugger `_
243
242
244
- Async dispatching
245
- -----------------
246
-
247
- Instead of calling the ``Publisher `` service directly, you can also let Symfony
248
- dispatching the updates asynchronously thanks to the provided integration with
249
- the Messenger component.
250
-
251
- First, be sure :doc: `to install the Messenger component </messenger >`
252
- and to configure properly a transport (if you don't, the handler will
253
- be called synchronously).
254
-
255
- Then, dispatch the Mercure ``Update `` to the Messenger's Message Bus,
256
- it will be handled automatically::
257
-
258
- // src/Controller/PublishController.php
259
- namespace App\Controller;
260
-
261
- use Symfony\Component\HttpFoundation\Response;
262
- use Symfony\Component\Mercure\Update;
263
- use Symfony\Component\Messenger\MessageBusInterface;
264
-
265
- class PublishController
266
- {
267
- public function __invoke(MessageBusInterface $bus): Response
268
- {
269
- $update = new Update(
270
- 'http://example.com/books/1',
271
- json_encode(['status' => 'OutOfStock'])
272
- );
273
-
274
- // Sync, or async (RabbitMQ, Kafka...)
275
- $bus->dispatch($update);
276
-
277
- return new Response('published!');
278
- }
279
- }
280
-
281
243
Discovery
282
244
---------
283
245
@@ -324,7 +286,7 @@ and to subscribe to it:
324
286
const hubUrl = response .headers .get (' Link' ).match (/ <([^ >] + )>;\s + rel=(?:mercure| "[^ "] * mercure[^ "] * ")/ )[1 ];
325
287
326
288
// Append the topic(s) to subscribe as query parameter
327
- const hub = new URL (hubUrl);
289
+ const hub = new URL (hubUrl, window . origin );
328
290
hub .searchParams .append (' topic' , ' http://example.com/books/{id}' );
329
291
330
292
// Subscribe to updates
@@ -348,7 +310,7 @@ of the ``Update`` constructor to ``true``::
348
310
349
311
class PublishController extends AbstractController
350
312
{
351
- public function __invoke (HubInterface $hub): Response
313
+ public function publish (HubInterface $hub): Response
352
314
{
353
315
$update = new Update(
354
316
'http://example.com/books/1',
@@ -457,7 +419,7 @@ And here is the controller::
457
419
458
420
class DiscoverController extends AbstractController
459
421
{
460
- public function __invoke (Request $request, Discovery $discovery, Authorization $authorization): Response
422
+ public function publish (Request $request, Discovery $discovery, Authorization $authorization): Response
461
423
{
462
424
$discovery->addLink($request);
463
425
@@ -602,7 +564,7 @@ During unit testing there is not need to send updates to Mercure.
602
564
603
565
You can instead make use of the `MockHub `::
604
566
605
- // tests/Functional/ .php
567
+ // tests/FunctionalTest .php
606
568
namespace App\Tests\Unit\Controller;
607
569
608
570
use App\Controller\MessageController;
@@ -654,6 +616,10 @@ sent. Here is the HubStub implementation:
654
616
App\Tests\Functional\Fixtures\HubStub :
655
617
decorates : mercure.hub.default
656
618
619
+ .. tip ::
620
+
621
+ Symfony Panther has `a feature to test applications using Mercure `_.
622
+
657
623
Debugging
658
624
---------
659
625
@@ -694,6 +660,51 @@ Enable the panel in your configuration, as follows:
694
660
695
661
.. image :: /_images/mercure/panel.png
696
662
663
+ Async dispatching
664
+ -----------------
665
+
666
+ .. tip ::
667
+
668
+ Async dispatching is discouraged. Most Mercure hubs already
669
+ handle publications asynchronously and using Messenger is
670
+ usually not necessary.
671
+
672
+ Instead of calling the ``Publisher `` service directly, you can also let Symfony
673
+ dispatching the updates asynchronously thanks to the provided integration with
674
+ the Messenger component.
675
+
676
+ First, be sure :doc: `to install the Messenger component </messenger >`
677
+ and to configure properly a transport (if you don't, the handler will
678
+ be called synchronously).
679
+
680
+ Then, dispatch the Mercure ``Update `` to the Messenger's Message Bus,
681
+ it will be handled automatically::
682
+
683
+ // src/Controller/PublishController.php
684
+ namespace App\Controller;
685
+
686
+ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
687
+ use Symfony\Component\HttpFoundation\Response;
688
+ use Symfony\Component\Mercure\Update;
689
+ use Symfony\Component\Messenger\MessageBusInterface;
690
+
691
+ class PublishController extends AbstractController
692
+ {
693
+ public function publish(MessageBusInterface $bus): Response
694
+ {
695
+ $update = new Update(
696
+ 'http://example.com/books/1',
697
+ json_encode(['status' => 'OutOfStock'])
698
+ );
699
+
700
+ // Sync, or async (Doctrine, RabbitMQ, Kafka...)
701
+ $bus->dispatch($update);
702
+
703
+ return new Response('published!');
704
+ }
705
+ }
706
+
707
+
697
708
.. _`the Mercure protocol` : https://mercure.rocks/spec
698
709
.. _`Server-Sent Events (SSE)` : https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events
699
710
.. _`a polyfill` : https://github.com/Yaffle/EventSource
@@ -708,3 +719,4 @@ Enable the panel in your configuration, as follows:
708
719
.. _`practical UI` : https://twitter.com/ChromeDevTools/status/562324683194785792
709
720
.. _`the dedicated API Platform documentation` : https://api-platform.com/docs/core/mercure/
710
721
.. _`the online debugger` : https://uri-template-tester.mercure.rocks
722
+ .. _`a feature to test applications using Mercure` : https://github.com/symfony/panther#creating-isolated-browsers-to-test-apps-using-mercure-or-websocket
0 commit comments