-
Notifications
You must be signed in to change notification settings - Fork 0
Document ConstraintViolation.field_path
field
#174
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
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #174 +/- ##
=========================================
Coverage 33.55% 33.55%
Complexity 349 349
=========================================
Files 142 142
Lines 2834 2834
Branches 234 234
=========================================
Hits 951 951
Misses 1814 1814
Partials 69 69 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yevhenii-nadtochii please see my comments.
|
||
// The field path. | ||
// | ||
// This field is populated when this violation is nested in another constraint violation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please rephrase this sentence. There are a couple of problems here:
- "... this violation" — this is not a violation, this is a validation error;
- let's describe this case: "violation is nested in another violation" — so that it is clear to readers not familiar with our internals; right now there is a gap between the fact "validation failed" and the phrase you've used.
// also fully validated according to its own constraints. If an invalid `Email` instance | ||
// is passed to `Student`, two constraint violations will be created: | ||
// | ||
// 1. The parental violation, which has `field_name` set to `email`. The error message |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say "root" instead of "parental".
// | ||
// 1. The parental violation, which has `field_name` set to `email`. The error message | ||
// indicates an invalid field, but without any specifics. | ||
// 2. The nested violation which has `field_path` set to `email.value`. The error message |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is here again. It's not easy to grasp what "nesting" means.
In this particular scenario will there be two items in repeated ConstraintViolation violation = 5;
, or just one? If there are two (like written here), it makes it even more difficult to understand "nesting" as a term.
// | ||
// The nested violation will be in `violation` list of the parental one. | ||
// | ||
base.FieldPath field_path = 3; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One more question here is why we cannot go with just this field. There may be a FieldPath
with a single "path element" in it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, provided comments from @armiol are addressed.
# Conflicts: # dependencies.md
ConstraintViolation
contain both field_path
and field_name
ConstraintViolation.field_path
field
@armiol @alexander-yevsyukov PTAL As discussed, the field has been restored and is better documented now. Also, I have left my latest thoughts on this in PR description. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
This PR updates docs to
ConstraintViolation.field_path
field.Initially, we wanted to alter this field somehow because it stands out a bit in
ConstraintViolation
, but we didn't come up with a much better solution.We have considered the following alternatives:
NestedConstraintViolation
message for(validate)
errors.one_of
:field_path
orfield_name
.parent_path
andfield_name
.Conceptually, all three options do the same: introduce a kind of "split/branching". We decided to avoid this split.
I will also leave my latest thoughts on this.
The other side of validation API (
options.proto
) still operates with${field.name}
placeholders. Many default error messages begin withThe ${parent.type}.${field.name} field must ...
. Probably, they should also be updated to usefield.path
. Or we are explicitly OK with this inconsistency. When we apply an option, we say about the field name, but when the option throws, it is talking about the field path.To me, it looks like that the desire of
(validate)
to passfield.path
and lack of our (at least, mine) desire to modifyConstraintViolation
to please the necessity of a specific option already met somehow in the recent changes tooptions.proto
.Now, options declare a set of placeholders that a user can use in error messages. We didn't extend
ConstraintViolation
to allow(distinct)
option passfield.duplicates
to the thrown error. I suggest treatingfield.path
as a part of option-specific metadata, which makes sense only within this option.Otherwise, it remains either a bit inconsistent (not much really, but it is as for now) or all options become nesting-aware, which is suggested by the first paragraph.
As a possible extension of an idea from the paragraph above, placeholder values may play the role of option-specific metadata passed to the violation error. We are going to pass all placeholder values, no matter whether they are used in the template. So, conceptually, it seems to me more than just template values.
The basic values of placeholders are the same with the values of
ConstraintViolation
fields. For example, see how(set_once)
tests placeholders and other fields ofConstraintViolation
:field.name
,parent.type
andfield.value
are actually checked twice because they are passed twice. The only difference is thatConstraintViolation.field_value
isAny
, but in placeholders, everything isString
.Whether to keep placeholders within the
TemplateString
or move up toConstraintViolation
– not clear, I have not given a deep thought for it. The main suggestion is to treat them more like option-specific metadata (key-value pairs), which can be used as placeholders just by the way, not because this is their only aim of existence.Indeed, through these placeholders, options pass important information for
ConstraintViolation
in general, not only for the template string. I would suggest that inViolationText
(which prepares an exception message), it'd be helpful to always print all passed placeholders, no matter whether the template uses them or not. The library can add a new, useful placeholder, and a user may forget to update the template.... When they are more like metadata, they are always printed along with the formatted message.(validate)
provides its own placeholders and its own error message. We can passfield.path
as placeholder/metadata value. And, for example,nested.error
with the template from the original error. All placeholder values fromnested
will be copied as well.Though, we have a split, in which some options are hard messages, and some use a pair of
boolean option + auxilary hard message to pass the template
. To ease things and have consistent API, I suggest migrating them all to hard messages.