This is a highly theoretical question and focuses largely on me not completely grasping design principles behind related data in microservices and responsibility of obtaining related data.
The basic gist of my data could be exampled as follows (each service also hosts data named after the service in a DB which i will hide for simplicity):
I have an API Gateway routing /api/* requests to their proper services and handling authentication. I have a species-service, the species has a GUID PK and a name. I have a zoo-service, the zoo has a GUID PK and a name. I have an animal-service, an animal has a GUID PK, a species FK and a zoo FK and a name.
Following scenarios have to happen:
This is my current implementation (which I think may be flawed):
I have the following two questions:
This decomposition looks like taking a relational DB schema and assigning each table to a different microservice. This decomposition takes all the coupling of a monolith and combines it with all the complexity of microservices, which means that you get very few of the benefits of either.
An alternative decomposition focuses on the functionality: what operations are being exposed and how are they related (and what sort of consistency/independence relations should hold between the operations). If there's a strong consistency requirement between two operations, that's a strong sign that those two operations belong in the same microservice (doing that doesn't guarantee consistency, but not doing that dramatically increases the effort of ensuring consistency without giving the benefits of separate microservices (beyond, perhaps, having the ability to say "we have more microservices than we need!", if that's the sort of thing that gives one satisfaction)).
So assuming we have an "add animal A with species S to zoo Z" operation, the question is then whether we want a guarantee that any subsequent request for all the animals in Z, all the animals of S, or the specific animal A sees the result of that operation. If the answer is yes, then those four operations probably "want" to be in the same microservice and the implementations of those operations are going to be coupled as a consequence. If the answer is no, then it's likely that eventual consistency with some liveness guarantee is acceptable, in which case (barring the presence of some other consistency relationship) put the operations into separate microservices and patterns like CQRS are possible.
If doing CQRS, the service providing the "get all animals in the zoo" operation could then have its own view of what animals there are and their respective species. It then doesn't depend on the animals/species services being available: those being down/unable to talk to this service (which could happen because one service changed something, it should be noted) simply means that the view is out of date. Eventually, communication will be re-established and the operation will return updated data.