Part I - Add A Building

We're going to add the first action to our buildings application. In a CQRS system, such as Event Engine, operations and processes are triggered by messages. Those messages can have three different types and define the API of the application. In the first part of the tutorial we learn the first message type: command.

API

The Event Engine skeleton includes an API folder (src/Domain/Api) that contains a predefined set of EventEngineDescription classes. We will look at these descriptions step by step and start with src/Domain/Api/Command.php:

Throughout the tutorial we'll use the default namespace of the skeleton MyService. If you use the skeleton for a project, you can replace it with your own.

<?php

declare(strict_types=1);

namespace MyService\Domain\Api;

use EventEngine\EventEngine;
use EventEngine\EventEngineDescription;

class Command implements EventEngineDescription
{
    /**
     * Define command names using constants
     *
     * @example
     *
     * const REGISTER_USER = 'RegisterUser';
     */


    /**
     * @param EventEngine $eventEngine
     */
    public static function describe(EventEngine $eventEngine): void
    {
        //Describe commands of the service and corresponding payload schema (used for input validation)
    }
}

The Command description is used to group all commands of our application into one file and add semantic meaning to our code. Replace the comment with a real constant const ADD_BUILDING = 'AddBuilding'; and register the command in the describe method.

<?php

declare(strict_types=1);

namespace MyService\Domain\Api;

use EventEngine\EventEngine;
use EventEngine\EventEngineDescription;
use EventEngine\JsonSchema\JsonSchema;

class Command implements EventEngineDescription
{
    const ADD_BUILDING = 'AddBuilding';

    /**
     * @param EventEngine $eventEngine
     */
    public static function describe(EventEngine $eventEngine): void
    {
        $eventEngine->registerCommand(
            Command::ADD_BUILDING,
            JsonSchema::object(
                [
                    'buildingId' => JsonSchema::uuid(),
                    'name' => JsonSchema::string(['minLength' => 2])
                ]
            )
        );
    }
}

Event Engine supports JSON Schema to describe messages. The advantage of JSON schema is that we can configure validation rules for our messages. Whenever Event Engine receives a message (command, event or query) it uses the defined JSON Schema for that message to validate the input. We configure it once and Event Engine takes care of the rest.

Descriptions

Event Engine Descriptions are very important. They are called at "compile time" and used to configure Event Engine. Descriptions can be cached to speed up bootstrapping. Find more information in the API docs @TODO: link docs.

Cockpit Integration

Switch to the Cockpit UI and reload the schema (press refresh button in top menu). Cockpit should show a new command called AddBuilding in the commands section.

Click on "commands" in the left sidebar and then on "Not Categorized" to see the command. Send the AddBuilding command with this payload:

{
  "buildingId": "9ee8d8a8-3bd3-4425-acee-f6f08b8633bb",
  "name": "Acme Headquarters"
}

Response:

{
  "exception": {
    "message": "No routing information found for command AddBuilding",
    "details": "..."
  }
}

Our command cannot be handled because a command handler is missing. In Event Engine commands can be routed directly to Aggregates. In part II you'll learn more about pure aggregates.

Sum up: Event Engine Descriptions allow you to easily describe the API of your application using messages. The messages get a unique name and payload is described with JSON Schema which allow us to add validation rules. The messages and their schema can be used by Event Engine Cockpit to interact with the backend service.

Fork me on GitHub