Tips for AdonisJs.

AdonisJs is a Laravel like to the javascript mvc land, so right away you’ll feel at home.

If you are into trying something new or you havent swam into the js mvc frameworks world yet give Adonis A Chance.

  • below are just some tips i found that could help make the experience slightly more pleasant.
  • new stuff gets added as i learn more about it.

Routes.js

instead of bloating the ‘route.js’ file with all ur routes logic, lets separate them into smaller files which will increase our code maintainability & quality, same as we did with laravel here

# Op.1

1- create a new folder “Routes” inside your “app/Http
2- inside the newly created folder, create files according to each route ex.User, Post, Stuff, etc… and add ur route logic as normal
3- inside the “routes.js” require those files

require('./Routes/User');
require('./Routes/Post');
// etc ...

# Op.2

1- create a new folder “routes” at the “root” of your project
2- inside the newly created folder, create files according to each route ex.User, Post, Stuff, etc… and add ur route logic as normal
3- install https://www.npmjs.com/package/require-all

$ npm install --save require-all
# or
$ yarn add require-all

4- inside the “routes.js” add

'use strict';

require('require-all')(use('Helpers').basePath() + '/routes');

5- open “package.json” and add “--watch routes” so any changes gets updated without stopping the server

"dev": "nodemon --watch app --watch bootstrap --watch routes --watch config --watch .env -x node server.js",

 


Models

instead of duplicating the logic across the models, lets create a ‘BaseModel‘ which will have all of our shared code and if we still want something in specific then we can add it to the model itself as usual.

1- create a new file “BaseModel.js” inside “app/Http/Model” and add

'use strict';

const Lucid = use('Lucid');

class BaseModel extends Lucid {
  // ...
}

module.exports = BaseModel;

2- make other models extend it instead of “Lucid

'use strict';

const BaseModel = use('App/Model/BaseModel');

class User extends BaseModel {
  // ...
}

module.exports = User;

3- now we can share any logic we want across all models, like

// BaseModel.js
static * first() {
  return yield this.query().pick(1);
}

// and call it like
const User = use('App/Model/User');
const result = yield User.first();

 


Macros

Adonis have a very flexible macros system that can truly make your experience much more enjoyable. for example,
let say you want to validate some data before sending it to the db.

1- lets add the validation logic

// inside your controller

* store(request, response) {

  let data = request.all();

  const rules = {
      email: 'required|email|unique:users,email',
      password: 'required|min:6'
  };

  const validation = yield Validator.validateAll(data, rules)

  if (validation.fails()) {
      yield request.withAll().andWith({ errors: validation.messages() }).flash()
      response.redirect('back')
  }

  // save data to db
}

2- but wouldn’t it be better if we could just write

const validation = yield Validator.validateAll(data, rules)

// validate & redirect back if there was an error
yield response.validate(request, validation)

// otherwise continue

3- so lets add our new macro in app/Listeners/Http.js under Http.onStart

Response.macro('validate', function(request, validation) {
  const self = this;
  return function*() {
    if (validation.fails()) {
      yield request.withAll().andWith({ errors: validation.messages() }).flash()
      self.redirect('back')
    }
  }
})

 


Validation

It works mostly the same as it does in Laravel except for one thing, currently you either need to add a custom validation message like

const messages = {
  required: 'This field is required to complete the registration process.'
  'username.required' : 'Username is required to continue',
}

or Adonis will fall back to the hard coded default of

{{validation}} validation failed on {{field}}.

so to tackle that while keeping the validation dynamic especially when using a multi-lang app, i came up with a better solution which use a file to contain all the validation messages and it works according to the current locale, exactly as it is in laravel.

And so to keep this as easy as possible & avoid duplication just like Models lets create a ‘BaseController

1- create a new file “BaseController.js” inside “app/Http/Controllers” and add

'use strict'

const Config = use('Config')
const Helpers = use('Helpers')
const Validator = use('Validator')

class BaseController {

  /**
   * return the validation messages from the rules file according
   * to the current locale or if no file found then return
   * the default Adonis messages
   *
   * you can find the validation file with all the currently supported
   * validation rules @ https://github.com/ctf0/adonis-validation-messages
   */
  validationMessages() {
    const fs = require('fs');
    const locale = Config.get('app.locales.locale')
    const validaitonFile = Helpers.resourcesPath(`locales/${locale}/validation.json`)

    if (fs.existsSync(validaitonFile)) {
      return JSON.parse(fs.readFileSync(validaitonFile, 'utf8'));
    }

    return {};
  }

  /**
   * automatically validate request data and flash back
   * old input + validation messages if any
   */
  validate(request, response, rules, messages) {
    messages = Object.assign(this.validationMessages(), messages)

    const validation = yield Validator.validateAll(request.all(), rules, messages);

    if (validation.fails()) {
      yield this.validationFailed(request, response, validation)
    }
  }
}

module.exports = BaseController

2- make other controllers extend it

'use strict';

const BaseController = use('App/Http/Controllers/BaseController')

class PostController extends BaseController {

  // ...

  * store(request, response) {

    const rules = {
      // ...
    }

    // redir back with validation messages & old input
    yield this.validate(request, response, rules);

    // otherwise save data
  }
}

module.exports = PostController;
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s