Differences in Layout of "Persistent Events" and "API events"

Hi all!

I am wondering about how to layout persistent-events (domain) and public events (api).

Currently i’m witnessing that i often design them with the same content and this just does not feel right.

Are there any “guidelines”/“recommendations”/“best practices” about the layout of those ?

Sorry for this rather “broad-question”.


1 Like

Hi Michael,

This is pretty much up to you. The reason for having two models is to protect your internal format. You want to be free to change the private representation (domain events) without affecting any external consumer of your events (public events).

If the only consumer of your public events is another application that is developed alongside with the one originating the events, and the representation is exactly the same, it’s natural that you perceive it as overkill. In that case, you may reconsider this approach and take the risk of removing this anti-corruption layer.

Hi Renato,

thanks for the quick response. Somehow i knew that Lightbend would response exactly this :slight_smile:

Nevertheless i think that for ES-Beginners it would be nice to have at least some best practices / production grade examples.

  • How do you weight performance issues? (e.g. small domain events might require querying the persistent-entity or read-side for additional data when transforming to an API event whereas a big domain event is costly in disk space space & memory consumption)
  • Event Granularity: This is a similar topic where there are many many ways to do things, most of them with pros and cons with many issues to consider. (see https://stackoverflow.com/questions/23833068/how-granular-should-a-domain-event-be )
  • Do you layout the API events in a way that you can convert them fast from the persistent events? Do you make a “generic” api-interface, mostly NOT considering consumers or do you layout them “exactly” for the consumers? Do you create multiple topics? In which cases is this an advantage?

I know that this is mostly up to the specific use case and a generic response is difficult.

If i encounter some rules of thumb i will try to post them here if I think i consider them generic.


Hi Michael,

The general rule for event design is that it should contain information that makes sense for the business and it should contain the delta of what was changed. I have seen systems that published the whole aggregate state in the event because people were just lazy. If you do that, you may have a concern with disk and the size of payloads in the wire (when propagating to Kafka, for instance).

You should certainly not query the entity or the read-side view when passing around an event. What you will fetch on both sides may be far ahead or far behind the event you are handling.

I think that the link you posted to SO has some good tips and insights. I don’t think I can add more to what was already discussed there.

On the subject of having different API interfaces. Well, again, that’s very application specific. There is no hard-coded rule for that. If you have a consumer that only need a very small subset of the data being published, you may want to have a dedicated topic for it. For example, you may have ServiceA consuming User information from another system and at the same time, ServiceB that is only interested in “seeing” UserCreated and are not interested in any information about that new user. Only that the system has a new user. In that case, it makes sense to have two topics.



Hi Renato,

thanks for your response - this helps me :slight_smile:


Hi Michael - I asked myself the same question as you.

An example that helped “gel” the difference for me was when thinking about a Card playing program (e.g. Poker or Cribbage).

A persistence event must have enough information to recreate the domain state when replayed, whereas the api event is related to the client(s).

So, back to the card game, when a 'Deal" command is given, the persistence event(s) records all the cards dealt to all the players. So your persistence event(s) may be CardsDealt(“player1”, setOfCards1), CardsDealt"player2", setOfCards2) (or CardsDealt(mapOf(player -> Seq[Card])) )

However you probably wouldn’t want player2 to know about player1’s cards and vice-versa. So player1 would receive CardsDealt(“player1”, cards) and CardsDealt(“player2”) API events, whereas player2 would receive CardsDealt(“player1”) and CardsDealt(“player2”, cards) API events.

Just because they have the same name (CardsDealt) doesn’t mean to say the events have the same meaning, or purpose. You can see from the above example(s) that the attributes needed for “CardsDealt” are different for persisted information, that those events raised via an API…

Hope that also helps when thinking about the differences.

1 Like