Validating Form Data with VineJS
In this lesson, we'll learn how to validate form data using AdonisJS homegrown validation library, VineJS. With VineJS we can easily ensure our request body consists of properties we need, in the types we need them, with valid values.
- Author
- Tom Gobich
- Published
- Apr 09
- Duration
- 9m 29s
Developer, dog lover, and burrito eater. Currently teaching AdonisJS, a fully featured NodeJS framework, and running Adocasts where I post new lessons weekly. Professionally, I work with JavaScript, .Net C#, and SQL Server.
Adocasts
Burlington, KY
Transcript
Validating Form Data with VineJS
-
[MUSIC]
-
>> So at this point, we're grabbing our request data
-
off of our registration form.
-
So we have our full name, email, and password.
-
What we need to do next is actually create our user.
-
So our step 1 is to grab our request data.
-
Our step 2 is to create our user.
-
Our step 3 is to log in that user,
-
and then our step 4 is to return the user back to home.
-
So as we've previously covered,
-
we can create our user by doing const user equals await user.
-
Let's import that from our user model,
-
dot, and there's a create method that we can call.
-
We have the data that we want to
-
actually create the user with right here.
-
So we can plop that directly into the create call,
-
and that will create our user with a full name,
-
email, and password that we send up to the store method.
-
Just to simplify the verification step that we have
-
actually created a user, underneath here,
-
let's go ahead and temporarily console log our user,
-
and we'll call user.serialize just so that we see
-
the underlying user data within
-
the console log rather than all of the model attributes.
-
Let's give that a save. With our application running,
-
let's go ahead and dive back into our browser,
-
visit our registration page.
-
Let's right-click before we submit anything and inspect.
-
Let's get our network tab open.
-
Let's go over to the gear icon and let's persist our logs.
-
Since these are server sent actions,
-
our log will get cleared out anytime that we're
-
redirected away from this page.
-
So we want to persist the logs so that we
-
can actually inspect what's sending out here.
-
For our full name, let's do John Dell.
-
Email, we can do [email protected],
-
and our password can be whatever we want.
-
I'll just put password there.
-
Let's click our "Register" button.
-
We see a fair amount of things go out.
-
If we scroll all the way back up to the top,
-
we should see our post request for our register path.
-
If we take a look at that and take a look at the request,
-
we can see the request data that we actually send out.
-
Furthermore, if we jump into our terminal,
-
we see our users data.
-
So we created a user with an ID of seven here.
-
So far so good.
-
Let's go ahead and clear our terminal back out,
-
jump back into our registration page.
-
Let's clear that out once more.
-
Let's try running through that flow again.
-
So we have John Dell.
-
We'll put two in here so that we can discern the data.
-
We have [email protected] and password.
-
So at this point, we have actually created a user with an email of
-
[email protected] via our register store method,
-
but we're not verifying the uniqueness of this email within
-
that method via any validation step quite yet.
-
So whenever we hit "Register" here,
-
we're going to get a 500 error because the data that we've
-
submitted we'll try to insert into the user's table.
-
But since we've used the same email that we've already registered a user with,
-
that's going to violate our unique constraint
-
that we've added onto our users email field.
-
That's where and why validation comes into play here.
-
By default, AdonisJS uses Viya JS,
-
their own homegrown validation library to do that.
-
So let's get validation added in for our auth register form.
-
Again, we can see our error here within the terminal.
-
Let's go ahead and temporarily stop our server,
-
clear that out, and let's do node.ace.make.validator.
-
This is going to create a validation folder for us within our app directory that can
-
house all of the different validation schemas that we create for our forms.
-
We can put multiple validation schemas inside of a single file here.
-
What I've been doing is creating an individual validator per resource that we have.
-
So a resource would be something like a movie,
-
a sentence, things like that.
-
So we can keep along that same trajectory and create
-
an auth validator that's broad-reaching for
-
any auth-based validations that we need to do. We'll run that.
-
Cool. So now we have a file at app validators auth.ts.
-
While we're in here, let's go ahead and boot back up
-
our server and hide our terminal away.
-
We'll scroll up to that new validator file right here and enter into it.
-
You'll see it started us off with a nice import for Vine from Vine JS.
-
So first what we want to do is create and export a schema.
-
So let's do export const and we'll call this register validator,
-
because it's the validator specifically for our registration step,
-
equals vine.compile.
-
Within this compile method, we'll do vine.object,
-
because our form is going to end up submitting
-
an object that we want to validate with.
-
Then we want to do a key value pair.
-
The key is the field name and the value is
-
the validation rules that we want to validate that key against.
-
So for example, for our full name here,
-
the field name that we're submitting with our form is full name,
-
that's coming from our input.
-
We can specify the rules for this full name as vine.
-
Then from here, we want to specify the type of the input.
-
So whether it's a number, string,
-
array, Boolean, so on and so forth,
-
or a full name, it's going to be a string.
-
By default, the fields that we define here will be required.
-
So if we wanted our full name to be optional,
-
we could chain off of the string declaration and optional declaration as well.
-
Now with this being optional,
-
anytime Vine.js receives a value that's either null or undefined,
-
it will strip that away from the underlying data that we end up
-
receiving after our validation has run.
-
If we just wanted to strip out undefined values and keep null values,
-
we could switch that to nullable instead.
-
For a full name though, optional makes more sense.
-
Additionally, if we wanted to, we could also set
-
a max length for the full name as well.
-
So we could say it can't go longer than 100 characters.
-
There's a plethora of other string-based validations that we can apply as well,
-
like verifying that it's alpha,
-
alphanumeric, ASCII, Bale, clone, confirmed, coordinates,
-
a credit card number, an email,
-
whether it ends with a specific value,
-
we can escape it, so on and so forth.
-
For our full name though,
-
I think what we have here works.
-
Next, we have our email.
-
Here we'll want to do Vine.
-
The value type is a string.
-
We want to verify that it's a valid email that's been provided.
-
If we wanted to, we could have Vine also normalize this email.
-
Within this normalized email,
-
we can either run with the defaults or we can specify
-
email normalization options as an argument here.
-
If we hold command and click into our normalized email,
-
and then click into that normalized email options type,
-
and then click into it once more,
-
we can then see everything that this will actually accept as arguments.
-
So we have all lowercase as a Boolean,
-
gmail lowercase, gmail remove dots,
-
gmail remove subdress, so on and so forth.
-
So let's close those back out.
-
We'll just run with the defaults for right now.
-
As we ran through in the beginning of this lesson,
-
we do need to verify that this value is unique inside of our database.
-
So to do that, we can chain off of this a unique requirement.
-
This will require us to provide in
-
a callback function that checks whether or not the value is actually unique.
-
So for this callback function,
-
we're provided the DB,
-
the value, and the field information.
-
So we'll define that as a callback function here.
-
All that we need to do is use the DB,
-
which is the database query builder,
-
to check whether or not this email value that we're
-
provided right here is unique inside of our database,
-
return back true if it is,
-
and false if it is not.
-
So we do const result equals await DB.from.
-
We want to check our users table.
-
We also want this method to be async.
-
There we go. We'll select just the ID where
-
our email is the value that's provided into this validation call.
-
Then we want to return.
-
If we have a result,
-
then this is not unique,
-
and we need to return back false to signal that to bind.js.
-
Otherwise, we'll want to return true because we didn't get anything back,
-
and that means that this value is unique.
-
So we're okay to use it.
-
Now, we're not using field,
-
but I want to leave it there so that you all know that it's available.
-
So I'll prefix that with an underscore so that TypeScript's happy with it.
-
Lastly, we have our password.
-
Here, we'll want bind.
-
This is a string value as well.
-
For this one, we might want a min length,
-
and require that to be at least eight characters.
-
You could use regex or any of the other available rules to make
-
the password require whatever it is that you
-
require for your specific application.
-
For us, eight characters should be good enough here.
-
Cool. So we have our register validator fully defined,
-
and if we hover over it,
-
we'll actually see that it knows what it should accept
-
in and what it's going to return back to us.
-
We'll either get a full name of type string or undefined,
-
since it's optional.
-
We'll get an e-mail that's a type string and a password of type string.
-
So now it's time to make use of it within our register controller.
-
So before we create our user,
-
let's const validatedData equals await,
-
then we'll want to import our validator.
-
So we call that register validator.
-
So we'll type that out,
-
hit tab to auto import it from our validators off file,
-
and then we can call validate with it.
-
Within this validate method,
-
all that we need to do is provide in the data that we want to validate with.
-
Once it's validated,
-
it will return us back at those types that we saw earlier into our validatedData.
-
So if we take a look at the type here,
-
it knows exactly what properties we can use with this validatedData.
-
Meaning, we could take our validatedData,
-
and then plop that directly into our users create call.
-
Furthermore, should our validation fail,
-
AdonisJS will take care of that error automatically for us.
-
We don't need to use a try catch here,
-
it will automatically handle and return back an appropriate error for us,
-
and it will even provide validation messages by default for
-
us as well for the validations that did fail.
-
So with that saved, with our server running,
-
let's jump back into our browser.
-
Let's go into our task bar and hit enter to resubmit the page to get it back,
-
clear out our network requests,
-
and let's try submitting that exact same thing again.
-
So we'll do John Doe to [email protected],
-
which already exists inside of our database, and some password.
-
If we submit this off,
-
we're returned right back to this form,
-
which is the default behavior whenever validations fail using the validator.
-
If we take a look, you'll see that we submitted to
-
register and it redirected us right back to register.
-
If we take a look at the data that we submitted,
-
we see that data, and if we check out our terminal,
-
we won't see an error because that error was properly handled.
-
Now, we need to learn how we can use that default error handling to show
-
the error back to our user so that it doesn't
-
just redirect them directly back to this page with no feedback.
-
Introduction
-
Fundamentals
Join The Discussion! (4 Comments)
Please sign in or sign up for free to join in on the dicussion.
guy-aloni
Great tutorial, thanks!
How can I validate dates? I get an error
Uncaught Exception: Invalid value for "Chapter.startDate". It must be an instance of "luxon.DateTime"
, looks like date should be cast inside the validator?Please sign in or sign up for free to reply
tomgobich
Hi Guy! Yeah, the VineJS date validation will return back a native JavaScript Date object. You can transform the value returned by the validator into a Luxon DateTime using the
transform
method.Please sign in or sign up for free to reply
guy-aloni
Thanks Tom!
In my case, just if someone has the same problem, I had to add also an ISO format:
startDate: vine.date({ formats: { utc: true } }).transform((date) => DateTime.fromJSDate(date)),
Please sign in or sign up for free to reply
tomgobich
Anytime!! Happy to hear you got it all working!
Please sign in or sign up for free to reply