Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Controllers

While there are few routes, the code can live right in start/routes.ts. But as the project grows, that file swells. A controller is a class that groups the request handlers for one part of the site, for example blog posts. Each class method handles one route.

Creating a controller

node ace make:controller posts

The file app/controllers/posts_controller.ts appears. The file name is plural and ends with _controller, and the class name is PostsController.

A controller method

Add two methods to the class:

// app/controllers/posts_controller.ts
import type { HttpContext } from '@adonisjs/core/http'
 
export default class PostsController {
  async index({}: HttpContext) {
    return 'List of posts'
  }
 
  async show({ params }: HttpContext) {
    return `Post number ${params.id}`
  }
}

Each method receives the same context object as the function in a route. The HttpContext type tells the editor which fields it has. The empty destructuring in index means this method needs no context fields yet.

Attaching it to a route

Instead of a function, the route gets an array: the controller and the method name.

// start/routes.ts
import router from '@adonisjs/core/services/router'
 
const PostsController = () => import('#controllers/posts_controller')
 
router.get('/posts', [PostsController, 'index']).as('posts.index')
router.get('/posts/:id', [PostsController, 'show']).as('posts.show')

The controller is attached through a function with a dynamic import(). This way the file loads only on the first request to the route, and the server starts faster. Open /posts — you see "List of posts", and /posts/3 shows "Post number 3".

A resource controller

The --resource flag creates a controller with all seven methods: index, create, store, show, edit, update, destroy.

node ace make:controller comments --resource

One line router.resource('comments', CommentsController) attaches it to routes — the address table was in the previous lesson. If you need only some methods, keep part of them:

// start/routes.ts
router.resource('posts', PostsController).only(['index', 'show', 'create', 'store'])

The except method does the opposite — it removes the listed actions.

Single-action controllers

A controller does not have to contain all seven methods. If a controller has one action, name the method handle and attach the class without a method name:

// start/routes.ts
const HomeController = () => import('#controllers/home_controller')
 
router.get('/', [HomeController])

The router calls handle itself.

Common mistake

Importing a controller with a regular line import PostsController from '#controllers/posts_controller' also works, but the editor and the AdonisJS docs recommend the lazy import. With a regular import every start loads all controllers with their dependencies, and an error in one file breaks the whole server. Write const PostsController = () => import('#controllers/posts_controller').

Thanks for reading!

Donate to the site — we work hard for you.