vapor / validation Goto Github PK
View Code? Open in Web Editor NEW✅ Extensible data validation library (name, email, etc)
License: MIT License
✅ Extensible data validation library (name, email, etc)
License: MIT License
Current email validator only supports 2-3 character long TLDs.
Currently, ErrorMiddleware
treats validation errors as internalServerError
due to validation errors only conforming to Debuggable
and not to AbortError
.
When Validations.run()
is called, it collects all failures in a ValidationErrors
object, which is then thrown as the final result (unless all validations passed, of course). Unfortunately, ValidationErrors
is fileprivate
, making it impossible to retrieve the array of individual ValidationError
s that occurred. This, in turn, makes it impossible to determine which specific validations passed or failed in calling code save by parsing the human-readable reason
string, hardly the most desirable solution. To make matters worse, Validations<M>.storage
is also fileprivate
, making it impossible to reimplement a custom version of run()
to get around the problem for code where "which key failed validation" matters to the program logic. Consider, for example, the case of a RESTful JSON API which defines different integer response codes for different input errors. Even aside the issue of more than one validation potentially failing (which can be addressed by simply taking the first to fail or by any of several other means), knowing which key paths failed validation is critical to such an API. A trivial fix is to make ValidationErrors
and its errors
property both public
. A more robust solution probably entails a minor API redesign.
Additionally, even if the matter of getting at the list of failures is addressed, the idiomatic form for determining which key path was affected looks like:
if let validationError = error as? ValidationError, try validationError.path == InputModel.decodeProperty(forKey: \.criticalInputValue)?.path {
Or:
catch let validationError as ValidationError where try! validationError.path == InputModel.decodeProperty(forKey: \.criticalInputValue)?.path {
Both of these are rather unwieldy at best. One alternative would be for a ValidationError
to track the Validator
which created it, and for Validations
to maintain the mapping of keypaths to arrays of Validator
s, so a simple comparison of PartialKeyPath<M>
s can be used instead of relying upon the reflection decoder. This feels like an unwieldy solution to an unwieldy problem, but nothing better comes immediately to mind.
Additionally, a variant of .run()
which throws the first validation error instead of gathering all of them might also be useful.
Upon running validation on a model (aka run(on model: M)
function), the validation errors are thrown in form of a private ValidateErrors
struct, which acts as a wrapper around all errors that are being found in the process of validation.
However, the reason
of ValidateErrors is just a composed string of reason
s from each of the validation errors. The problem is that this reason
string is not readable by the end user, as it includes the keypaths of the errors and so on.
In my opinion, there should be a way to specify custom failure message that gets returned by the API, skipping the "debuggable" reason which don't make sense to the end user.
Is it possible to compare two attributes? I have two dates and one of the dates should be before the other. I'm going to do some user-facing validation on the client side but a model validation would be great too.
When a Validatable
object at the bottom of a class hierarchy calls try validate()
in init(from decoder: )
, an infinite recursion happens. This does not happen to base classes, but only to classes which are sub-classes of others. Below is an example:
class LoginCredentials: Decodable {
let email: String
let password: String
}
final class UserInfo: LoginCredentials {
let firstName: Name
private enum CodingKeys: CodingKey {
case firstName
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.firstName = try container.decode(Name.self, forKey: .firstName)
try super.init(from: decoder)
try validate()
}
}
extension UserInfo: Validatable, Reflectable {
static func validations() throws -> Validations<UserInfo> {
var validations = Validations(UserInfo.self)
try validations.add(\.email, .email)
try validations.add(\.password, .count(8...64))
return validations
}
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.