Skip to content

[Question] Event Sourcing with Eloquent Resources? #290

@tsterker

Description

@tsterker

Apologies if there is a better way to submit such open-ended questions. In this case, please let me know or simply close the issue.

What I want to do

I want to adopt event sourcing (via verbs) for my application that is using laravel-json-api (the go-to package I don't want to live without).

In essence, it means that there should not be any direct model creation, but I would fire events instead with the relevant request data.

Given that everything would still be backed by Eloquent models, I think the existing implementation is a great start for all read and the main thing that would differ is how I create/update my models.

FYI: I have not yet extensively thought about or researched how well REST/JSON:API and event sourcing go together.
But from a conceptual point of view, I don't see any conflict at this point.

What I'm currently doing

I'm currently simply implementing custom controller actions to hand over the validated data to my events.
I ensure that my events are "committed" to be reflected in the DB and then I simply query and return the eloquent model I expected to be created via the event.

Example:

// routes/api.php
JsonApiRoute::server('v0')
    ->prefix('v0')
    ->resources(function (ResourceRegistrar $server) {
        $server
            ->resource('posts', PostController::class)
            ->only('store', 'index', 'read');
    });
// app/Http/Controllers/Api/V0/PostController.php

// ...

    public function store(Route $route, StoreContract $store)
    {
        $request = ResourceRequest::forResource(
            $resourceType = $route->resourceType()
        );

        $data = $request->validated();

        PostCreated::fire(
            post_id: $postId = snowflake_id(),
            title: $data['title'],
            body: $data['body'],
        );

        Verbs::commit();
        
        return DataResponse::make(Post::find($postId)->sole())
            ->withQueryParameters(ResourceQuery::queryOne($resourceType))
            ->didCreate();
    }

// ...

What I Imagine

I was thinking about if/how I should eventually implement my own "non-eloquent" Resource (?), where I would somehow be mapping schemas to event states. Or maybe I should keep the mapping to Eloquent models, but somehow be able map certain API routes/actions to certain events being fired instead of the mapped eloquent models to be updated directly.

I think I would need to put some more thought into this to understand the different moving parts, but for now I was wondering how I could:

  • Fully replace any create/update logic with custom logic to fire events
  • Still utilize the Eloquent implementation for all API read operations.

I acknowledge that this is a long-winded post. In essence, I would like to

  • Validate that my current approach is idiomatic in regards to this package
  • How I would move forward with my approach to turn it into a custom extension that supports event sourcing more declaratively, if even possible. I imagine that I could reuse most (all?) of the Eloquent related read logic for this and only adjust the create/update parts.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions