Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question] How do you return values (like created ids) in Commands/from the message bus? #50

Open
ArcticXWolf opened this issue Apr 13, 2022 · 2 comments

Comments

@ArcticXWolf
Copy link

Hey,

first and foremost: thanks for this awesome book, it is the first time I had to plan an architecture for a bigger project and your book has helped me enormously to create maintainable code.

Question

In Chapter 9 you temporarly show how to return values from the handlers to the entrypoint. You mention that this is still ugly, because it mixes resposibilities (of read and write) and refactor everything according to CQRS in Chapter 12.

However during this you loose the ability ("feature") of returning the batchref in the entrypoint (see here in the code).

I agree that reading and writing are separate responsibilities, but sometimes there is a usecase for returning values even for a command and not a query. Examples:

  • Errors and reasons (you can implement this via the exception, you already do this with the invalid_sku)
  • Some object has been created and you need to provide your clientapplication/user with the id of this object from your microservice (e.g. a user can register and you provide a query to query for user_info_by_id, the user needs to somehow get the user_id from the creation command)

Possible Solutions

I've thought about two ways to solve this, but why I would choose which approach is more of a gut feeling. Maybe you can help me by providing feedback of why these are good/bad or if there is even a better/dogmatic way.

Just returning values from the handler (like in the ugly workaround section linked above)

This enables you to just use it like already shown in your book. What I dont like about here is that there is no real "interface"/"annotation" of the return value of messagebus.handle. It completely depends on the handler. Furthermore, how should we deal with a chain of commands and events (as one handler/model can create new events). Do we discard them or do we return a list/dict of all return values?
Also it just "feels wrong" to return Any.

Leverage the events to return values

As the return values will be mostly stuff like "ObjectCreated(id=1)" or similar, we could just use the available events. Just in the messagebus create a separate copy of all events that are added to self.queue and return this list of events. Then the handle-method just returns the list of thrown events. This solves both problems above: we have an "interface" (List[events.Event]) and also we can return stuff from ALL handlers in a handler chain.

The entrypoint just extracts the events/data it is interested in then.

What do you think about this idea? Or am I wrong and we can also solve this with CQRS? Or some other way completely?

@cottet-ju-e3
Copy link

Same as @ArcticXWolf big thanks for the book I bought last year.
I encountered exactly the same issue and choose to return the head of self.queue as the response.
I think there could have a better and secured way.
I hope this could be answered.

@abdulhaq-e
Copy link

Hello @ArcticXWolf and @cottet-ju-e3

While I'm not an expert but the pattern that I've seen to solve this issue is by having the client create the resource identifier. Ideally this identifier would be a GUID. It's definitely mentioned by Udi Dahan here but I think Harry and Bob mentioned it somewhere in the book too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants