Skip to content

Commit

Permalink
feat(validation.md): added custom validator documentation (#1016)
Browse files Browse the repository at this point in the history
I created a [PR](vapor/vapor#3263) earlier
today, adding in a custom validator called `Custom`. This allows users
to easily create custom validations, it is simpler to use and shorter in
syntax compared to the current [Custom
Validators](https://docs.vapor.codes/basics/validation/#custom-validators).

This PR also resolves [this
issue](#1015)

---------

Co-authored-by: Tim Condon <[email protected]>
  • Loading branch information
WilliamFernsV3 and 0xTim authored Jan 1, 2025
1 parent a0d7615 commit 0946bf8
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 48 deletions.
45 changes: 0 additions & 45 deletions docs/basics/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,51 +136,6 @@ struct MyError: DebuggableError {

`DebuggableError` has several other properties like `possibleCauses` and `suggestedFixes` that you can use to improve the debuggability of your errors. Take a look at the protocol itself for more information.

## Stack Traces

Vapor includes support for viewing stack traces for both normal Swift errors and crashes.

### Swift Backtrace

Vapor uses the [SwiftBacktrace](https://github.com/swift-server/swift-backtrace) library to provide stack traces after a fatal error or assertion on Linux. In order for this to work, your app must include debug symbols during compilation.

```sh
swift build -c release -Xswiftc -g
```

### Error Traces

By default, `Abort` will capture the current stack trace when initialized. Your custom error types can achieve this by conforming to `DebuggableError` and storing `StackTrace.capture()`.

```swift
import Vapor

struct MyError: DebuggableError {
var identifier: String
var reason: String
var stackTrace: StackTrace?

init(
identifier: String,
reason: String,
stackTrace: StackTrace? = .capture()
) {
self.identifier = identifier
self.reason = reason
self.stackTrace = stackTrace
}
}
```

When your application's [log level](logging.md#level) is set to `.debug` or lower, error stack traces will be included in log output.

Stack traces will not be captured when the log level is greater than `.debug`. To override this behavior, set `StackTrace.isCaptureEnabled` manually in `configure`.

```swift
// Always capture stack traces, regardless of log level.
StackTrace.isCaptureEnabled = true
```

## Error Middleware

`ErrorMiddleware` is one of the only two middlewares added to your application by default. This middleware converts Swift errors that have been thrown or returned by your route handlers into HTTP responses. Without this middleware, errors thrown will result in the connection being closed without a response.
Expand Down
51 changes: 48 additions & 3 deletions docs/basics/validation.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Validation

Vapor's Validation API helps you validate incoming request before using the [Content](content.md) API to decode data.
Vapor's Validation API helps you validate the body and query parameters of an incoming request before using the [Content](content.md) API to decode data.

## Introduction

Expand Down Expand Up @@ -219,8 +219,9 @@ Below is a list of the currently supported validators and a brief explanation of
|`.nil`|Value is `null`.|
|`.range(_:)`|Value is within supplied `Range`.|
|`.url`|Contains a valid URL.|
|`.custom(_:, validationClosure: (value) -> Bool)`|Custom, once-off validation.|

Validators can also be combined to build complex validations using operators.
Validators can also be combined to build complex validations using operators. More information on `.custom` validator at [[#Custom Validators]].

|Operator|Position|Description|
|-|-|-|
Expand All @@ -232,7 +233,11 @@ Validators can also be combined to build complex validations using operators.

## Custom Validators

Creating a custom validator for zip codes allows you to extend the functionality of the validation framework. In this section, we'll walk you through the steps to create a custom validator for validating zip codes.
There are two ways to create custom validators.

### Extending Validation API

Extending the Validation API is best suited for cases where you plan on using the custom validator in more than one `Content` object. In this section, we'll walk you through the steps to create a custom validator for validating zip codes.

First create a new type to represent the `ZipCode` validation results. This struct will be responsible for reporting whether a given string is a valid zip code.

Expand Down Expand Up @@ -289,4 +294,44 @@ Now that you've defined the custom `zipCode` validator, you can use it to valida
```swift
validations.add("zipCode", as: String.self, is: .zipCode)
```
### `Custom` Validator

The `Custom` validator is best suited for cases where you want to validate a property in only one `Content` object. This implementation has the following two advantages compared to extending the Validation API:

- Simpler to implement custom validation logic.
- Shorter syntax.

In this section, we'll walk you through the steps to create a custom validator for checking whether an employee is part of our company by looking at the `nameAndSurname` property.

```swift
let allCompanyEmployees: [String] = [
"Everett Erickson",
"Sabrina Manning",
"Seth Gates",
"Melina Hobbs",
"Brendan Wade",
"Evie Richardson",
]

struct Employee: Content {
var nameAndSurname: String
var email: String
var age: Int
var role: String

static func validations(_ validations: inout Validations) {
validations.add(
"nameAndSurname",
as: String.self,
is: .custom("Validates whether employee is part of XYZ company by looking at name and surname.") { nameAndSurname in
for employee in allCompanyEmployees {
if employee == nameAndSurname {
return true
}
}
return false
}
)
}
}
```

0 comments on commit 0946bf8

Please sign in to comment.