From abd7c931a199bcc1674348c0eda719c7bfb8919e Mon Sep 17 00:00:00 2001 From: Logan Wright Date: Tue, 2 Aug 2016 15:55:18 -0400 Subject: [PATCH 1/3] validation --- couscous.yml | 3 ++ guide/validation.md | 106 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 guide/validation.md diff --git a/couscous.yml b/couscous.yml index e8c82b7f..03db9a55 100644 --- a/couscous.yml +++ b/couscous.yml @@ -47,3 +47,6 @@ menu: guide-config: text: Config relativeUrl: guide/config.html + guide-validation: + text: Validation + relativeUrl: guide/validation.html diff --git a/guide/validation.md b/guide/validation.md new file mode 100644 index 00000000..b266c204 --- /dev/null +++ b/guide/validation.md @@ -0,0 +1,106 @@ +--- +currentMenu: guide-validation +--- + +# Validation + +Vapor provides a few different ways to validate data coming into your application. Let's start by looking at the most common. + +## Common Usage + +Several useful convenience validators are included by default. You can use these to validate data coming into your application, or combine them and create your own. + +Let's look at the most common way to validate data. + +```Swift +class Employee { + var email: Valid + var name: Valid + + init(request: Request) throws { + name = try request.data["name"].validated() + email = try request.data["email"].validated() + } +} +``` + +Here we have a typical Employee model with an `email` and `name` property. By declaring both of these properties as `Valid<>`, you are ensuring that these properties can only ever contain valid data. The Swift type checking system will prevent anything that does not pass validation from being stored. + +To store something in a `Valid<>` property, you must use the `.validated()` method. This is available for any data returned by `request.data`. + +`Email` is a real `validator` included with Vapor, but `Name` is not. Let's take a look at how you can create a Validator. + +```Swift +Valid +Valid +Valid> +Valid> +Valid> +Valid> +Valid> +``` + +## Validators vs. ValidationSuites + +Validators, like Count or Contains can have multiple configurations. For example: + +```Swift +let name: Valid> = try "Vapor".validated(by: Count.max(5)) +``` + +Here we are validating that the `String` is at most 5 characters long. The type of `Valid` tells us that the string has been validated to be a certain count, but it does not tell us exactly what that count was. The string could have been validated to be less than three characters or more than one million. + +Because of this, `Validators` themselves are not as type safe as some applications might desire. ValidationSuites fix this. They combine multiple `Validators` and/or `ValidationSuites` together to represent exactly what type of data should be considered valid + +## Custom Validator + +Here is how to create a custom `ValidationSuite`. + +```Swift +class Name: ValidationSuite { + static func validate(input value: String) throws { + let evaluation = OnlyAlphanumeric.self + && Count.min(5) + && Count.max(20) + + try evaluation.validate(input: value) + } +} +``` + +You only have to implement one method. In this method, use any other validators or logic to create your custom validator. Here we are defining a Name as only accepting alphanumeric Strings that are between 5 and 20 characters. + +Now we can be sure that anything of type Valid follows these rules. + +## Combining Validators + +In the `Name` validator, you can see that `&&` is being used to combine validators. You can use `&&` as well as `||` to combine any validator as you would boolean values with an `if` statement. + +You can also use `!` to invert the validator. + +```Swift +let symbols = input.validated(by: !OnlyAlphanumeric.self) +``` + +## Testing Validity + +While `validated() throw` is the most common method for validating, there are two others. + +```Swift +let passed = input.passes(Count.min(5)) +let valid = try input.tested(Count.min(5)) +``` + +`passes()` returns a boolean indicating whether or not the test passed. `tested()` will throw if the validation does not pass. But unlike `validated()` which returns a `Valid<>` type, `tested()` returns the original type of the item it was called on. + +## Validation Failures + +Vapor will automatically catch validation failures in the `ValidationMiddleware`. But you can catch them on your own, or customize responses for certain types of failures. + +```Swift +do { + //validation here +} catch let error as ValidationErrorProtocol { + print(error.message) +} +``` From c05546e41ec398e011c045ede0cf8fb6790c4b80 Mon Sep 17 00:00:00 2001 From: Logan Wright Date: Tue, 2 Aug 2016 15:59:03 -0400 Subject: [PATCH 2/3] lowercase swift on code blocks --- guide/validation.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/guide/validation.md b/guide/validation.md index b266c204..e82464e5 100644 --- a/guide/validation.md +++ b/guide/validation.md @@ -12,7 +12,7 @@ Several useful convenience validators are included by default. You can use these Let's look at the most common way to validate data. -```Swift +```swift class Employee { var email: Valid var name: Valid @@ -30,7 +30,7 @@ To store something in a `Valid<>` property, you must use the `.validated()` meth `Email` is a real `validator` included with Vapor, but `Name` is not. Let's take a look at how you can create a Validator. -```Swift +```swift Valid Valid Valid> @@ -44,7 +44,7 @@ Valid> Validators, like Count or Contains can have multiple configurations. For example: -```Swift +```swift let name: Valid> = try "Vapor".validated(by: Count.max(5)) ``` @@ -56,7 +56,7 @@ Because of this, `Validators` themselves are not as type safe as some applicatio Here is how to create a custom `ValidationSuite`. -```Swift +```swift class Name: ValidationSuite { static func validate(input value: String) throws { let evaluation = OnlyAlphanumeric.self @@ -78,7 +78,7 @@ In the `Name` validator, you can see that `&&` is being used to combine validato You can also use `!` to invert the validator. -```Swift +```swift let symbols = input.validated(by: !OnlyAlphanumeric.self) ``` @@ -86,7 +86,7 @@ let symbols = input.validated(by: !OnlyAlphanumeric.self) While `validated() throw` is the most common method for validating, there are two others. -```Swift +```swift let passed = input.passes(Count.min(5)) let valid = try input.tested(Count.min(5)) ``` @@ -97,7 +97,7 @@ let valid = try input.tested(Count.min(5)) Vapor will automatically catch validation failures in the `ValidationMiddleware`. But you can catch them on your own, or customize responses for certain types of failures. -```Swift +```swift do { //validation here } catch let error as ValidationErrorProtocol { From 7b4cd4f5b77d73cef82f182cebe3628074f8276d Mon Sep 17 00:00:00 2001 From: Logan Wright Date: Tue, 2 Aug 2016 16:02:46 -0400 Subject: [PATCH 3/3] comments --- guide/config.md | 14 +++++++------- guide/validation.md | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/guide/config.md b/guide/config.md index 236c55cf..63d59169 100644 --- a/guide/config.md +++ b/guide/config.md @@ -27,7 +27,7 @@ And an example of how this might look: } ``` -What that's saying, is that our application should start a single server named 'default' serving port `8080` on host `0.0.0.0`. This represents the following url: `http://localhost:8080`. +What that's saying, is that our application should start a single server named 'http' serving port `8080` on host `0.0.0.0`. This represents the following url: `http://localhost:8080`. ### Custom Keys @@ -45,7 +45,7 @@ Let's add a custom key to the `servers.json` file: This can be accessed from your application's config using the following. -```Swift +```swift let customValue = app.config["server", "http", "custom-key"].string ``` @@ -70,13 +70,13 @@ You can access your config directory with the following syntax. `app.config[<#fi We can access this file by making sure the first argument in our subscript is keys. To get the first name in our list: -```Swift +```swift let name = app.config["keys", "test-names", 0].string ``` Or our mongo url: -```Swift +```swift let mongoUrl = app.config["keys", "mongo", "url"].string ``` @@ -145,7 +145,7 @@ Let's start with the following JSON files. Please notice that servers.json, and production/servers.json both declare the same keys. host, and port. In our application, we'll call: -```Swift +```swift // will load 0.0.0.0 or 127.0.0.1 based on above config let host = app.config["servers", "http", "host"].string // will load 9000, or environment variable port. @@ -166,7 +166,7 @@ Arguments set through the command line can be accessed through config's cli file would be accessible within your application by using the following: -```Swift +```swift let mongoPassword = app.config["cli", "mongo-password"].string ``` @@ -180,6 +180,6 @@ If you want command line arguments set to a file besides "cli", you can use this would be accessible within your application by using the following: -```Swift +```swift let analyticsKey = app.config["keys", "analytics"].string ``` diff --git a/guide/validation.md b/guide/validation.md index e82464e5..e65f09e9 100644 --- a/guide/validation.md +++ b/guide/validation.md @@ -42,7 +42,7 @@ Valid> ## Validators vs. ValidationSuites -Validators, like Count or Contains can have multiple configurations. For example: +Validators, like `Count` or `Contains` can have multiple configurations. For example: ```swift let name: Valid> = try "Vapor".validated(by: Count.max(5)) @@ -50,7 +50,7 @@ let name: Valid> = try "Vapor".validated(by: Count.max(5)) Here we are validating that the `String` is at most 5 characters long. The type of `Valid` tells us that the string has been validated to be a certain count, but it does not tell us exactly what that count was. The string could have been validated to be less than three characters or more than one million. -Because of this, `Validators` themselves are not as type safe as some applications might desire. ValidationSuites fix this. They combine multiple `Validators` and/or `ValidationSuites` together to represent exactly what type of data should be considered valid +Because of this, `Validators` themselves are not as type safe as some applications might desire. `ValidationSuites` fix this. They combine multiple `Validators` and/or `ValidationSuites` together to represent exactly what type of data should be considered valid ## Custom Validator