Let's Learn AdonisJS 6
In this series, we'll learn AdonisJS 6 step-by-step in a beginner-friendly way. Covering topics like routing, controllers, services, EdgeJS, Lucid ORM, forms, filtering, authentication, etc.
Module 1 › Introduction (5 lessons)
Lesson 1.0
Introducing AdonisJS
In this lesson, we'll introduce AdonisJS by giving a brief overview of what it is and what it offers. We'll also talk about some of its first-party and framework-agnostic packages.
Lesson 1.1
What We'll Need Before We Begin
In this lesson, we'll talk about some prerequisites to AdonisJS and this series. These include installing NodeJS, VS Code, a database environment, and Redis.
Lesson 1.2
Creating A New AdonisJS 6 Project
In this lesson, we'll create our first AdonisJS 6 project and learn how we can boot it up and open it within VS Code.
Lesson 1.3
Project Structure
In this lesson, we'll learn how AdonisJS uses our project to boot up and which folders and files within our project matter as we get started with learning AdonisJS 6
Lesson 1.4
VS Code Extensions and Configuration
In this lesson, we'll install three extensions for VS Code from the AdonisJS Core Team to make our lives easier as we build applications. We'll also configure Prettier and ESLint with auto-formatting and lint fixing on save.
Module 2 › Fundamentals (18 lessons)
Lesson 2.0
Routes and How To Create Them
In this lesson, we'll learn how to define routes within AdonisJS and how those routes work.
Lesson 2.1
Rendering a View for a Route
In this lesson, we'll learn how we can use the EdgeJS Template Engine to render HTML views and send them back as the response for our routes. We'll also see how we can pass dynamic data into our views from our route handler.
Lesson 2.2
Linking Between Routes
In this lesson, we'll learn how we can link between the routes we have defined in our application. We'll also learn about the importance of HTTP Method verbs and resources to standardize our route definitions.
Lesson 2.3
Loading A Movie Using Route Parameters
In this lesson, we'll learn how we can reuse a route definition using route parameters to show any item we have for our movie resource.
Lesson 2.4
Validating Route Parameters
In this lesson, we'll learn how we can return a 404 Not Found exception when someone tries to view a movie that doesn't exist. We'll then learn how we can validate our route parameters using Regular Expressions or matchers.
Lesson 2.5
Vite and Our Assets
In this lesson, we'll learn how Vite is integrating into our EdgeJS views to serve our JavaScript and CSS files.
Lesson 2.6
Setting Up Tailwind CSS
In this lesson, we'll learn how to install and configure PostCSS and Tailwind CSS within our AdonisJS 6 project using Vite.
Lesson 2.7
Reading and Supporting Markdown Content
In this lesson, we'll learn how we can support Markdown content by switching our movies from HTML to Markdown. To do this, we'll make use of the DimerApp Markdown package.
Lesson 2.8
Listing Movies from their Markdown Files
In this lesson, we'll learn how we can list movies and their details directly from our movies directory using a YAML-based declaration called frontmatter.
Lesson 2.9
Extracting Reusable Code with Services
In this lesson, we'll learn about services and how we can use them to extract reusable code in a way that makes it super simple to use throughout your project.
Lesson 2.10
Cleaning Up Routes with Controllers
In this lesson, we'll learn what controllers are and how they can be used to drastically simplify our route definitions by allowing us to move our route handlers off the route definition and into the controller.
Lesson 2.11
Defining A Structure for our Movie using Models
In this lesson, we'll introduce the concept of models by using one to define the properties our movies should contain. We'll then stub some methods that will mock calls we'll later be able to use to load data from our database.
Lesson 2.12
Singleton Services and the Idea of Caching
In this lesson, we'll learn about singleton services and how to use them as a store to hold temporary information throughout our server's life by building a simple in-memory caching service.
Lesson 2.13
Environment Variables and their Validation
In this lesson, we'll learn how we can securely store sensitive and environment-based variables using our .env file. We'll also learn how AdonisJS adds type-safety to these variables using our env.ts file as validation.
Lesson 2.14
Improved Caching with Redis
In this lesson, we'll install and configure the AdonisJS Redis package. We'll then swap out our singleton in-memory cache service with a Redis cache implementation.
Lesson 2.15
Deleting Items and Flushing our Redis Cache
Not everyone is perfect, and one day you'll accidentally cache bad data and need a way to quickly clear it out. In this lesson, we'll learn how we can create two routes to clear a single Redis key or flush the entire database.
Lesson 2.16
Quick Start Apps with Custom Starter Kits
In this lesson, we'll take a look at AdonisJS' bring your own kit feature that allows us to use Git repositories as starter kits when creating a new AdonisJS application.
Lesson 2.17
Easy Imports with NodeJS Subpath Imports
In this lesson, we'll learn about NodeJs Subpath Imports and how AdonisJS leverages them to help simplify our import paths throughout our application.
Module 3 › Building Views with EdgeJS (11 lessons)
Lesson 3.0
EdgeJS Templating Basics
In this lesson, we'll learn the basics of AdonisJS's homegrown template engine EdgeJS. We'll cover interpolation, conditional statements, looping, variables, state, and more!
Lesson 3.1
HTML Attribute and Class Utilities
In this lesson, we'll take a look at a few powerful utilities provided by EdgeJS that make working with attributes and conditional classes a breeze.
Lesson 3.2
Making A Reusable Movie Card Component
In this lesson, we'll learn how we can make a movie card component with EdgeJS that we can define once and easily use throughout our markup.
Lesson 3.3
Component Tags, State, and Props
In this lesson, we'll learn how to use EdgeJS components within AdonisJS as direct tags. We'll also learn about our component's state and props
Lesson 3.4
Use Slots To Make A Button Component
In this lesson, we'll learn about EdgeJS component slots by making a versatile button component that can gracefully handle both links and button types.
Lesson 3.5
Extracting A Layout Component
In this lesson, we'll learn how we can create EdgeJS layouts using components so that we don't have to redefine or HTML structure for every page in our application.
Lesson 3.6
State vs Share Data Flow
In this lesson, we'll learn about the difference between passing information directly into EdgeJS' state and sharing information with EdgeJS.
Lesson 3.7
Share vs Global Data Flow
In this lesson, we'll compare the difference between sharing information with an EdgeJS instance and defining a Global within EdgeJS.
Lesson 3.8
Form Basics and CSRF Protection
In this lesson, we'll cover the basics of working with HTML forms in AdonisJS and how they incorporate Cross-Site Request Forgery (CSRF) protection via AdonisJS Shield.
Lesson 3.9
HTTP Method Spoofing HTML Forms
In this lesson, we'll learn how we can enable HTTP Method Spoofing to allow AdonisJS to spoof intended HTTP Verbs for basic HTML form POST requests.
Lesson 3.10
Easy SVG Icons with Edge Iconify
In this lesson, we'll learn how we can install and use the edge-iconify package giving us super easy access within our EdgeJS files to any of the SVG icon packages available through Iconify.
Module 4 › Database and Lucid ORM Basics (18 lessons)
Lesson 4.0
Configuring Lucid and our Database Connection
In this lesson, we'll learn how we can configure Lucid to use a different driver other than SQLite; PostgreSQL is shown but MySQL and MSSQL are much the same. Then, we'll set up our connection details so that we can successfully connect to our database.
Lesson 4.1
Understanding our Database Schema
In this lesson, we'll walk through how to understand a database schema diagram. We'll then discuss the schema we'll be working with throughout this series; describing the tables, columns, data types, and relationships.
Lesson 4.2
Introducing and Defining Database Migrations
In this lesson, we'll introduce database migrations. We'll learn what they are, why they're great to have, and how we can create and use them to define our database tables and their columns.
Lesson 4.3
The Flow of Migrations
In this lesson, we'll learn about the various migration-based commands made available by the Ace CLI and how they interact with our migration files. We'll use these commands to run, rollback, and refresh our migrations against our database.
Lesson 4.4
Introducing Lucid Models
In this lesson, we'll introduce models using the Lucid ORM. We'll learn how we can map database columns to our model properties and specify special behavior for our date time columns.
Lesson 4.5
Defining Our Models
In this lesson, we'll walk through the process of defining all our database tables and columns as models and properties within our application.
Lesson 4.6
The Basics of CRUD
In this lesson, we'll walk through the basics of creating, reading, updating, and deleting (CRUD) data from our database using our Lucid Models.
Lesson 4.7
Defining Required Data with Seeders
Our database will have specific, non-changing, roles and movie statuses. In this lesson, we'll learn how we can quickly and easily create these records inside of our database using seeders.
Lesson 4.8
Stubbing Fake Data with Model Factories
In this lesson, we'll learn how we can quickly and easily bulk-create dummy/fake data within our database for each of our Lucid Models using Model Factories
Lesson 4.9
Querying Our Movies with the Query Builder
In this lesson, we'll introduce both the database and model query builder. We'll learn the differences between the two and the basics of how to use them.
Lesson 4.10
Unmapped and Computed Model Properties
In this lesson, we'll learn how to add unmapped and computed properties to our Lucid Models. We'll discuss the differences between a model column, unmapped property, and a computed property.
Lesson 4.11
Altering Tables with Migrations
In this lesson, we'll learn how to alter our database tables using migrations both while in development, where we can delete our data, and once our data has already hit production where we need to persist all data.
Lesson 4.12
Adding A Profile Model, Migration, Factory, and Controller
Uh oh, a new requirement has come in and now we also need to account for user profiles! In this lesson, we'll learn how we can easily create a new model, migration, factory, and controller for an entity in one fell swoop!
Lesson 4.13
SQL Parameters and Injection Protection
In this lesson, we'll learn about SQL Parameters, also called query bindings, and how using them helps safeguard our database from malicious attacks attempting to perform SQL Injection.
Lesson 4.14
Reusable Query Statements with Model Query Scopes
In this lesson, we'll learn about Model Query Scopes and how we can use them to create easily reusable query statements that we can apply using the Model Query Builder.
Lesson 4.15
Tapping into Model Factory States
In this lesson, we'll dive a little bit deeper into Model Factories by introducing factory states. We'll also learn how we can use the tap method to alter a factory result prior to it persisting into the database
Lesson 4.16
Querying Recently Released and Coming Soon Movies
In this lesson, we'll learn how to use the Model Query Builder to query our movies that have been recently released. We'll then do a separate query to get movies that are coming soon.
Lesson 4.17
Generating A Unique Movie Slug With Model Hooks
In this lesson, we'll learn how we can use Model Hooks to generate a unique URL-safe slug based on the movie's title.
Module 5 › Lucid ORM Relationships (14 lessons)
Lesson 5.0
Defining One to One Relationships Within Lucid Models
In this lesson, we'll learn how to define one-to-one relationships within our Lucid Models. We'll learn about the belongs to and has one decorators, their options, and types that make this possible.
Lesson 5.1
Model Factory Relationships
In this lesson, we'll learn how to use relationships with our Model Factories; easing our capabilities to quickly generate fake data with relationships.
Lesson 5.2
Querying Relationships and Eager Vs Lazy Loading
In this lesson, we'll learn how we can query our relationships using our Lucid Models. We'll then learn what the difference is between eagerly loading a relationship (load) and lazily loading a relationship (preload).
Lesson 5.3
Cascading and Deleting Model Relationships
In this lesson, we'll learn how to account for foreign key constraints when deleting relationships using our Lucid Models. We'll then learn how we can automatically cascade deletions through to relationships.
Lesson 5.4
Defining One to Many Relationships with Lucid Models
In this lesson, we'll learn how to define one-to-many and many-to-one relationships using Lucid Models. We'll also learn how we can specify the columns that should be used for a relationship, allowing us to use one model for multiple relationships.
Lesson 5.5
Seeding Movies with One to Many Model Factory Relationships
In this lesson, we'll learn how we can use Model Factory Relationships to create a pool of cineasts to bind to our movies. This will create cineasts bound to many movies as a writer, director, or both.
Lesson 5.6
Listing A Director's Movies with Relationship Existence Queries
In this lesson, we'll learn how we can perform a relationship existence check to grab a list of our cineasts who have directed one or more movies. We'll then create a show page for that director, listing the movies that they directed.
Lesson 5.7
Listing and Counting a Writer's Movies
In this lesson, we'll learn how we can perform multiple different relationship counts with the same relationship using the Model Query Builder. We'll count our writer's total number of released and not-released movies.
Lesson 5.8
Using Eager and Lazy Loading to Load A Movie's Writer and Director
In this lesson, we'll learn how we can use eager loading to preload our writer and director onto our movie's details. We'll then, learn how we can load our writer and director onto our movie's details using lazy loading.
Lesson 5.9
Defining Many-To-Many Relationships and Pivot Columns
In this lesson, we'll learn how you can define many-to-many relationships within your Lucid ORM Models. We'll also discuss the relationship options, and how you can automatically include pivot table data with all queries.
Lesson 5.10
Many-To-Many Model Factory Relationships
In this lesson, we'll learn how we can define and use many-to-many relationships with Model Factories, including how we can define pivot table data when creating our fake records.
Lesson 5.11
A Deep Dive Into Relationship CRUD with Models
In this lesson, we'll take a deep look at how we can perform CRUD operations with one-to-one, one-to-many, many-to-one, and many-to-many relationships using our Lucid Models.
Lesson 5.12
How To Create Factory Relationships from a Pool of Data
In this lesson, we'll learn how we can refactor our fake data seeder to allow us to assign cast members and crew members to our movies via our many-to-many relationships from a single pool of cineast records.
Lesson 5.13
How To Query, Sort, and Filter by Pivot Table Data
In this lesson, we'll learn how we can query pivot table data. We'll then learn how we can also sort and filter our results by those pivot table columns as well.
Module 6 › Working With Forms (7 lessons)
Lesson 6.0
Accepting Form Data
In this lesson, we'll take a look at how we can create a register form and accept data from that form within our route handler.
Lesson 6.1
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.
Lesson 6.2
Displaying Validation Errors and Validating from our Request
In this lesson, we'll learn how we can display feedback for invalid fields noted by errors from our VineJS validators. We'll also see how we can validate directly from our request using request data.
Lesson 6.3
Reusing Old Form Values After A Validation Error
In this lesson, we'll learn how we can easily repopulate our form input values with their previously submitted values when our VineJS validator finds and sends back an error.
Lesson 6.4
Creating An EdgeJS Form Input Component
In this lesson, we'll create a form input component with EdgeJS to simplify adding inputs throughout our application and to extract away old value and validation error logic.
Lesson 6.5
Creating A Login Form and Validator
In this lesson, we'll apply what we've learned to create a login page as well as a validator for our login form.
Lesson 6.6
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.
Module 7 › Authentication & Middleware (7 lessons)
Lesson 7.0
The Flow of Middleware
In this lesson, we'll learn about the middleware that comes preinstalled within AdonisJS and the flow of this middleware during an HTTP Request at both a global and route-specific scale.
Lesson 7.1
Authenticating A Newly Registered User
In this lesson, we'll learn how we can authenticate, or login, a new user who just registered with our application. We'll then see how we can populate the authenticated user's details on subsequent requests.
Lesson 7.2
Checking For and Populating an Authenticated User
In this lesson, we'll create a silent auth middleware that will automatically check whether a request has an authenticated user attached to it, and populate that user's details if one is found.
Lesson 7.3
Logging Out An Authenticated User
In this lesson, we'll learn how to logout an authenticated user using a POST request with CSRF protection.
Lesson 7.4
Logging In An Existing User
In this lesson, we'll learn how we can login an existing user using just their email and password. We'll discuss how the AuthFinder mixin protects us from timing attacks, and how we can use it to verify the accuracy of a user's password.
Lesson 7.5
Remembering A User's Authenticated Session
In this lesson, we'll learn how we can use AdonisJS' Remember Me Tokens feature to allow a user to specify they'd like their authentication state to be remembered for a long time across sessions.
Lesson 7.6
Protecting Routes with Auth, Guest, and Admin Middleware
In this lesson, we'll learn about the auth and guest middleware included when we created our AdonisJS 6 project. Then, we'll create our own named middleware that will allow us to restrict page access to only users with the admin role.
Module 8 › Filtering and Paginating Queries (8 lessons)
Lesson 8.0
Creating A Movie List Page
In this lesson, we'll create a page to list all of our movies. Since we have a lot of movies, in this module, we'll focus on adding filters and pagination to this list.
Lesson 8.1
Filtering A Query By Pattern Likeness
In this lesson, we'll learn how to add a pattern filter to our movies.index page that will allow us to filter our movies list by title using a case-insensitive pattern search.
Lesson 8.2
Filtering Our List by Movie Status
In this lesson, we'll alter our form input component to allow selects. Then, we'll learn how to add a select-based filter to our movie list page so that we can see only movies containing a specific movie status.
Lesson 8.3
How To Apply A Dynamic Sort Filter To Your Query
In this lesson, we'll learn how we can add a user-selected sort option to our filters. Then, we'll apply the selected filter to our movie query
Lesson 8.4
Joining SQL Tables To Order By A Related Column
In this lesson, we'll learn how to join a related table into our query and use that table to apply a sort via the relationship. We'll then see how we can conditionally apply this join only when it's needed for the selected order by.
Lesson 8.5
Validating Query String Filter Values
In this lesson, we'll learn how to use VineJS, AdonisJS' Validator, to validate the filter properties and values we have within our query string.
Lesson 8.6
How To Paginate Filtered Query Results
In this lesson, we'll learn about AdonisJS Model Query Builder pagination and walk through an example of how we can easily paginate the results of our filtered movies.
Lesson 8.7
Pagination First, Last, Next, and Previous Buttons
In this lesson, we'll take a look at how to add pagination links to the next and previous pagination pages. Then, we'll follow the same process to add links to the first and last pagination pages.
Module 9 › User Watchlist (7 lessons)
Lesson 9.0
An Alternative Approach to Many-To-Many Relationships
In this lesson, learn an alternative approach to many-to-many relationships that allows you to work directly with the pivot table as a model.
Lesson 9.1
Toggling A Movie in an Authenticated User's Watchlist
In this lesson, we'll learn how to add the ability to toggle whether a user has a movie within their watchlist. We'll also query and display whether a movie is in the authenticated user's watchlist as well.
Lesson 9.2
Listing and Filtering User Watchlist Items
In this lesson, we'll take our movie filter, and learn how we can reuse it to display a filterable list of the user's watchlist movies.
Lesson 9.3
Allowing Users To Toggle A Movie As Watched
In this lesson, we'll learn how to allow users to toggle whether they've watched a movie or not within their watchlist.
Lesson 9.4
Filtering By User's Watched Status
In this lesson, we'll learn how to add a filter to our user's watchlist allowing them to show only movies they have or have not watched.
Lesson 9.5
Defining A Composite Unique Constraint
In this lesson, we'll learn how you can enforce uniqueness between multiple columns using a composite unique constraint.
Lesson 9.6
Persist Filters Easily with Lucid's Query String Method
Learn how to simplify pagination by persisting active filters with the query string method. Follow this step-by-step guide to clean up your code, apply the .queryString method from Lucid, and ensure seamless pagination for your web applications.
Module 10 › User Profiles (6 lessons)
Lesson 10.0
How to Create and Fix Missing User Profiles in Your Application
Learn how to create and manage user profiles in your application. This tutorial covers adding an edit profile button, setting up routes and controllers, ensuring profile creation during registration, handling existing users without profiles, and verifying
Lesson 10.1
Using Dependency Injection to Update A User's Profile
In this lesson, we'll learn how to allow users to edit their profiles. We'll also cover how we can inject the HttpContext into a service instance using Dependency Injection (DI).
Lesson 10.2
Saving All Or Nothing with Database Transactions
In this lesson, we'll learn about database transactions and how we can use them to batch commit or rollback updates, safeguarding against partial updates due to errors.
Lesson 10.3
Uploading and Displaying User Avatars
In this lesson, we'll learn how to validate and upload avatar images into our project's storage. We'll then learn how we can easily display images we have contained within our app's storage
Lesson 10.4
Displaying A User's Profile
In this lesson, we'll learn how you can mimic popular sites and use an @ handle to display your user's profiles
Lesson 10.5
Filtering, Preloading, and Sorting By Relationship
In this lesson, we'll list the movies a user has watched on their profile. To do this, we'll filter, preload, and sort by the watchlist relationship where the user's watched at value is not null.
Module 11 › Admin Panel (12 lessons)
Lesson 11.0
Creating An Admin Layout
In this lesson, we'll learn how to create an admin layout we can use throughout our admin section pages. This layout will include a secondary navigation specific to administrative actions.
Lesson 11.1
Counting Stats for our Admin Dashboard
In this lesson, we'll perform various counts against our models to display on our admin dashboard page.
Lesson 11.2
Paginated Admin Movie Table
In this lesson, we'll learn how we can create a paginated movie table for our administrators. We'll list the movies and some of their relationship data, like the number of crew and cast members associated with the movie.
Lesson 11.3
Allowing Admins to Create Movies
In this lesson, we'll allow our administrators to create movies via our admin panel. We'll walk through getting the form set up, validated, and our movies created.
Lesson 11.4
Allowing Admins to Update Movies and Clear Values
In this lesson, we'll recreate our movie form for the purpose of updating our movies. We'll also add the ability to clear values and discuss the difference between VineJS' optional and nullable chain options.
Lesson 11.5
How To Use One Form to Create or Edit Movies
In this lesson, we'll learn how we can merge our create form and edit form together into a create or edit form. We'll conditionally determine whether we'll be creating or editing based on our movie value and use EdgeJS features to simplify the process
Lesson 11.6
Uploading Movie Cover Images in our Create or Edit Form
In this lesson, we'll learn how to upload movie cover images when either creating or editing a movie via our create or edit form.
Lesson 11.7
Using A Wildcard Route Param to Download Storage Images
In this lesson, we'll learn how we can utilize a wildcard route parameter to dynamically download images that've been uploaded and stored within our application storage.
Lesson 11.8
Posting Objects, Arrays, and an Array of Objects in HTML Forms
In this lesson, we'll learn how we can use form field names to send an array of objects with our HTML form submission. We'll discuss pitfalls to watch out for and how we use AlpineJS to simplify index syncing within our field names.
Lesson 11.9
Managed Transactions and Syncing Movie Cast Members
In this lesson, we'll learn how we can use what we learned in the last lesson to also sync our cast members. We'll then extract this functionality into a service and wrap it within a managed database transactions.
Lesson 11.10
Allowing Admins to Delete Movies and their Relationships
In this lesson, we'll learn how we can safely delete movies and their relationships. We'll discuss how we need to consider foreign key constraints, and what to do when our deletes aren't set to cascade.
Lesson 11.11
Thank You for Watching!
A quick thank you to all those who watched! If you have feedback, please let us know down in the comments.