Validatie¶
Vapor's Validatie API helpt u inkomende verzoeken te valideren voordat u de Content API gebruikt om gegevens te decoderen.
Introductie¶
Vapor's diepe integratie van Swift's type-veilige Codable
protocol betekent dat je je niet zoveel zorgen hoeft te maken over data validatie in vergelijking met dynamisch getypeerde talen. Er zijn echter nog steeds een paar redenen waarom je zou willen kiezen voor expliciete validatie met behulp van de Validatie API.
Menselijk leesbare fouten¶
Het decoderen van structs met behulp van de Content API zal fouten opleveren als een van de gegevens niet geldig is. Echter, deze foutmeldingen kunnen soms onleesbaar zijn voor mensen. Neem bijvoorbeeld de volgende string-backed enum:
enum Color: String, Codable {
case red, blue, green
}
Als een gebruiker de string "purple"
probeert door te geven aan een eigenschap van het type Color
, krijgt hij een foutmelding zoals in het volgende voorbeeld:
Cannot initialize Color from invalid String value purple for key favoriteColor
Hoewel deze fout technisch correct is en het eindpunt met succes beschermt tegen een ongeldige waarde, zou het beter zijn om de gebruiker te informeren over de fout en welke opties beschikbaar zijn. Door de Validation API te gebruiken, kunt u fouten als de volgende genereren:
favoriteColor is not red, blue, or green
Verder zal Codable
stoppen met het proberen te decoderen van een type zodra de eerste fout wordt gevonden. Dit betekent dat zelfs als er veel ongeldige eigenschappen in het verzoek zijn, de gebruiker alleen de eerste fout zal zien. De validatie API zal alle validatie fouten in een enkel verzoek rapporteren.
Specifieke Validatie¶
Codable
handelt type-validatie goed af, maar soms wil je meer dan dat. Bijvoorbeeld, het valideren van de inhoud van een string of het valideren van de grootte van een integer. De validatie API heeft validators om te helpen bij het valideren van gegevens zoals emails, character sets, integer ranges, en meer.
Validatable¶
Om een verzoek te valideren, moet je een Validations
collectie genereren. Dit wordt meestal gedaan door een bestaand type te conformeren aan Validatable
.
Laten we eens kijken hoe je validatie kunt toevoegen aan dit eenvoudige POST /users
endpoint. Deze handleiding gaat ervan uit dat je al bekend bent met de Content API.
enum Color: String, Codable {
case red, blue, green
}
struct CreateUser: Content {
var name: String
var username: String
var age: Int
var email: String
var favoriteColor: Color?
}
app.post("users") { req -> CreateUser in
let user = try req.content.decode(CreateUser.self)
// Do something with user.
return user
}
Validaties Toevoegen¶
De eerste stap is om het type dat je aan het decoderen bent, in dit geval CreateUser
, te conformeren aan Validatable
. Dit kan gedaan worden in een extensie.
extension CreateUser: Validatable {
static func validations(_ validations: inout Validations) {
// Validations go here.
}
}
De statische methode validations(_:)
zal worden aangeroepen wanneer CreateUser
wordt gevalideerd. Alle validaties die je wilt uitvoeren moeten worden toegevoegd aan de Validations
collectie. Laten we eens kijken naar het toevoegen van een eenvoudige validatie om te eisen dat het e-mailadres van de gebruiker geldig is.
validations.add("email", as: String.self, is: .email)
De eerste parameter is de verwachte sleutel van de waarde, in dit geval "email"
. Deze moet overeenkomen met de naam van de eigenschap op het type dat gevalideerd wordt. De tweede parameter, as
, is het verwachte type, in dit geval String
. Het type komt meestal overeen met het type van de eigenschap, maar niet altijd. Tenslotte kunnen na de derde parameter, is
, nog één of meerdere validaties worden toegevoegd. In dit geval voegen we een enkele validator toe die controleert of de waarde een e-mailadres is.
Valideren van verzoekinhoud¶
Als je je type hebt geconformeerd aan Validatable
, kan de statische validate(content:)
functie worden gebruikt om de request inhoud te valideren. Voeg de volgende regel toe voor req.content.decode(CreateUser.self)
in de route handler.
try CreateUser.validate(content: req)
Probeer nu het volgende verzoek te sturen met een ongeldige e-mail:
POST /users HTTP/1.1
Content-Length: 67
Content-Type: application/json
{
"age": 4,
"email": "foo",
"favoriteColor": "green",
"name": "Foo",
"username": "foo"
}
U zou de volgende foutmelding moeten zien:
email is not a valid email address
Valideren van verzoek query¶
Types die voldoen aan Validatable
hebben ook validate(query:)
die gebruikt kan worden om de query string van een request te valideren. Voeg de volgende regels toe aan de route handler.
try CreateUser.validate(query: req)
req.query.decode(CreateUser.self)
Probeer nu het volgende verzoek te verzenden met een ongeldig e-mailadres in de querystring.
GET /users?age=4&email=foo&favoriteColor=green&name=Foo&username=foo HTTP/1.1
U zou de volgende foutmelding moeten zien:
email is not a valid email address
Integer Validatie¶
Geweldig, laten we nu eens proberen een validatie voor leeftijd
toe te voegen.
validations.add("age", as: Int.self, is: .range(13...))
De leeftijdsvalidatie vereist dat de leeftijd groter of gelijk is aan 13
. Als je hetzelfde verzoek als hierboven probeert, zou je nu een nieuwe fout moeten zien:
age is less than minimum of 13, email is not a valid email address
String Validatie¶
Laten we nu validaties voor name
en username
toevoegen.
validations.add("name", as: String.self, is: !.empty)
validations.add("username", as: String.self, is: .count(3...) && .alphanumeric)
De naam validatie gebruikt de !
operator om de .empty
validatie om te keren. Dit vereist dat de string niet leeg is.
De gebruikersnaam validatie combineert twee validators met behulp van &&
. Dit vereist dat de string minstens 3 tekens lang is en alleen alfanumerieke tekens bevat.
Enum Validatie¶
Laten we tenslotte eens kijken naar een iets meer geavanceerde validatie om te controleren of de opgegeven favoriteColor
geldig is.
validations.add(
"favoriteColor", as: String.self,
is: .in("red", "blue", "green"),
required: false
)
Omdat het niet mogelijk is om een Kleur
te decoderen uit een ongeldige waarde, gebruikt deze validatie String
als het basistype. Het gebruikt de .in
validator om te controleren of de waarde een geldige optie is: rood, blauw, of groen. Omdat deze waarde optioneel is, wordt required
op false gezet om aan te geven dat de validatie niet mag mislukken als deze sleutel ontbreekt in de request data.
Merk op dat terwijl de favoriete kleur validatie zal slagen als de sleutel ontbreekt, het niet zal slagen als null
wordt geleverd. Als je null
wilt ondersteunen, verander dan het validatie type in String?
en gebruik het .nil ||
(te lezen als: "is nil of ...") gemak.
validations.add(
"favoriteColor", as: String?.self,
is: .nil || .in("red", "blue", "green"),
required: false
)
Aangepaste fouten¶
Het is mogelijk dat u aangepaste menselijk leesbare fouten wilt toevoegen aan uw Validations
of Validator
. Om dit te doen hoeft u alleen maar de customFailureDescription
parameter op te geven, deze zal de standaard fout overschrijven.
validations.add(
"name",
as: String.self,
is: !.empty,
customFailureDescription: "Provided name is empty!"
)
validations.add(
"username",
as: String.self,
is: .count(3...) && .alphanumeric,
customFailureDescription: "Provided username is invalid!"
)
Validatoren¶
Hieronder staat een lijst van de momenteel ondersteunde validaties en een korte uitleg van wat ze doen.
Validatie | Beschrijving |
---|---|
.ascii |
Bevat enkel ASCII karakters. |
.alphanumeric |
Bevat enkel alphanumerieke karakters. |
.characterSet(_:) |
Bevat enkel karakters uit de opgegeven CharacterSet . |
.count(_:) |
De telling van de collectie is binnen de opgegeven grenzen. |
.email |
Bevat een geldig email. |
.internationalEmail | Bevat een geldig email met unicode karakters. |
.empty |
De verzameling is leeg. |
.in(_:) |
Waarde zit in de opgegeven Collection . |
.nil |
Waarde is null . |
.range(_:) |
Waarde is binnen de opgegeven Range . |
.url |
Bevat een geldige URL. |
Validators kunnen ook gecombineerd worden om complexe validaties te bouwen met behulp van operatoren.
Operator | Positie | Beschrijving |
---|---|---|
! |
voorvoegsel | Voert een validator in, die het tegenovergestelde vereist. |
&& |
tussenvoegsel | Combineert twee validators, vereist beide. |
|| |
tussenvoegsel | Combineert twee validators, vereist één. |