I have been talking about this a little bit with @thetutlage in an issue over in the Discussions repo. One of the only things that I have found clunky and repetitive so far when working with Adonis, compared to the simplicity in the rest of the framework, has been the process of communicating field-related data between the frontend and backend of a project. My suggestion is to establish model field schemas that allow developers to establish a single source of truth for data inputs within an application.
What problem does it solve?
In particular, it eliminates a lot of repetitive copy>pasting and duplication of Indicative rules, messages, and sanitization across multiple validators, but it also allows the potential to simplify the communication with form input on the frontend. Let's take an example of a user's password. In the accounts system for my application I've recently been building, I have the exact same rules, sanitizations, and messages for the password fields for each of the following validators: CancelAccount, ChangePassword, CreateAccount, ResetPassword, UpdateEmail.
I then have to ensure that the field names for the frontend inputs exactly match the key names for each of the fields within those validators. For a few simple forms like managing accounts, copy>pasting may ensure changes to the above validators aren't terribly difficult changes to make. However, it starts to get more complicated as features evolve, forms change, and inputs are moved around an application. It also results with larger applications having a lot of lines of duplicate code spread throughout the project.
Proposal
My suggestion is to have an additional folder added within the App/Models path for Schemas that would operate similarly to the Hooks and Traits classes which are bound in the boot () method (although I'm not sure if Schemas need to be bound). The classes in this Schemas directory would allow the consistent, centralized definition of the input-related data:
class AccountSchema extends ModelSchema {
constructor () {
this.fields = [
'email': {
type: 'email',
label: 'E-Mail',
help: 'E-mail must match the user@domain.com format',
// since attributes vary widely between the various input types,
// we provide an optional object that allows 1:1 mapping in final field output
attrs: [
required: true,
placeholder: 'username@domain.com',
classes: 'form-control'
],
rules: 'required|email|unique:accounts',
sanitization: 'normalize_email|strip_tags'
messages: {
unique: 'That e-mail has already been used.'
}
},
'password': {
type: 'password',
label: 'Password',
attrs: [
required: true,
classes: 'form-control'
],
rules: 'required|min:6',
messages: {
'password.min': 'Password must be at least 6 characters long'
}
}
]
}
}
I would then anticipate that these Schema classes would then have a relatively basic API to fetch field data:
which could be used by Validators something like this:
const AccountSchema = use('App/Models/Schema/AccountSchema')
class ChangeEmailValidator extends Validator {
get schema () {
return AccountSchema.getFields('email', 'password')
}
}
This centralization also comes with an added potential benefit, the creation and usage of Forms could be simplified greatly with the implementation of an additional Form object:
// App/Forms
const AccountSchema = use('App/Models/Schema/Account')
const ProfileSchema = use('App/Models/Schema/Profile')
class SignupForm extends Form {
get form () {
return {
action: 'signup',
method: 'post',
fields: [
...AccountSchema.getFields('email', 'password'),
...ProfileSchema.getFields('firstName', 'lastName')
]
}
}
}
// start/routes.js
Route.on('signup').render('account.signup').form('SignupForm')
Route.post('signup', 'AccountController.signup').validator('SignupValidator')
In the case of the .form('SignupForm'), I would anticipate that the only responsibility here would be that it automatically inserts a form object into the context which the developer would be responsible for choosing how to display/use. A field tag would potentially be useful as an addition to Edge's templating language, but otherwise I think the form output should still be the responsibility of the developer. Also, note, the .form() tag could be just as easily used with SPAs because it's just inserting the form object into the context object:
I am definitely willing to help out with this wherever/however I can. The vast majority of my experience however is in the frontend of applications, so I'm going to expect that someone else could implement it much faster/better than I could.
Brief history
I have been talking about this a little bit with @thetutlage in an issue over in the Discussions repo. One of the only things that I have found clunky and repetitive so far when working with Adonis, compared to the simplicity in the rest of the framework, has been the process of communicating field-related data between the frontend and backend of a project. My suggestion is to establish model field schemas that allow developers to establish a single source of truth for data inputs within an application.
What problem does it solve?
In particular, it eliminates a lot of repetitive copy>pasting and duplication of Indicative rules, messages, and sanitization across multiple validators, but it also allows the potential to simplify the communication with form input on the frontend. Let's take an example of a user's password. In the accounts system for my application I've recently been building, I have the exact same rules, sanitizations, and messages for the password fields for each of the following validators:
CancelAccount
,ChangePassword
,CreateAccount
,ResetPassword
,UpdateEmail
.I then have to ensure that the field names for the frontend inputs exactly match the key names for each of the fields within those validators. For a few simple forms like managing accounts, copy>pasting may ensure changes to the above validators aren't terribly difficult changes to make. However, it starts to get more complicated as features evolve, forms change, and inputs are moved around an application. It also results with larger applications having a lot of lines of duplicate code spread throughout the project.
Proposal
My suggestion is to have an additional folder added within the
App/Models
path forSchemas
that would operate similarly to theHooks
andTraits
classes which are bound in theboot ()
method (although I'm not sure if Schemas need to be bound). The classes in thisSchemas
directory would allow the consistent, centralized definition of the input-related data:I would then anticipate that these Schema classes would then have a relatively basic API to fetch field data:
which could be used by Validators something like this:
This centralization also comes with an added potential benefit, the creation and usage of Forms could be simplified greatly with the implementation of an additional Form object:
In the case of the
.form('SignupForm')
, I would anticipate that the only responsibility here would be that it automatically inserts aform
object into the context which the developer would be responsible for choosing how to display/use. Afield
tag would potentially be useful as an addition to Edge's templating language, but otherwise I think the form output should still be the responsibility of the developer. Also, note, the.form()
tag could be just as easily used with SPAs because it's just inserting the form object into the context object:Are you willing to work on it?
I am definitely willing to help out with this wherever/however I can. The vast majority of my experience however is in the frontend of applications, so I'm going to expect that someone else could implement it much faster/better than I could.