moleculerjs / moleculer

:rocket: Progressive microservices framework for Node.js
https://moleculer.services/
MIT License
6.16k stars 587 forks source link

Can define ACTION return value validator ? #397

Closed roytan883 closed 6 years ago

roytan883 commented 6 years ago

Is your feature request related to a problem? Please describe. Can define ACTION return value validator

Describe the solution you'd like Just like the params validator, like this:

returns: {
  uids: {
    type: "array", empty: false, items: {
      type: "string", empty: false, min: 10
    },
  },
  mtype: { type: "string", optional: true },
},
xynon commented 6 years ago

I want that too and for some actions it's a really nice feature - so I wrote my own validator middleware because of that and my issue on #395.

So I do the following (moleculer 0.13.3)

const { ServiceBroker, Errors, Validator } = require('moleculer');

class CustomValidator extends Validator {
  middleware() {
    return function validatorMiddleware(handler, action) {
      let checkParams = null;
      let checkReturns = null;

      if (action.params && typeof action.params === "object") {
        checkParams = this.compile(action.params);
      }
      if (action.returns && typeof action.returns === "object") {
        checkReturns = this.compile(action.returns);
      }

      if (checkParams || checkReturns) {
        return function validateContextParams(ctx) {
          let result = true;
          if (checkParams) {
            result = checkParams(ctx.params);
          }

          if (result === true) {
            return handler(ctx).then((returns) => {
              if (checkReturns) {
                result = checkReturns(returns);
                if (result === true) {
                  return returns;
                }
                result.forEach((data) => { data.actionName = action.name });
                return Promise.reject(new Errors.ValidationError("Resturns validation error!", null, result));
              }
              return returns;
            });
          }
          result.forEach((data) => { data.actionName = action.name });
          return Promise.reject(new Errors.ValidationError("Parameters validation error!", null, result));
        };
      }
      return handler;
    }.bind(this);
  }
}

now I can use them in the broker options

broker = new ServiceBroker({ 
  ...  
  validator: new CustomValidator(), 
  ...
})

But beware the option of action.returns will don't be parse clear on the service create. Like the action.params does. So there just pass through the options so they are raw like you set them in your actions and will be pass in the validator middleware to the fastest-validator.

roytan883 commented 6 years ago

@xynon Nice solution.

@icebob I'm curious why the official returns validator is missing? Any especial reason?

icebob commented 6 years ago

I didn't think it is a necessary function, because the same service generates and validate the response. E.g. if I write an action which adds two number and returns a number I know it will return a number, plus you can check it with tests. The validation will be executed locally after the response is generated by action.

The "input params" are different because it could come from other unknown services or from user inputs and often need to validate them.

roytan883 commented 6 years ago

@icebob It's reasonable for personal development. But for teamwork, other people created some micro service, if there is no INPUT and RETURN definition at the begining, hard for team cooperation. Can't expect everyone read others ACTION source code to know the result format. Especially, JavaScript can have vary format of result, add RETURN validator will somehow avoid some bug by developer mistake returned unexpected result format.

icebob commented 6 years ago

As you can see, very easy to implement it as a custom middleware (thanks for @xynon). Moleculer can be expanded very well, so I don't want to add every feature to the core module. Instead, we need to create an awesome collection and collects these useful middlewares and mixins.