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
-
2.0Routes and How To Create Them5m 23s
-
2.1Rendering a View for a Route6m 29s
-
2.2Linking Between Routes7m 51s
-
2.3Loading A Movie Using Route Parameters9m 17s
-
2.4Validating Route Parameters6m 6s
-
2.5Vite and Our Assets6m 38s
-
2.6Setting Up Tailwind CSS9m 5s
-
2.7Reading and Supporting Markdown Content4m 32s
-
2.8Listing Movies from their Markdown Files8m 51s
-
2.9Extracting Reusable Code with Services7m 4s
-
2.10Cleaning Up Routes with Controllers4m 52s
-
2.11Defining A Structure for our Movie using Models9m 38s
-
2.12Singleton Services and the Idea of Caching6m 11s
-
2.13Environment Variables and their Validation4m 16s
-
2.14Improved Caching with Redis10m 44s
-
2.15Deleting Items and Flushing our Redis Cache6m 46s
-
2.16Quick Start Apps with Custom Starter Kits6m 28s
-
2.17Easy Imports with NodeJS Subpath Imports8m 40s
-
-
Building Views with EdgeJS
-
3.0EdgeJS Templating Basics8m 49s
-
3.1HTML Attribute and Class Utilities6m 9s
-
3.2Making A Reusable Movie Card Component10m 24s
-
3.3Component Tags, State, and Props4m 53s
-
3.4Use Slots To Make A Button Component6m 56s
-
3.5Extracting A Layout Component5m 13s
-
3.6State vs Share Data Flow2m 59s
-
3.7Share vs Global Data Flow6m 7s
-
3.8Form Basics and CSRF Protection6m 13s
-
3.9HTTP Method Spoofing HTML Forms3m 3s
-
3.10Easy SVG Icons with Edge Iconify7m 57s
-
-
Database and Lucid ORM Basics
-
4.0Configuring Lucid and our Database Connection4m 3s
-
4.1Understanding our Database Schema9m 35s
-
4.2Introducing and Defining Database Migrations18m 35s
-
4.3The Flow of Migrations8m 28s
-
4.4Introducing Lucid Models5m 43s
-
4.5Defining Our Models6m 49s
-
4.6The Basics of CRUD11m 56s
-
4.7Defining Required Data with Seeders11m 11s
-
4.8Stubbing Fake Data with Model Factories13m 48s
-
4.9Querying Our Movies with the Query Builder15m 30s
-
4.10Unmapped and Computed Model Properties3m 24s
-
4.11Altering Tables with Migrations7m 6s
-
4.12Adding A Profile Model, Migration, Factory, and Controller2m 57s
-
4.13SQL Parameters and Injection Protection9m 19s
-
4.14Reusable Query Statements with Model Query Scopes8m 11s
-
4.15Tapping into Model Factory States9m 15s
-
4.16Querying Recently Released and Coming Soon Movies4m 59s
-
4.17Generating A Unique Movie Slug With Model Hooks7m 59s
-
-
Lucid ORM Relationships
-
5.0Defining One to One Relationships Within Lucid Models5m 49s
-
5.1Model Factory Relationships2m 54s
-
5.2Querying Relationships and Eager Vs Lazy Loading5m 17s
-
5.3Cascading and Deleting Model Relationships5m 16s
-
5.4Defining One to Many Relationships with Lucid Models6m 56s
-
5.5Seeding Movies with One to Many Model Factory Relationships5m 24s
-
5.6Listing A Director's Movies with Relationship Existence Queries8m 41s
-
5.7Listing and Counting a Writer's Movies8m 41s
-
5.8Using Eager and Lazy Loading to Load A Movie's Writer and Director5m 18s
-
5.9Defining Many-To-Many Relationships and Pivot Columns9m 48s
-
5.10Many-To-Many Model Factory Relationships4m 50s
-
5.11A Deep Dive Into Relationship CRUD with Models18m 5s
-
5.12How To Create Factory Relationships from a Pool of Data13m 55s
-
5.13How To Query, Sort, and Filter by Pivot Table Data9m 47s
-
-
Working With Forms
-
6.0Accepting Form Data12m 15s
-
6.1Validating Form Data with VineJS9m 29s
-
6.2Displaying Validation Errors and Validating from our Request7m 16s
-
6.3Reusing Old Form Values After A Validation Error2m 3s
-
6.4Creating An EdgeJS Form Input Component5m 28s
-
6.5Creating A Login Form and Validator5m 1s
-
6.6How To Create A Custom VineJS Validation Rule9m 7s
-
-
Authentication & Middleware
-
7.0The Flow of Middleware7m 49s
-
7.1Authenticating A Newly Registered User4m 14s
-
7.2Checking For and Populating an Authenticated User2m 10s
-
Logging Out An Authenticated User2m 24s
-
Logging In An Existing User6m 54s
-
Remembering A User's Authenticated Session6m 55s
-
Protecting Routes with Auth, Guest, and Admin Middleware5m 36s
-
-
Filtering and Paginating Queries
Join The Discussion! (0 Comments)
Please sign in or sign up for free to join in on the dicussion.
Be the first to Comment!