0

I am going back and forth on an aspect of our FluentValidation and MediatR pipeline behavior implementation. We receive requests which, in a Mediator pattern, are mapped to command or query objects, which are, in turn, validated before being presented to the service layer/business logic. I can mostly validate everything discretely, only accessing an injected configuration object containing reference values/lookup lists. However, I have to call out to a repository for some values to get customer-specific information about "grandfathered" values that may alter the validation logic. Thinking I should not "pollute" the validations with external calls, I implemented that check in the service layer outside our validation pipeline (a MediatR Pipeline Behavior).

However, in researching the issue, I see Q&A where people deem making such external calls from a validator acceptable as long as they are constrained and do not move too much domain logic into the validator. My call to get the grandfathered value is done via a MediatR query, so I would only need to inject IMediator to dispatch the query. Thus, the validator would not be tightly coupled to a repository.

I like the idea of keeping all validations within the FluentValidation framework, and the automatic application of validation rules in the MediatR pipeline is an excellent approach. Still, I cannot decide if moving the MediatR query to access external data into the validations executed by the pipeline behavior crosses a line we do not want to cross.

On one hand, including the data lookup more fully encapsulates the validation logic, while on the other, it introduces the possibility of non-validation-related errors (time-outs, etc.) and behavior in the validation pipeline.

I will appreciate perspectives, pro and con, on this quandary.

2
  • 1
    Please edit the question to limit it to a specific problem with enough detail to identify an adequate answer.
    – Community Bot
    Commented Nov 18, 2023 at 17:14
  • 1
    it seems like you already know the pros and cons, what breaks if you just trust the client validation and error if it wasn't good enough?
    – Ewan
    Commented Nov 18, 2023 at 22:50

1 Answer 1

2

I should not "pollute" the validations with external calls

So there's a bit of nuance here.

In general, logic that does not require external calls is preferable, when it is freely available as an approach. For a list of why, look up what the benefits of pure functions are, you'll find plenty.

However, such benefits get lost (and can even become counterproductive) if you try to dogmatically enforce this approach to scenarios where it's not freely available; by which I mean that you start incurring a technical cost, whether it be related to readability, complexity or maintainability.

I have to call out to a repository for some values to get customer-specific information about "grandfathered" values that may alter the validation logic

If your business requirements require you to write your validation in a way that it looks up the current state of some data, because that's how the application should behave according to the requirements, then the necessity of looking up that data is more important than trying to have a pure validation method. This is the part where this approach is clearly not freely available.

My call to get the grandfathered value is done via a MediatR query, so I would only need to inject IMediator to dispatch the query. Thus, the validator would not be tightly coupled to a repository.

I've wanted to daisy-chain Mediatr requests. I get why you want to do this. Instinctively, it feels like a clean approach to me. However, the overall feedback I've received both online and offline suggests to not do this. Using the mediator pattern to decouple the consumer from the implementation is good, but repeatedly doing so yields diminished returns and makes it harder to follow the flow of your implementation.

The handler of a Mediatr request gets to access a repository, right? If so, then why wouldn't the validator, which is just an intermediary handler if you think about it, get access to the same thing? Any justification for giving the "actual" handler access to the repo would also work in favor of the validator getting the same kind of access.

If your handlers don't access the repo, and instead they re-queue another Mediatr request, then that's an intentional design decision on your end. I'm not going to exclude that as a viable approach.

The end conclusion here is that I would allow your validators to access the persistence layer in the same way that your "real" handlers get to access the data, because the reason for doing so is the same.

I like the idea of keeping all validations within the FluentValidation framework, and the automatic application of validation rules in the MediatR pipeline is an excellent approach. Still, I cannot decide if moving the MediatR query to access external data into the validations executed by the pipeline behavior crosses a line we do not want to cross.

Part of the draw of FluentValidation is that it enables you to write custom validation logic without any real constraints. The ability to access persisted data (when the validation logic calls for it), to me, is making use of the power of FluentValidation, as opposed to crossing a line that should not be crossed.

That's not to say some lines of reasonability don't exist, but this isn't one of them.

It introduces the possibility of non-validation-related errors (time-outs, etc.) and behavior in the validation pipeline

If the data needed for your validation is not available, for whatever technical reason, should you then deny the current request because it cannot be confirmed to be valid, or you should provisionally accept the request?

Usually, it's the former. There are cases where it's the latter (if your end user is a consumer who you don't want to turn away, and you're not incurring a lot of risk by allowing the unvalidated request).

However, in either case the validator can be written to account for the intended behavior, either returning a success or a failure based on the appropriate response.

If your concern is a more general "but my developers keep forgetting/refusing to handle exceptions whenever they call a repository", that's a problem that validation logic design is not going to help you solve.

1
  • Thank you for your well-reasoned and thought provoking response. It is precisely that kind of assistance in clarifying my perspectives that I was hoping to get here.
    – BJ Safdie
    Commented Nov 21, 2023 at 0:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.