How To Create A Custom VineJS Validation Rule
In this lesson, we'll learn how to make a custom validation rule with VineJS that requires a value to be unique for the provided table and column. We'll learn how we can register this rule for both strings and number types.
- Author
- Tom Gobich
- Published
- Apr 12
- Duration
- 9m 7s
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
How To Create A Custom VineJS Validation Rule
-
(upbeat music)
-
So we can create our own rules with VineJS as well.
-
And the documentation does a fantastic job
-
of walking through this.
-
And the example that they give is great as well.
-
So we're gonna walk through that in this lesson
-
in the context of AdonisJS.
-
So we're gonna be provided a couple of things
-
whenever we create a rule.
-
We're gonna be provided the value,
-
which will be of type unknown.
-
So we're gonna need to discern what the type is
-
before we actually attempt to use it.
-
Options accepted by the rule.
-
These are options that we can define as is.
-
So this could be something like a table or a column
-
to check the database to see whether or not
-
a value is unique.
-
That's something defined by us.
-
And if we define the rule to have nothing as options,
-
then the second parameter will be undefined.
-
Then comes the field context.
-
This is contextual information about the actual field data.
-
So things like the value, data, metadata,
-
whether the field is valid, defined.
-
You can mutate the value, report errors,
-
field parent, name, and whether or not it's an array member.
-
So that's what's confined within the field context.
-
So to start, we're going to need a place
-
to house our new validation rule.
-
For this, we'll want to use a preload file.
-
So we can stop our server.
-
Let's clear that out.
-
Let's do node ace make reload.
-
We'll put these inside of a directory called rules,
-
and we're gonna follow along with the documentations example.
-
So we'll create a unique rule to simplify the unique checks
-
throughout our validation example.
-
Remember, right now within our application,
-
if we dive inside of our auth validator,
-
our unique check looks something like this,
-
where we're taking a callback function
-
that's provided into the database,
-
manually compiling out that query,
-
and then returning back whether or not we found results.
-
So we're gonna wrap this up in a pretty little bow,
-
where all that we need to do is provide in the table
-
and the column that we want to check,
-
and the check will happen automatically.
-
So let's hide that back away.
-
Let's run that to create our preload.
-
We'll have it register it within our AdonisRC.ts file,
-
and we're good to go there.
-
Let's go ahead and boot our server back up while we're here.
-
All right, let's hide that back away
-
and dive into our text editor,
-
and let's head into our new preload file.
-
So that's within our start directory.
-
We created that within a folder called rules,
-
and there's our file for unique.
-
Within here, we're gonna want an async function.
-
We'll call this function our rules name.
-
Within the documentation, they call this unique.
-
However, I don't want to overwrite
-
the current unique check that we have.
-
We'll leave this in place.
-
So let's name our simplified rule something different,
-
maybe something like is unique.
-
Our parameters to this method will then be the value,
-
which as the documentation noted, is of type unknown.
-
So we need to discern what type the actual value holds
-
before we can use it.
-
Then options.
-
By default, if we don't want our method
-
to accept any options, this will be undefined.
-
We do want ours to accept options,
-
but just to get us going,
-
let's stub that to undefined for right now.
-
And then our field information,
-
which is of type field context,
-
which we can import from vine.js/vine-types.
-
Since we're specifically going to use that just as a type,
-
we'll import that as a type there as well.
-
So for our options,
-
let's go ahead and create a type for that.
-
So we'll do type options equals object.
-
We'll have one option be our table.
-
So the table that we should check against for the column,
-
this will be a type string,
-
and then the column that we should check against
-
inside of that table.
-
Let's jump down to our options
-
and set that as the type value there.
-
The first thing we're going to want to do
-
is check the type of our value.
-
For the documentation,
-
they show this as just being a string
-
and they kick out anything that is not a string,
-
but I could see this being used for an ID as well.
-
So I think we'll allow numbers within ours as well.
-
So let's do if type of value does not equal string
-
and type of value does not equal number,
-
then we'll just want to return back out of this method
-
so that this particular method
-
doesn't handle either of those types.
-
We're going to add our is unique method
-
as an option onto vine string and vine number.
-
So if the value doesn't match one of those two types,
-
the vine string or vine number validation
-
will handle that accordingly.
-
So within our actual unique check,
-
we don't need to report the error at this point
-
because that vine string or vine number check
-
will take care of that for us.
-
We can just ignore the value here.
-
Then if our value is a string or a number,
-
we can move onward.
-
So we'll do const result equals await,
-
and then we're going to want to import the database module
-
because we don't know what particular model
-
we're going to be working with here.
-
So we can use the database module to accept in the table
-
that we should check against and hone that in
-
on the particular column to check and see
-
whether or not we have a value.
-
So import db from at AdonisJS,
-
Lucid services, db, we can scroll back down
-
and make use of that db query builder.
-
So db.from, provide in our options.table,
-
select just the options.column that we want to hone in on
-
where that options.column equals the value
-
that's provided in.
-
And then if any of them exist inside of the database,
-
the is unique check will be false.
-
So we can just stop at the first found record
-
and get that back as our result.
-
So if we have a result,
-
then we'll want to report that the value is not unique.
-
So we'll do field, and then we can use that report method
-
that we saw inside of the documentation to report an error.
-
The first argument here is going to be that error message.
-
The second argument is going to be the rule that failed.
-
And then the third argument is going to be
-
the field information for our validation.
-
So for this value, we can do something like this
-
and then reach for interpolation and specify in the field.
-
And this would plop something in like this.
-
And then if we're validating an email,
-
this would be this email is already taken
-
or something like that.
-
The rule here is is unique.
-
And then the field information we can provide in
-
as the third argument.
-
If this rule is valid, however,
-
we don't want to report an error.
-
And instead we can just escape out of this function
-
so we don't need to do anything else.
-
Okay, so we have the function handler
-
for our rule fully defined.
-
Now we need to register it with VineJS.
-
So first thing we're going to want to import find
-
from VineJS/find.
-
Scroll back down and let's do const is unique rule
-
equals find.
-
And there's a method on here called create rule
-
that will actually create a find validator rule
-
for the function that we provide in.
-
So we'll just want to provide in our is unique function.
-
There, now we've actually created a find rule
-
with our is unique method.
-
And the full rule is our is unique rule variable.
-
We could export this so that we could use it
-
as needed elsewhere.
-
But as stated earlier, we could also add this directly
-
onto the types that we want this rule
-
to be available for as well,
-
which in our case is both our string and our numbered types.
-
So let's import find string,
-
which is the rule set for the find string validator
-
and then find number,
-
which is the same thing for the number validator.
-
Scroll back down and let's do a macro for both of those.
-
So we'll do find string first,
-
create a macro called is unique.
-
We'll create a block level function that accepts in this,
-
which is of type find string.
-
And this is an instance of the actual validation rule
-
that's being built specifically for the string type.
-
And then the second argument will want to be
-
the actual options that we accept
-
into our new is unique validation rule.
-
So that's going to be the options type
-
that we defined at the top of this file.
-
It's defined as a block level function
-
and then return this dot.
-
And we can use to push our validation rule
-
into the applied validations
-
for this specific find string instance.
-
So for this use method,
-
we'll want to provide in our is unique rule,
-
not the actual is unique function.
-
So we'll do is unique rule.
-
We'll call that as a function
-
and provide the options into it.
-
Okay, now we're getting a red squiggly
-
on our is unique string because is unique
-
is not assignable to a parameter uptight key find string
-
because it has not been defined on the actual type set.
-
So we want to do that next.
-
So let's declare module at find JS slash bind.
-
Then we'll want to reach for the bind string interface.
-
So bind string there and add in our is unique rule
-
and designate that this accepts in options of type options
-
and returns back the validation rule builder of type this.
-
And now we should have that readily available to us.
-
Furthermore, if we now dive back into our auth validator,
-
before where we call this unique,
-
let's attempt to do now dot is unique
-
and there is our brand new rule.
-
And if we attempt to call it,
-
we'll see that it accepts in our options.
-
So we can provide in our object with a type table.
-
For this, we want to check the users table
-
and provide in the column.
-
Then we'll want to check the email column there.
-
So now we should be able to get rid
-
of this big function call
-
and just use our brand new is unique rule.
-
And additionally, we've left that unique method there
-
just in case we need it in the future
-
for more expandability.
-
Okay, let's jump back into our unique rule
-
and apply this for our number types as well.
-
It's gonna look very similar to this.
-
The types are just gonna be different.
-
So we'll do bind number.
-
This right here will be bind number as well.
-
And then we just want to copy the interface,
-
paste it in here and switch this
-
from bind string to find number.
-
And now we have this available for numbers
-
as well as strings.
-
So if we were to try to dive back into our auth validator,
-
let's do something like user ID.
-
This doesn't make much sense,
-
but just so that we can actually see that it's available,
-
let's do bind number.
-
That is unique.
-
And there we go.
-
So it's available there as well.
-
But if we do something that we haven't applied it to,
-
like remember me, bind Boolean type is unique.
-
It does not exist there.
-
So awesome.
-
Everything's looking a-okay.
-
The last thing to do is to actually test it out
-
and make sure that it works.
-
So with our server running,
-
let's head back into our application.
-
Let's jump into our register page
-
because this is where we're actually using
-
that unique check rule.
-
We'll provide John for our first name,
-
[email protected] for our email,
-
and then just whatever for the password.
-
And there we go.
-
We got back our error.
-
This email is already taken as we've described it
-
within our brand new custom rule.
-
Let's switch this to [email protected],
-
which does not exist inside of our database.
-
And let's enter in a valid password,
-
attempt to register, and voila, everything worked a-okay.
-
We didn't get any errors with our validation.
-
And we can check our terminal out once more.
-
And we see the actual created user within here as well.
-
So we know everything worked a-okay in terms of our user being created.
-
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
-
The Flow of Middleware7m 49s
-
Authenticating A Newly Registered User4m 14s
-
Checking 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! (4 Comments)
Please sign in or sign up for free to join in on the dicussion.
redeemefy
Good content so far. Thanks for putting it together. Keep up the hard work. This course indeed is going to help me start my own business. Praying to God to give me the strength to move forward with it.
Please sign in or sign up for free to reply
tomgobich
Thank you, redeemefy!! I'm happy to hear it's helping, and best of luck with starting your business! You got this, just take it one line at a time!! :D
Also - apologies your Adocasts Plus badge was missing! Looks like it was a concurrency issue with the Stripe Webhook, I'll have to get that fixed up.
Please sign in or sign up for free to reply
redeemefy
Nice listening with those Stripe web-hooks. I use those myself at work when Stripe was our provider.
Please sign in or sign up for free to reply
tomgobich
Adocasts has been my first time working with Stripe, we do more direct B2B sales where I work, so it's been a fun learning experience lol. :D
Please sign in or sign up for free to reply