@@ -22,8 +22,9 @@ server to clients. It is a modern and efficient alternative to timer-based
2222polling and to WebSocket.
2323
2424Because 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.
2728
2829Mercure comes with an authorization mechanism,
2930automatic re-connection in case of network issues
@@ -65,34 +66,19 @@ clients.
6566
6667.. image :: /_images/mercure/schema.png
6768
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 .
7071
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.
9076
9177.. tip ::
9278
9379 The `API Platform distribution `_ comes with a Docker Compose configuration
9480 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.
9682 You can copy them in your project, even if you don't use API Platform.
9783
9884Configuration
@@ -101,18 +87,30 @@ Configuration
10187The preferred way to configure the MercureBundle is using
10288:doc: `environment variables </configuration >`.
10389
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.
10896
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 ``).
111105
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.
113110
114111The 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).
116114Its payload must contain at least the following structure to be allowed to
117115publish:
118116
@@ -136,7 +134,7 @@ public updates (see the authorization_ section for further information).
136134
137135.. caution ::
138136
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!
140138 This environment variable must contain a JWT, signed with the secret key.
141139
142140 Also, be sure to keep both the secret key and the JWTs... secrets!
@@ -158,13 +156,14 @@ service, including controllers::
158156 // src/Controller/PublishController.php
159157 namespace App\Controller;
160158
159+ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
161160 use Symfony\Component\HttpFoundation\Response;
162161 use Symfony\Component\Mercure\HubInterface;
163162 use Symfony\Component\Mercure\Update;
164163
165- class PublishController
164+ class PublishController extends AbstractController
166165 {
167- public function __invoke (HubInterface $hub): Response
166+ public function publish (HubInterface $hub): Response
168167 {
169168 $update = new Update(
170169 'http://example.com/books/1',
@@ -198,7 +197,7 @@ Subscribing to updates in JavaScript is straightforward:
198197
199198.. code-block :: javascript
200199
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' ));
202201 eventSource .onmessage = event => {
203202 // Will be called every time an update is published by the server
204203 console .log (JSON .parse (event .data ));
@@ -211,7 +210,7 @@ as patterns:
211210.. code-block :: javascript
212211
213212 // 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 );
215214 url .searchParams .append (' topic' , ' http://example.com/books/1' );
216215 // Subscribe to updates of several Book resources
217216 url .searchParams .append (' topic' , ' http://example.com/books/2' );
@@ -241,43 +240,6 @@ as patterns:
241240
242241 Test if a URI Template match a URL using `the online debugger `_
243242
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-
281243Discovery
282244---------
283245
@@ -324,7 +286,7 @@ and to subscribe to it:
324286 const hubUrl = response .headers .get (' Link' ).match (/ <([^ >] + )>;\s + rel=(?:mercure| "[^ "] * mercure[^ "] * ")/ )[1 ];
325287
326288 // Append the topic(s) to subscribe as query parameter
327- const hub = new URL (hubUrl);
289+ const hub = new URL (hubUrl, window . origin );
328290 hub .searchParams .append (' topic' , ' http://example.com/books/{id}' );
329291
330292 // Subscribe to updates
@@ -348,7 +310,7 @@ of the ``Update`` constructor to ``true``::
348310
349311 class PublishController extends AbstractController
350312 {
351- public function __invoke (HubInterface $hub): Response
313+ public function publish (HubInterface $hub): Response
352314 {
353315 $update = new Update(
354316 'http://example.com/books/1',
@@ -457,7 +419,7 @@ And here is the controller::
457419
458420 class DiscoverController extends AbstractController
459421 {
460- public function __invoke (Request $request, Discovery $discovery, Authorization $authorization): Response
422+ public function publish (Request $request, Discovery $discovery, Authorization $authorization): Response
461423 {
462424 $discovery->addLink($request);
463425
@@ -602,7 +564,7 @@ During unit testing there is not need to send updates to Mercure.
602564
603565You can instead make use of the `MockHub `::
604566
605- // tests/Functional/ .php
567+ // tests/FunctionalTest .php
606568 namespace App\Tests\Unit\Controller;
607569
608570 use App\Controller\MessageController;
@@ -654,6 +616,10 @@ sent. Here is the HubStub implementation:
654616 App\Tests\Functional\Fixtures\HubStub :
655617 decorates : mercure.hub.default
656618
619+ .. tip ::
620+
621+ Symfony Panther has `a feature to test applications using Mercure `_.
622+
657623Debugging
658624---------
659625
@@ -694,6 +660,51 @@ Enable the panel in your configuration, as follows:
694660
695661 .. image :: /_images/mercure/panel.png
696662
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+
697708.. _`the Mercure protocol` : https://mercure.rocks/spec
698709.. _`Server-Sent Events (SSE)` : https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events
699710.. _`a polyfill` : https://github.com/Yaffle/EventSource
@@ -708,3 +719,4 @@ Enable the panel in your configuration, as follows:
708719.. _`practical UI` : https://twitter.com/ChromeDevTools/status/562324683194785792
709720.. _`the dedicated API Platform documentation` : https://api-platform.com/docs/core/mercure/
710721.. _`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