Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 14f3623

Browse filesBrowse files
dunglasOskarStark
authored andcommitted
[Mercure] integration with Symfony cli and various improvements
1 parent 052e1ec commit 14f3623
Copy full SHA for 14f3623

File tree

Expand file treeCollapse file tree

1 file changed

+90
-78
lines changed
Filter options
Expand file treeCollapse file tree

1 file changed

+90
-78
lines changed

‎mercure.rst

Copy file name to clipboardExpand all lines: mercure.rst
+90-78Lines changed: 90 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ 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 (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

2829
Mercure comes with an authorization mechanism,
2930
automatic 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

9884
Configuration
@@ -101,18 +87,30 @@ Configuration
10187
The 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

114111
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).
116114
Its payload must contain at least the following structure to be allowed to
117115
publish:
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-
281243
Discovery
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',
@@ -456,7 +418,7 @@ And here is the controller::
456418

457419
class DiscoverController extends AbstractController
458420
{
459-
public function __invoke(Request $request, Discovery $discovery, Authorization $authorization): Response
421+
public function publish(Request $request, Discovery $discovery, Authorization $authorization): Response
460422
{
461423
$discovery->addLink($request);
462424

@@ -601,7 +563,7 @@ During unit testing there is not need to send updates to Mercure.
601563

602564
You can instead make use of the `MockHub`::
603565

604-
// tests/Functional/.php
566+
// tests/FunctionalTest.php
605567
namespace App\Tests\Unit\Controller;
606568

607569
use App\Controller\MessageController;
@@ -653,6 +615,10 @@ sent. Here is the HubStub implementation:
653615
App\Tests\Functional\Fixtures\HubStub:
654616
decorates: mercure.hub.default
655617
618+
.. tip::
619+
620+
Symfony Panther has `a feature to test applications using Mercure`_.
621+
656622
Debugging
657623
---------
658624

@@ -693,6 +659,51 @@ Enable the panel in your configuration, as follows:
693659
694660
.. image:: /_images/mercure/panel.png
695661

662+
Async dispatching
663+
-----------------
664+
665+
.. tip::
666+
667+
Async dispatching is discouraged. Most Mercure hubs already
668+
handle publications asynchronously and using Messenger is
669+
usually not necessary.
670+
671+
Instead of calling the ``Publisher`` service directly, you can also let Symfony
672+
dispatching the updates asynchronously thanks to the provided integration with
673+
the Messenger component.
674+
675+
First, be sure :doc:`to install the Messenger component </messenger>`
676+
and to configure properly a transport (if you don't, the handler will
677+
be called synchronously).
678+
679+
Then, dispatch the Mercure ``Update`` to the Messenger's Message Bus,
680+
it will be handled automatically::
681+
682+
// src/Controller/PublishController.php
683+
namespace App\Controller;
684+
685+
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
686+
use Symfony\Component\HttpFoundation\Response;
687+
use Symfony\Component\Mercure\Update;
688+
use Symfony\Component\Messenger\MessageBusInterface;
689+
690+
class PublishController extends AbstractController
691+
{
692+
public function publish(MessageBusInterface $bus): Response
693+
{
694+
$update = new Update(
695+
'http://example.com/books/1',
696+
json_encode(['status' => 'OutOfStock'])
697+
);
698+
699+
// Sync, or async (Doctrine, RabbitMQ, Kafka...)
700+
$bus->dispatch($update);
701+
702+
return new Response('published!');
703+
}
704+
}
705+
706+
696707
.. _`the Mercure protocol`: https://mercure.rocks/spec
697708
.. _`Server-Sent Events (SSE)`: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events
698709
.. _`a polyfill`: https://github.com/Yaffle/EventSource
@@ -707,3 +718,4 @@ Enable the panel in your configuration, as follows:
707718
.. _`practical UI`: https://twitter.com/ChromeDevTools/status/562324683194785792
708719
.. _`the dedicated API Platform documentation`: https://api-platform.com/docs/core/mercure/
709720
.. _`the online debugger`: https://uri-template-tester.mercure.rocks
721+
.. _`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

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.