Validation maintaining status in requests

Asked

Viewed 45 times

1

I created an express server and a class to structure my validation errors. This is how it is:

function Error() {
  this.anyError = false
  this.errors = {}
}

Error.prototype.addError = function (attr, error) {
  this.anyError = true
  this.errors[attr] = error
}

module.exports = new Error()

Then in the validation classes I use this module like this:

const validator = require("validator")
const Error = require("./error")

function validateCustomer(body) {
  let helper = Error

  if ( ! validator.isEmail(body.email)) {
    helper.addError("email", "Invalid email.")
  }
  if ( ! validator.isLength(body.document, {min: 14, max: 14})) {
    helper.addError("document", "Invalid document.")
  }
  if ( ! validator.isLength(body.social_name, {min: 5})) {
    helper.addError("social_name", "Invalid social name, minimal length is 5.")
  }
  if ( ! validator.isMobilePhone(body.contact_phone, 'pt-BR')) {
    helper.addError("contact_phone", "Invalid mobile phone.")
  }

  return {
    invalid: helper.anyError,
    errors: helper.errors
  }
}

module.exports = {
  customerValidator: validateCustomer
}

The route is as follows:

router.post('/', [verifyAdmin, function(req, res) {
  if(req.body) {
    let validation = customerValidator(req.body.customer)
    if (validation.invalid) {
      return res.status(200).json({errors: validation.errors, status: 'invalid'})
    }
    // encripta a senha
    const newCustomer = new Customers(req.body.customer)
    newCustomer.encripted_password = customerCript(newCustomer.encripted_password)
    newCustomer
      .save()
      .then(function(customer) {
        delete customer.encripted_password
        res.status(201).json({message: 'record created successfully', customer})
      })
      .catch(function(error){
        res.status(500).json({error})
      })
  } else {
    return status(500).json({error: 'body not found'})
  }
}])

Every time I submit something that is not valid it falls right in the validation, but once I tidy up the data is as if the validation is persistent on the server.

Surely I’ve done something wrong with regard to require, scope and etc. Could you please help me?

  • 2

    If I were you, I’d use a different name than Error for its function, since so you are overwriting the Error native Javascript. Maybe you already know this. Just a note. :)

  • @Luizfelipe knew no! Thank you

  • 2

    :) I forgot to mention in the other comment... Could you include in your question the code of your route in express? Probably the app.post...

  • @Luizfelipe Feito!

1 answer

3


TL;DR: Your problem boils down in your module Error, using a Singleton.


The problem arises in the fact that you are using a pattern called Singleton (learn more in this excellent video of Waldemar Neto). To understand, let’s review the code:

PS: I omitted the implementation - irrelevant in this context.

function Error() {
}

Error.prototype.addError = function (attr, error) {
}

// Note abaixo que uma única instância será exportada por este módulo.
//               ↓↓↓
module.exports = new Error()

As pointed out by the comment, this module will always export the same instance of Error. This means that the class will be instantiated the first time you import the module and from there, in all subsequent imports the exported value will be that same instance.

In this context, this approach brings several problems, since you are reusing the same instance of this validation mechanism throughout the application. This means that all requisitions share this instance, so errors will accumulate with each new validation.

This happens because of the cache that Node.js uses to import modules using Commonjs (require et al.).

Therefore, the simplest way to fix the problem is simply not to use Singleton:

function Error() {
}

Error.prototype.addError = function (attr, error) {
}

// Note agora que estamos exportando a classe. Isso assegurará que
// a sua instanciação seja realizada a cada requisição.
module.exports = Error

And always create a new instance for each request (in your case, within the method validateCustomer, that is called to each request.

const Error = require('./Error')

function validateCustomer(body) {
  // Note abaixo que estamos criando uma nova instância das sua
  // classe de validação sempre que a função `validateCustomer`
  // for chamada, isto é, a cada requisição. Isso resolve o seu problemas. :)
  let helper = new Error()

  // Condições omitidas.

  return {
    invalid: helper.anyError,
    errors: helper.errors
  }
}

Again, I strongly recommend that you see the video mentioned earlier. Without it, I would not even have been able to draw up this answer. :)

Other related resources:


And just to emphasize: I strongly suggest that you use a name other than Error for your class. As I have already mentioned in comments, when using the name Error, you are overwriting the Error javascript native.

Also, as you are using a new version of Ecmascript, think that you should use the syntax of classes for maybe facilitate:

// Note que já está com um nome diferente de `Error`. :)
class ErrorHelper {
  constructor() {
    this.anyError = false
    this.errors = {}
  }

  addError(attr, error) {
    this.anyError = true
    this.errors[attr] = error
  }
}

module.exports = ErrorHelper
  • 1

    Great example :D

  • @Waldemarneto already watched your video, everything worked out.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.