AdonisJS is a backend framework. It helps you create data-driven dynamic web applications. Using AdonisJS, you can handle the HTTP requests, query the database, authenticate users, upload files, send emails, and do a lot more.

If you have ever worked with a different backend framework like Rails, Laravel, or Django, then you can consider AdonisJS to be in the same boat.

Create URLs using routes

You define the URLs of your app using the routes module of AdonisJS. Think of routes as a mapping between the URL and the Javascript function you want to execute when someone visits that URL.

import Route from '@ioc:Adonis/Core/Route'
Route.get('/', () => {
return 'Hello! This is the homepage of my new app'
})

The above code defines a static route. However, a data-driven application also needs the power to register dynamic routes. For example: Grab the post id from the URL and then query the database.

import Route from '@ioc:Adonis/Core/Route'
import Database from '@ioc:Adonis/Lucid/Database'
Route.get('posts/:id', ({ params }) => {
return Database
.from('posts')
.select('*')
.where('id', params.id)
.first()
})

Handle requests using controllers

Controllers are the de-facto way of handling HTTP requests in AdonisJS. They help you extract all the inline function calls from the routes file to the dedicated controller files and keep your routes file tidy.

1. Create a controller

node ace make:controller Posts

2. Implement the required methods

import Database from '@ioc:Adonis/Lucid/Database'
export default class PostsController {
public async show({ params }) {
return Database
.from('posts')
.select('*')
.where('id', params.id)
.first()
}
}

3. Register it with the route

Route.get('posts/:id', 'PostsController.show')

Query database using the ORM

You can interact with the SQL databases using the official ORM of AdonisJS - "Lucid". Lucid has a rich API to perform schema migrations, seed databases with dummy data, and construct SQL queries using the Javascript API.

More importantly, Lucid has data models built on top of the Active Record pattern. You can create and use Models as follows:

1. Create a new model

node ace make:model Post

2. Configure columns

import { column, BaseModel } from '@ioc:Adonis/Lucid/Orm'
export default class Post extends BaseModel {
@column({ isPrimary: true })
public id: number
@column()
public title: string
@column()
public description: string
}

3. Import and use it inside the controller

import Post from 'App/Models/Post'
export default class PostsController {
public async show({ params }) {
const post = await Post.find(1)
return post
}
}

Render HTML using templates

AdonisJS also ships with a homegrown template engine - "Edge". Edge has support for layouts, partials, conditionals, loops, and a lot more. However, the feature that shines the most is the edge components system.

1. Create a view template

node ace make:view posts/index

2. Write the markup

<div class="article">
<h1> {{ post.title }} </h1>
<p> {{ post.description }} </p>
</div>

3. Render it inside the controller

import Post from 'App/Models/Post'
export default class PostsController {
public async show({ params, view }) {
const post = await Post.find(1)
return view.render('posts/index', { post })
}
}

Authenticate users using the auth package

AdonisJS has a diverse authentication system, covering the needs of both the traditional web apps and the API servers. With the help of guards, you can use sessions based login or create an API token for stateless authentication.

1. Install and configure the auth package

npm i @adonisjs/auth
node ace configure @adonisjs/auth

2. Login users using sessions

export default class AuthController {
public async login({ request, auth, response }) {
const email = request.input('email')
const password = request.input('password')
await auth
.use('web') // 👈 using sessions guard
.attempt(email, password)
response.redirect().toRoute('dashboard')
}
}

3. Generate an API token instead

export default class AuthController {
public async login({ request, auth }) {
const email = request.input('email')
const password = request.input('password')
const token = await auth
.use('api') // 👈 using API guard
.attempt(email, password)
return token
}
}

Validate input using the validator

Consider validators as the first line of defense to protect your application from invalid or missing data.

Requests failing to satisfy the validation rules are redirected back to the form with proper error messages. Otherwise, you can access the validated values with correct data types.

1. Create a validator

node ace make:validator CreatePost

2. Define the validation schema

import { schema, rules } from '@ioc:Adonis/Core/Validator'
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
export default class CreatePostValidator {
constructor (protected ctx: HttpContextContract) {
}
public schema = schema.create({
title: schema.string(),
description: schema.string({}, [
rules.escape()
]),
})
}

3. Validate the request

import CreatePost from 'App/Validators/CreatePostValidator'
export default class PostsController {
public async store({ request }) {
const post = await request.validate(CreatePost)
console.log(post.title)
console.log(post.description)
}
}

Compile assets using webpack encore

At some point in time, you may reach for a CSS framework and might want to sprinkle some JavaScript to make your web apps interactive.

As per the standards today, the CSS and the frontend JavaScript need to be transpiled and minified before serving it to the browser. This bundling process is not that simple, and hence you must use a bundler for it.

AdonisJS pre-configures Webpack (an industry-standard bundler) with sane defaults so that you don't have to waste time adjusting its knobs.

1. Configure webpack encore

node ace configure encore

2. Start the development server

node ace serve --watch
# Serve command starts both
# ✅ The AdonisJS HTTP server
# ✅ And the Webpack dev server

3. Build for production

node ace build --production
# Build commands compile both
# ✅ The AdonisJS Typescript source to JavaScript
# ✅ And the frontend assets using Webpack