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 postsThe 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 --resourceOne 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').