Open mirosval opened 1 month ago
Hi, thank you for opening the issue! I can see this within the scope of bon
. I understand you'd like some short syntax for validating the inputs and collecting a Vec
of errors. This requires some design for the attributes interface for such a feature. I've seen some other crates that can do validation and your PoC will also be a good reference for this feature. It'll require some work, but we can try to get there, although it won't be an immediate priority for bon
.
Right now, with the current state of bon
it's possible to do validation, but it requires writing a bit more code by using #[builder]
on the type's new()
method. It allows you to define any custom logic that you'd like inside of the new()
method. The builder will use your implementation in the build()
method:
use anyhow::{Context, Error};
use bon::bon;
use uuid::Uuid;
struct User {
name: String,
id: Uuid,
group_id: Uuid,
}
#[bon]
impl User {
#[builder]
fn new(name: String, id: &str, group_id: &str) -> Result<Self, Vec<Error>> {
let mut errors = vec![];
if name.contains("@#!$") {
errors.push(anyhow::anyhow!("Name contains invalid characters: {name}"));
}
let id = Uuid::parse_str(id)
.with_context(|| format!("Invalid UUID: {id}"))
.map_err(|err| errors.push(err));
let group_id = Uuid::parse_str(group_id)
.with_context(|| format!("Invalid UUID: {group_id}"))
.map_err(|err| errors.push(err));
if !errors.is_empty() {
return Err(errors);
}
Ok(Self {
name,
// Unwraps are meh.. but not critical. `errors.is_empty()` check ensures no panics here
id: id.unwrap(),
group_id: group_id.unwrap(),
})
}
}
let result = User::builder()
.name("username")
.id("a1da0850-03dc-4f53-8e54-e609b28d17e8")
.group_id("fbb1efc2-bd9b-425f-a97d-b7ffc6430a1b")
.build();
if let Err(errors) = result {
// handle errors
}
Did you consider this possibility with bon
?
This would be a great example to have in the documentation. I was looking for exactly the kind of thing you're showing here where the builder can succeed or fail to build, and couldn't find it, and then luckily saw it here in this issue.
Makes sense, I'll add it to the docs together with some other common patterns with the coming release.
I added an example to the docs at the "Fallible builders" page. There are some other patterns described in the "Patterns" section. I recommend you to check them out.
See the 2.0 release blog post for details.
What are possible options of validating inputs regarding ability to reference already set fields?
What are possible options of validating inputs regarding ability to reference already set fields?
I'm not sure I understand the full context of this question. Currently bon
provides a way to generate a builder from a fallible method where all the fields are already set and available.
I refer to this text
If you have a use case for some convenience attributes to do automatic validations using the #[builder] macro with the struct syntax, then add a 👍 reaction to this Github issue.
If to introduce convenience attributes to do automatic validations
, there is problem if need to cross validate fields, so one field validation depends on how other field validated.
Hello and thank you for writing this lib!
I'm wondering if extending this lib with validation would be in scope. What I'm imagining is an interface where I can specify input validators (e.g.
string -> uuid
). The builder would then run them all and collect the errors. The type of the build method would befn build() -> Result<T, Vec<E>>
or something like this.It is a common scenario in a lot of software to write types that have some guaranteed invariants, but are built from some basic wire types. Validating all of the fields manually is a lot of boilerplate. I've attempted to do a PoC of this in my crate called valibuk, but I don't have the capacity to properly maintain an OSS project.
A note for the community from the maintainers
Please vote on this issue by adding a 👍 reaction to help the maintainers with prioritizing it. You may add a comment describing your real use case related to this issue for us to better understand the problem domain.