Skip to content

Commit 142a6f9

Browse files
committed
[mercure] Compatibility with the Docker integration and various improvements
1 parent 123ad73 commit 142a6f9

File tree

1 file changed

+111
-50
lines changed

1 file changed

+111
-50
lines changed

mercure.rst

+111-50
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ requiring "push" capabilities.
1717
Symfony provides a straightforward component, built on top of
1818
`the Mercure protocol`_, specifically designed for this class of use cases.
1919

20-
Mercure is an open protocol designed from the ground to publish updates from
20+
Mercure is an open protocol designed from the ground up to publish updates from
2121
server to clients. It is a modern and efficient alternative to timer-based
2222
polling and to WebSocket.
2323

2424
Because it is built on top `Server-Sent Events (SSE)`_, Mercure is supported
25-
out of the box in most modern browsers (old versions of Edge and IE require
25+
out of the box in modern browsers (old versions of Edge and IE require
2626
`a polyfill`_) and has `high-level implementations`_ in many programming
2727
languages.
2828

@@ -42,49 +42,44 @@ generated using the API Platform client generator.
4242
Installation
4343
------------
4444

45-
Running a Mercure Hub
46-
~~~~~~~~~~~~~~~~~~~~~
45+
Installing the Symfony Bundle
46+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
47+
48+
Run this command to install the Mercure support:
49+
50+
.. code-block:: terminal
51+
52+
$ composer require mercure
4753
4854
To manage persistent connections, Mercure relies on a Hub: a dedicated server
4955
that handles persistent SSE connections with the clients.
5056
The Symfony app publishes the updates to the hub, that will broadcast them to
5157
clients.
5258

53-
.. image:: /_images/mercure/schema.png
54-
55-
An official and open source (AGPL) Hub based on the Caddy web server
56-
can be downloaded as a static binary from `Mercure.rocks`_.
57-
A Docker image, a Helm chart for Kubernetes
58-
and a managed, High Availability Hub are also provided.
59-
60-
If you use `Symfony Docker`_ or the `API Platform distribution`_, a Mercure Hub
61-
is automatically installed and your Symfony application is automatically
62-
configured to use it. You can jump directly to the next section.
59+
Thanks to :ref:`the Docker integration of Symfony </setup/docker>`,
60+
:ref:`Flex <symfony-flex>` proposes to install a Mercure hub.
61+
Run ``docker-compose up`` to start the hub if you have chosen this option.
6362

6463
If you use the :doc:`Symfony Local Web Server </setup/symfony_server>`,
65-
a Mercure hub will be automatically available as a Docker service thanks to its
66-
:ref:`Docker integration <symfony-server-docker>.
67-
68-
Be sure that recent versions of Docker and Docker Compose are properly installed
69-
on your computer and to start the Symfony Local Web Server with the ``--no-tls``
70-
option:
64+
you must start it with the ``--no-tls`` option.
7165

7266
.. code-block:: terminal
7367
7468
$ symfony server:start --no-tls -d
7569
76-
Installing the Symfony Bundle
77-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
78-
79-
Run this command to install the Mercure support before using it:
70+
Running a Mercure Hub
71+
~~~~~~~~~~~~~~~~~~~~~
8072

81-
.. code-block:: terminal
73+
.. image:: /_images/mercure/schema.png
8274

83-
$ composer require mercure
75+
If you use the Docker integration, a hub is already up and running,
76+
and you can go straight to the next section.
8477

85-
:ref:`Symfony Flex <symfony-flex>` has automatically installed and configured
86-
MercureBundle. It also created (if needed) and configured a Docker Compose
87-
definition that provides a Mercure service. Run ``docker-compose up`` to start it.
78+
Otherwise, and in production, you have to install a hub by yourself.
79+
An official and open source (AGPL) Hub based on the Caddy web server
80+
can be downloaded as a static binary from `Mercure.rocks`_.
81+
A Docker image, a Helm chart for Kubernetes
82+
and a managed, High Availability Hub are also provided.
8883

8984
Configuration
9085
-------------
@@ -95,23 +90,26 @@ The preferred way to configure MercureBundle is using
9590
When MercureBundle has been installed, the ``.env`` file of your project
9691
has been updated by the Flex recipe to include the available env vars.
9792

98-
If you use the Symfony Local Web Server, Symfony Docker or the API Platform
99-
distribution, the Symfony app is automatically configured and you can skip
100-
straight to the next section.
93+
Also, if you are using the Docker integration with the Symfony Local Web Server,
94+
`Symfony Docker`_ or the `API Platform distribution`_,
95+
the proper environment variables have been automatically set.
96+
Skip straight to the next section.
10197

10298
Otherwise, set the URL of your hub as the value of the ``MERCURE_URL``
10399
and ``MERCURE_PUBLIC_URL`` env vars.
104100
Sometimes a different URL must be called by the Symfony app (usually to publish),
105101
and the JavaScript client (usually to subscribe). It's especially common when
106102
the Symfony app must use a local URL and the client-side JavaScript code a public one.
107-
In this case, ``MERCURE_URL`` must contain the local URL that will be used by the
103+
In this case, ``MERCURE_URL`` must contain the local URL used by the
108104
Symfony app (e.g. ``https://mercure/.well-known/mercure``), and ``MERCURE_PUBLIC_URL``
109105
the publicly available URL (e.g. ``https://example.com/.well-known/mercure``).
110106

111107
The clients must also bear a `JSON Web Token`_ (JWT)
112108
to the Mercure Hub to be authorized to publish updates and, sometimes, to subscribe.
113109

114-
This token must be signed with the same secret key as the one used by the Hub to verify the JWT (``!ChangeMe!`` in you use the Local Web Server or Symfony Docker), which should be stored in the ``MERCURE_JWT_SECRET`` environment variable.
110+
This token must be signed with the same secret key as the one used by the Hub to verify the JWT (``!ChangeMe!`` in you use the Docker integration).
111+
This secret key must be stored in the ``MERCURE_JWT_SECRET`` environment variable.
112+
MercureBundle will use it to automatically generate and sign the needed JWTs.
115113

116114
If you don't want to use the provided environment variables,
117115
use the following configuration:
@@ -155,6 +153,68 @@ use the following configuration:
155153
],
156154
]);
157155
156+
Alternatively, it's also possible to pass directly the JWT to use:
157+
158+
.. configuration-block::
159+
160+
.. code-block:: yaml
161+
162+
# config/packages/mercure.yaml
163+
mercure:
164+
hubs:
165+
default:
166+
url: https://mercure-hub.example.com/.well-known/mercure
167+
jwt:
168+
value: 'the.JWT'
169+
170+
.. code-block:: xml
171+
172+
<!-- config/packages/mercure.xml -->
173+
<?xml version="1.0" encoding="UTF-8" ?>
174+
<config>
175+
<hub
176+
name="default"
177+
url="https://mercure-hub.example.com/.well-known/mercure"
178+
>
179+
<jwt value="the.JWT"/>
180+
</hub>
181+
</config>
182+
183+
.. code-block:: php
184+
185+
// config/packages/mercure.php
186+
$container->loadFromExtension('mercure', [
187+
'hubs' => [
188+
'default' => [
189+
'url' => 'https://mercure-hub.example.com/.well-known/mercure',
190+
'jwt' => [
191+
'value' => 'the.JWT',
192+
],
193+
],
194+
],
195+
]);
196+
197+
198+
The JWT payload must contain at least the following structure to be allowed to
199+
publish:
200+
201+
.. code-block:: json
202+
203+
{
204+
"mercure": {
205+
"publish": []
206+
}
207+
}
208+
209+
Because the array is empty, the Symfony app will only be authorized to publish
210+
public updates (see the authorization_ section for further information).
211+
212+
.. tip::
213+
214+
The jwt.io website is a convenient way to create and sign JWTs.
215+
Checkout this `example JWT`_, that grants publishing rights for all *topics*
216+
(notice the star in the array).
217+
Don't forget to set your secret key properly in the bottom of the right panel of the form!
158218

159219
Basic Usage
160220
-----------
@@ -222,8 +282,8 @@ Subscribing to updates in JavaScript from a Twig template is straightforward:
222282
}
223283
</script>
224284
225-
The ``mercure()`` Twig function will generate the URL of the Mercure hub
226-
according to the configuration. The URL will include the ``topic`` query
285+
The ``mercure()`` Twig function generates the URL of the Mercure hub
286+
according to the configuration. The URL includes the ``topic`` query
227287
parameters corresponding to the topics passed as first argument.
228288

229289
If you want to access to this URL from an external JavaScript file, generate the
@@ -302,9 +362,9 @@ by using the ``AbstractController::addLink`` helper method::
302362

303363
class DiscoverController extends AbstractController
304364
{
305-
public function __invoke(Request $request, Discovery $discovery): JsonResponse
365+
public function discover(Request $request, Discovery $discovery): JsonResponse
306366
{
307-
// Link: <http://localhost:3000/.well-known/mercure>; rel="mercure"
367+
// Link: <http://hub.example.com/.well-known/mercure>; rel="mercure"
308368
$discovery->addLink($request);
309369

310370
return $this->json([
@@ -320,7 +380,7 @@ and to subscribe to it:
320380
.. code-block:: javascript
321381
322382
// Fetch the original resource served by the Symfony web API
323-
fetch('/books/1') // Has Link: <http://localhost:3000/.well-known/mercure>; rel="mercure"
383+
fetch('/books/1') // Has Link: <http://hub.example.com/.well-known/mercure>; rel="mercure"
324384
.then(response => {
325385
// Extract the hub URL from the Link header
326386
const hubUrl = response.headers.get('Link').match(/<([^>]+)>;\s+rel=(?:mercure|"[^"]*mercure[^"]*")/)[1];
@@ -373,9 +433,9 @@ To provide this JWT, the subscriber can use a cookie,
373433
or a ``Authorization`` HTTP header.
374434

375435
Cookies can be set automatically by Symfony by passing the appropriate options
376-
to the ``mercure()`` Twig function. Cookies set by Symfony will be automatically
436+
to the ``mercure()`` Twig function. Cookies set by Symfony are automatically
377437
passed by the browsers to the Mercure hub if the ``withCredentials`` attribute
378-
of the ``EventSource`` class is set to ``true``. Then, the Hub will verify the
438+
of the ``EventSource`` class is set to ``true``. Then, the Hub verifies the
379439
validity of the provided JWT, and extract the topic selectors from it.
380440

381441
.. code-block:: twig
@@ -572,9 +632,9 @@ its Mercure support.
572632
Testing
573633
--------
574634

575-
During unit testing there is no need to send updates to Mercure.
635+
During unit testing it's usually not needed to send updates to Mercure.
576636

577-
You can instead make use of the `MockHub`::
637+
You can instead make use of the `MockHub` class::
578638

579639
// tests/FunctionalTest.php
580640
namespace App\Tests\Unit\Controller;
@@ -601,10 +661,10 @@ You can instead make use of the `MockHub`::
601661
}
602662
}
603663

604-
During functional testing you can instead decorate the Hub::
664+
During functional testing you can instead create a stub of the Hub::
605665

606-
// tests/Functional/Fixtures/HubStub.php
607-
namespace App\Tests\Functional\Fixtures;
666+
// tests/Functional/Stub/HubStub.php
667+
namespace App\Tests\Functional\Stub;
608668

609669
use Symfony\Component\Mercure\HubInterface;
610670
use Symfony\Component\Mercure\Update;
@@ -619,14 +679,14 @@ During functional testing you can instead decorate the Hub::
619679
// implement rest of HubInterface methods here
620680
}
621681

622-
HubStub decorates the default hub service so no updates are actually
623-
sent. Here is the HubStub implementation:
682+
Use ``HubStub`` to replace the default hub service so no updates are actually
683+
sent:
624684

625685
.. code-block:: yaml
626686
627687
# config/services_test.yaml
628-
App\Tests\Functional\Fixtures\HubStub:
629-
decorates: mercure.hub.default
688+
mercure.hub.default:
689+
class: App\Tests\Functional\Stub\HubStub
630690
631691
.. tip::
632692

@@ -711,6 +771,7 @@ Going further
711771
.. _`Symfony Docker`: https://github.com/dunglas/symfony-docker/
712772
.. _`API Platform distribution`: https://api-platform.com/docs/distribution/
713773
.. _`JSON Web Token`: https://tools.ietf.org/html/rfc7519
774+
.. _`example JWT`: https://jwt.io/#debugger-io?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXJjdXJlIjp7InB1Ymxpc2giOlsiKiJdfX0.iHLdpAEjX4BqCsHJEegxRmO-Y6sMxXwNATrQyRNt3GY
714775
.. _`IRI`: https://tools.ietf.org/html/rfc3987
715776
.. _`practical UI`: https://twitter.com/ChromeDevTools/status/562324683194785792
716777
.. _`the dedicated API Platform documentation`: https://api-platform.com/docs/core/mercure/

0 commit comments

Comments
 (0)