CQRS and eventsourcing with API Platform I

February 2, 2019

Last week I’have started to build a new backend for our groundwater managenment platform INOWAS-DSS. My goal was to use all the great tools which offers API Platform out of the box, combined with CQRS and event sourcing, which we are happy to have ready in production with our React-Web-App.

Happy with my first steps I shouted out into twitter:

I was overwhelmed from the feedback given by so many people.

So, here it comes with the following contents:


  1. Setup API Platform and CLI tools
  2. Setup user management and authentication
  3. Implementing CQRS with symfony messenger
  4. Implementing eventsourcing


  • This is an opinionated prototype of an ES implementation.
  • It’s definitely not perfect.
  • It does not treat every use case.
  • I would like to hear your opinions about it.

The domain

For this tutorial a have choosen library example.
Assuming we have a big library with a lot of books.
Mainly you can find books, but you have also staff there and you have the users which are lending books.

  • Books located in the library can be lend.
  • New books can be aquired.
  • Users can lend this books and bring them back.
  • Books will get sorted out if they are out of date.

Part I: Setup API Platform

Starting on the official website of the API Platform project you can find the Installation section.

I have cloned the repository into the folder api-platform-eventsourcing and checked out the latest stable version:

$ git clone https://github.com/api-platform/api-platform.git api-platform-eventsourcing
$ git tag 
$ git checkout -b part-1 v2.3.6

As explained in the Docs you can start the whole distribution.

$ docker-compose up -d

Make sure you have the docker client running. You can list all running containers with:

$ docker-compose ps
                  Name                                Command               State                                          Ports
api-platform-eventsourcing_admin_1         /bin/sh -c yarn start            Up>3000/tcp
api-platform-eventsourcing_api_1           nginx -g daemon off;             Up>80/tcp
api-platform-eventsourcing_cache-proxy_1   docker-varnish-entrypoint  ...   Up>80/tcp
api-platform-eventsourcing_client_1        /bin/sh -c yarn start            Up>3000/tcp
api-platform-eventsourcing_db_1            docker-entrypoint.sh postgres    Up>5432/tcp
api-platform-eventsourcing_h2-proxy_1      nginx -g daemon off;             Up>443/tcp,>444/tcp, 80/tcp,>8443/tcp,
api-platform-eventsourcing_php_1           docker-entrypoint php-fpm        Up      9000/tcp

Running console/composer commands

To execute symfony console commands you can run now:

$ docker-compose exec php bin/console
WARNING: The CONTAINER_REGISTRY_BASE variable is not set. Defaulting to a blank string.
Symfony 4.2.2 (env: dev, debug: true)

  command [options] [arguments]


To install additional composer packages run:

$ docker-compose exec php composer
WARNING: The CONTAINER_REGISTRY_BASE variable is not set. Defaulting to a blank string.
  / ____/___  ____ ___  ____  ____  ________  _____
 / /   / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/
/ /___/ /_/ / / / / / / /_/ / /_/ (__  )  __/ /
\____/\____/_/ /_/ /_/ .___/\____/____/\___/_/
Composer version 1.8.2 2019-01-29 15:00:53

  command [options] [arguments]


Querying your API

Now you can make your first API call with cURL.

$ curl localhost:8080

For this tutorial I’m using mainly HTTPie ❤ for HTTP-calls from the CLI.

$ http localhost:8080
HTTP/1.1 200 OK
Cache-Control: no-cache, private
Connection: keep-alive
Content-Type: application/ld+json; charset=utf-8
Date: Sat, 02 Feb 2019 17:03:50 GMT
Link: <http://localhost:8080/docs.jsonld>; rel="http://www.w3.org/ns/hydra/core#apiDocumentation"
Server: nginx/1.15.8
Transfer-Encoding: chunked
Vary: Accept
X-Content-Type-Options: nosniff
X-Debug-Token: e3e684
X-Debug-Token-Link: http://localhost:8080/_profiler/e3e684
X-Frame-Options: deny
X-Powered-By: PHP/7.2.14

    "@context": "/contexts/Entrypoint",
    "@id": "/",
    "@type": "Entrypoint",
    "greeting": "/greetings"

The response gives you some useful informations.
You can open the Symfony Profiler in your browser with the link given under X-Debug-Token-Link.

X-Debug-Token-Link: http://localhost:8080/_profiler/e3e684

Symfony profiler

Now we have everything setup and running and can finally start coding.

Click here to get to the next part

comments powered by Disqus