example for remote queryGateway without shared api lib?

Hi

I have a queryHandler

@QueryHandler
public Optional findById(FindById query)

on my projection. I use axonServer and jackson/json serialization.

Is it possible to query this from a service connected to the axon server without sharing the FindById/Foo classes in a shared library?
This would allow a more “rest”-like experience …

Thanks
Jan

Would it be possible for you to write a rest Ressource and delegate the queries to the query gateway?
This works pretty well.

Or did you mean that it would be interesting to get something like that without writing all that delegating code?

The question is more general: It looks to me that I need a shared query model lib to work with the queryGateway/Bus … which leads to stronger coupling of my services and forces me to be very careful about read model changes.

Using Rest on top of it is possible, but requires me to configure where the endpoint is … while the axonServer/queryGateway would allow location transparency/automatic discovery.
Plus advanced query features like scatter/gather and subscription won’t work with Rest (out of the box).

I think I heard Allard talk about “the old” and “the new” query API … but I did not figure this out so far … although I use json without fqn for serialization …

Hi Jan,

This is a general topic, I agree.

Queries represents the messaging API of the Query side application/component.
By sharing this API within lib/jar with other consumers/applications you will converge to conformist relationship, making independent deployment and release cycles of this applications (consumer and provider of API) hard.

If you would consider sharing Schema of this API (JSON schema in your case, and not JAR/lib) you would make this relationship more flexible (customer-suplier), as you can introduce changes in a backward/forward compatible way. In this case you should introduce Consumer Driven Contract Testing to check if you are breaking your consumers (Pact, Spring Cloud Contracts). By my opinion this is the right way to go, and I understand that this is something people avoid from time to time :wink:

These are good points for an interesting topic. There are some aspects to look at:

Technical questions:
Is it possible to (re)use axonserver buildin features e.g. for service discovery,..? Is it possible to use contracts like json schema or open api yaml to describe the message structures for better decoupling?

Domain questions:
Would the shared lib change often and for different reasons? Does the projection belong to the same bounded context e.g. developed by the same team?

For communication beyond bounded contexts i would go the hard way and define distinct purpose-committed interfaces/apis.
Even if you decouple as much as possible technically, versioning would get harder and harder without a common language.

Stable objects like maybe an OrderID or an IBAN might never change and could be put inside a shared lib.
This lib is then not made to change and should be very distinct and small.

A ProductDescription might be extended all the time. A projection might only be interested in the name and the price. Those fields might be considered "stable" again. These are the domain considerations beyond the technical way to communicate.

I have'nt found a silver bullet technology that solves these design problems out of the box yet. :slight_smile:

It is possible to define and document a schema of your messages (commands, events, queries). You can check https://docs.pact.io/ or https://spring.io/projects/spring-cloud-contract
I believe that you should reflect the relationship of your Bounded Contexts in the source code by implementing tests for this contracts. In addition to controlling contracts, you will have information who is consuming your API and how. This can form a baseline for introduce versioning of your API.

Axon location transparency enables you to deploy components (command side, query side, adapters/REST/WebSockets…) from your Bounded Context independently as well. The same concept of contract testing could be applied here, but I agree that this contracts are within the scope one team (one bounded context) and more pragmatic approach could be taken. Still, I think it worth the effort :wink:

https://axoniq.io/blog-overview/bounded-contexts-with-axon

If you are sharing the API (commands, events, queries) as libs/jars, make sure you have flat libs per service/bounded context: service-command1-api.jar, service-command2-api.jar, service-query1-api.jar… without common-api.jar please. Having a common API lib would make your language dirty, universal, and hard to decouple latter. You would be surprised how IBAN can have a different meaning (or usage) in different Bounded contexts. I know that this sounds enthusiastic, but I believe that we should converge to this in the future if we want to apply microservices architecture style. There is no silver bullet.

To go back to original question: example for remote queryGateway without shared api lib
I have not found any open source example of this yet. You can do this easily by simply copying the Queries (Java classes, full package name should match) from your Query application (producer of the queries) to your Adapter/Web/Client application (consumer of the queries). This will enable correct serialization/deserialization. Then you should invest your time in trying to implement PACT contract test for this so you can control the contract changes, and potentially share with the community…

Best,
Ivan