moleculerjs / moleculer

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

Internal services pass `fastest-validator` param schemas to custom validator #1094

Open keawade opened 2 years ago

keawade commented 2 years ago

Prerequisites

Please answer the following questions for yourself before submitting an issue.

Current Behavior

Custom validators are passed fastest-validator schemas by the Moleculer internal services.

Expected Behavior

I would expect the Moleculer internal services to handle their own validation and not rely on my custom validator implementation.

Failure Information

Steps to Reproduce

Please provide detailed steps for reproducing the issue.

  1. Define a custom validator
  2. Create a ServiceBroker with the custom validator
  3. Observe internal services actions passing fastest-validator param schemas to the custom validator

Reproduce code snippet

const { ServiceBroker, Validators, Errors } = require("moleculer");
const Ajv = require("ajv");
const addFormats = require("ajv-formats");

class JsonSchemaValidator extends Validators.Base {
  constructor() {
    super();
    this.validator = new Ajv({
      /**
       * This is the default configuration but can be changed to 'log' to log
       * errors instead of throwing which may be more convenient while debugging
       */
      strict: true
    });
    addFormats(this.validator);
  }

  compile(schema) {
    const validate = this.validator.compile(schema);

    return (params) => {
      const result = validate(params);

      if (validate.errors) {
        throw new Errors.ValidationError(
          "Parameters validation error!",
          null,
          this.validator.errors
        );
      }

      return result;
    };
  }

  validate(params, schema) {
    const result = this.validator.validate(schema, params);

    if (this.validator.errors) {
      throw new Errors.ValidationError(
        "Parameters validation error!",
        null,
        this.validator.errors
      );
    }

    return result;
  }
}

/**
 * Custom validator throws errors out of this location when attempting to
 * compile default `fastest-validator` schemas that are passed to it by
 * Moleculer's internal services actions.
 */
const broker = new ServiceBroker({ validator: new JsonSchemaValidator() });

broker.createService({
  name: "greeter",
  actions: {
    hello: {
      params: {
        type: 'object',
        required: [],
        additionalProperties: false,
        properties: {
          name: { type: 'string' },
        },
      },
      handler(ctx) {
        return `Hello ${ctx.params.name || "Moleculer"}!`;
      },
    },
  },
});

broker.start().then(() => {
  setInterval(() => {
    broker
      .call("greeter.hello", { name: "CodeSandbox" })
      .then((res) => broker.logger.info(res))
      .catch((err) => broker.logger.error(err.message));
  }, 1000);
});

Context

Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions.

Failure Logs

When using default strict: true Ajv configuration.

[2022-05-26T14:15:37.819Z] INFO  my-machine-10438/BROKER: Moleculer v0.14.21 is starting...
[2022-05-26T14:15:37.820Z] INFO  my-machine-10438/BROKER: Namespace: <not defined>
[2022-05-26T14:15:37.820Z] INFO  my-machine-10438/BROKER: Node ID: my-machine-10438
[2022-05-26T14:15:37.821Z] INFO  my-machine-10438/REGISTRY: Strategy: RoundRobinStrategy
[2022-05-26T14:15:37.821Z] INFO  my-machine-10438/REGISTRY: Discoverer: LocalDiscoverer
[2022-05-26T14:15:37.822Z] INFO  my-machine-10438/BROKER: Serializer: JSONSerializer
[2022-05-26T14:15:37.822Z] INFO  my-machine-10438/BROKER: Validator: JsonSchemaValidator
[2022-05-26T14:15:37.823Z] INFO  my-machine-10438/BROKER: Registered 13 middleware(s).
[2022-05-26T14:15:37.844Z] FATAL my-machine-10438/BROKER: Unable to create ServiceBroker. Error: strict mode: unknown keyword: "withServices"
    at checkStrictMode (/Users/keawade/Code/demo/node_modules/ajv/dist/compile/util.js:174:15)
    at checkUnknownRules (/Users/keawade/Code/demo/node_modules/ajv/dist/compile/util.js:32:13)
    at checkKeywords (/Users/keawade/Code/demo/node_modules/ajv/dist/compile/validate/index.js:120:34)
    at validateFunctionCode (/Users/keawade/Code/demo/node_modules/ajv/dist/compile/validate/index.js:19:9)
    at Ajv.compileSchema (/Users/keawade/Code/demo/node_modules/ajv/dist/compile/index.js:80:45)
    at Ajv._compileSchemaEnv (/Users/keawade/Code/demo/node_modules/ajv/dist/core.js:472:37)
    at Ajv.compile (/Users/keawade/Code/demo/node_modules/ajv/dist/core.js:159:38)
    at JsonSchemaValidator.compile (/Users/keawade/Code/demo/foo.js:19:37)
    at ServiceBroker.validatorMiddleware (/Users/keawade/Code/demo/node_modules/moleculer/src/validators/base.js:78:25)
    at /Users/keawade/Code/demo/node_modules/moleculer/src/middleware.js:67:15

When using the strict: 'log' configuration so you can see all the unknown keyword errors emitted.

[2022-05-26T14:17:32.356Z] INFO  my-machine-10581/BROKER: Moleculer v0.14.21 is starting...
[2022-05-26T14:17:32.356Z] INFO  my-machine-10581/BROKER: Namespace: <not defined>
[2022-05-26T14:17:32.356Z] INFO  my-machine-10581/BROKER: Node ID: my-machine-10581
[2022-05-26T14:17:32.357Z] INFO  my-machine-10581/REGISTRY: Strategy: RoundRobinStrategy
[2022-05-26T14:17:32.357Z] INFO  my-machine-10581/REGISTRY: Discoverer: LocalDiscoverer
[2022-05-26T14:17:32.358Z] INFO  my-machine-10581/BROKER: Serializer: JSONSerializer
[2022-05-26T14:17:32.358Z] INFO  my-machine-10581/BROKER: Validator: JsonSchemaValidator
[2022-05-26T14:17:32.359Z] INFO  my-machine-10581/BROKER: Registered 13 middleware(s).
strict mode: unknown keyword: "withServices"
strict mode: unknown keyword: "onlyAvailable"
strict mode: unknown keyword: "onlyLocal"
strict mode: unknown keyword: "skipInternal"
strict mode: unknown keyword: "withActions"
strict mode: unknown keyword: "withEvents"
strict mode: unknown keyword: "onlyAvailable"
strict mode: unknown keyword: "grouping"
strict mode: unknown keyword: "onlyLocal"
strict mode: unknown keyword: "skipInternal"
strict mode: unknown keyword: "withEndpoints"
strict mode: unknown keyword: "onlyAvailable"
strict mode: unknown keyword: "onlyLocal"
strict mode: unknown keyword: "skipInternal"
strict mode: unknown keyword: "withEndpoints"
strict mode: unknown keyword: "onlyAvailable"
strict mode: unknown keyword: "types"
strict mode: unknown keyword: "includes"
strict mode: unknown keyword: "excludes"
[2022-05-26T14:17:32.385Z] INFO  my-machine-10581/REGISTRY: '$node' service is registered.
[2022-05-26T14:17:32.385Z] INFO  my-machine-10581/REGISTRY: 'greeter' service is registered.
[2022-05-26T14:17:32.386Z] INFO  my-machine-10581/$NODE: Service '$node' started.
[2022-05-26T14:17:32.386Z] INFO  my-machine-10581/GREETER: Service 'greeter' started.
[2022-05-26T14:17:32.386Z] INFO  my-machine-10581/BROKER: ✔ ServiceBroker with 2 service(s) started successfully in 3ms.
[2022-05-26T14:17:33.387Z] INFO  my-machine-10581/BROKER: Hello CodeSandbox!
[2022-05-26T14:17:34.387Z] INFO  my-machine-10581/BROKER: Hello CodeSandbox!
[2022-05-26T14:17:35.388Z] INFO  my-machine-10581/BROKER: Hello CodeSandbox!
[2022-05-26T14:17:36.390Z] INFO  my-machine-10581/BROKER: Hello CodeSandbox!
^C[2022-05-26T14:17:37.352Z] INFO  my-machine-10581/$NODE: Service '$node' stopped.
[2022-05-26T14:17:37.352Z] INFO  my-machine-10581/GREETER: Service 'greeter' stopped.
[2022-05-26T14:17:37.352Z] INFO  my-machine-10581/BROKER: ServiceBroker is stopped. Good bye.
pibi commented 2 years ago

Here at https://github.com/pibi/moleculer-json-schema-validator we are using an explicit jsonSchema property to work around that. Regular schema is handled by fastest-validator as a fallback.

Unfortunately, this module does not work with 0.14.21 (see issue #1106).