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.

Published
Jan 31
Duration
4m 52s

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

Join The Discussion! (10 Comments)

Please sign in or sign up for free to join in on the dicussion.

  1. Commented 4 months ago

    Hi,

    When I save routes.ts file, imports remain identical. Do we have to do anything to make it work?

    1

    Please sign in or sign up for free to reply

    1. Commented 4 months ago

      Hi Jean!

      The standard import for controllers will work just fine, for example

      import MoviesController from '#controllers/movies_controller'
      Copied!

      However, mine changed to lazy style imports on save within the video due to the ESLint I set up and configured code actions for within VS Code in lesson 1.4 of this series.

      Below is an example of the ESLint rule error that's auto-fixed by my code action configuration when I save my routes.ts file.

      ESLint is completely optional! It essentially is a style guide for your code, and anything not matching the style guide will display an ESLint error.

      If you'd like to use it, you can install the ESLint extension within VS Code. Then, you can have it auto-fix ESLint errors by adding the below within your VS Code settings.json

      "editor.codeActionsOnSave": {
        "source.fixAll.eslint": "explicit"
      } 
      Copied!
      1

      Please sign in or sign up for free to reply

      1. Commented 4 months ago

        For mystical reasons, I missed that part. Sorry :D

        By the way, the new version of Adocasts is cool.

        1

        Please sign in or sign up for free to reply

        1. Commented 4 months ago

          No worries at all, Jean!! :D

          Thank you, I really appreciate that!!

          0

          Please sign in or sign up for free to reply

  2. Commented 3 months ago

    Hi Tom!

    I'm trying to inject the context into a controller, and it is not working:

    import type { HttpContext } from '@adonisjs/core/http'
    import { inject } from '@adonisjs/core'
    
    @inject()
    export default class JoinController {
      ctx: HttpContext
    
      constructor(ctx: HttpContext) {
        this.ctx = ctx
      }
    }

    I got this error message:

    Cannot inject "[Function: Object]" in "[class JoinController]

    Sorry about the massive font lol. It looks like in the docs but does not work. Any ideas?

    1

    Please sign in or sign up for free to reply

    1. Commented 3 months ago

      Hey frp! When a route calls a controller's method as its handler the HttpContext is automatically provided as their first parameter, so you shouldn't need to inject the context into a controller.

      That said, somewhere Harminder Virk explained this well, but I can't seem to find it. The error though is because the HttpContext can't be bound in this context. If you were to bind it to a service, and then bind the service to your controller, all would work.

      export default class MoviesController {
        async index(ctx: HttpContext) { // <--
          return ctx.view.render('pages/home')
        }
      }
      Copied!

      Here's an example of binding the HttpContext to a service and then the service to a controller.

      
      
      import { HttpContext } from '@adonisjs/core/http'
      import { inject } from '@adonisjs/core'
      
      @inject()
      export default class MovieService {
        constructor(public ctx: HttpContext) {}
      }
      Copied!
      • app
      • services
      • movie_service.ts
      
      
      import type { HttpContext } from '@adonisjs/core/http'
      import Movie from '#models/movie'
      import { inject } from '@adonisjs/core'
      import MovieService from '../services/movie_service.js'
      
      @inject()
      export default class MoviesController {
        constructor(protected movieService: MovieService) {}
      
        async index({ request, view }: HttpContext) {
          console.log(request.url())
          console.log(this.movieService.ctx.request.url())
          return view.render('pages/home')
        }
      }
      Copied!
      • app
      • controllers
      • movies_controller.ts
      0

      Please sign in or sign up for free to reply

      1. Commented 3 months ago

        Ok thanks. That might do what I want just as well.

        0

        Please sign in or sign up for free to reply

        1. Commented 3 months ago

          Anytime! Yeah, most of the time, I like to offload most of my business logic into services, keeping controllers clean to just handle the request flow.

          0

          Please sign in or sign up for free to reply

  3. Commented 1 month ago

    Hello Master.

    When I try to make a request via the api, the message "Connection was refused by the server." is being returned.

    I changed the origin to '*'(config/cors.ts), but unfortunately I was unsuccessful.

    Access via http (brownser) works perfectly, but via rest api does not.

    0

    Please sign in or sign up for free to reply

    1. Commented 1 month ago

      Hi Gabriel! Unfortunately, there isn't a straightforward answer here with the given information. Are your API requests being sent from inside your application or via a REST client? It sounds like your application works a-okay, your environment is just having issues connecting to it. This could be due to firewall settings or even WSL vs Non-WSL, if you're on Windows. Or, you may just need to use 0.0.0.0 instead of localhost if you're using a REST client.

      0

      Please sign in or sign up for free to reply