moleculerjs / moleculer-web

:earth_africa: Official API Gateway service for Moleculer framework
http://moleculer.services/docs/moleculer-web.html
MIT License
292 stars 120 forks source link

setting $$strict=true for params should work with nested objects #314

Closed ekellstrand closed 2 years ago

ekellstrand commented 2 years ago

Consider the following action definition. Take note of:

createLocation: {
    auth: 'required',
    params: {
        $$strict: true  
        alias: { type: 'string' },
        address: {
            type: 'object',
            props: {
                address1: { type: 'string', optional: true },
                city: { type: 'string', optional: true },
            },
            optional: true,
        }
    }
    async handler(ctx: Context<Record<string, unknown>, ClientMeta>) {/* doSomethingLogical() */}
}

Now call this service with the following payload

{
  "alias": "InCoherent Developer's Palace",
  "address": {
    "address1": "42 Somewhere Path",
    "I_DONT_REMEMBER_HOW_TO_SPELL_CITY": "Why does this value get silently dropped and not stored in my database??  I set $$strict=true so I would get politely told to bugger off and go fix my typo",
  },
}

$$strict seems work great for top level params. (ie, If I added "I_DONT_REMEMBER_HOW_TO_SPELL_ALIAS" at the top level, right under "alias" in my payload, validation correctly rejects it). It's only when I define an object that I see this problem.

ps. Thx for your efforts. I really enjoy working with Moleculer!

Edit: Sorry, Let me give you the software version details..

OS                      : Windows 10
NodeJS                  : 16.15.0 
moleculer               : ^0.14.21
moleculer-web           : ^0.10.4
moleculer-decorators    : ^1.3.0
moleculer-http-client   : ^0.4.2
moleculer-io            : ^2.0.0

I tested with Chrome 104.0.5112.102 & Postman 9.28.2

ColinFrick commented 2 years ago

Does it work if you add strict: true to the address definition? See https://github.com/icebob/fastest-validator#properties-10

ekellstrand commented 2 years ago

@ColinFrick Yes! Interesting... Adding "$$strict:true" to the address definition did not work. Adding "strict:true" to the address definition, with out the dollar signs, did work.

I'll have to check and see if I should be using "strict:true" everywhere now instead of "$$strict:true".

ColinFrick commented 2 years ago

@ekellstrand top level is $$strict. Otherwise you wouldn’t be able to add a parameter with the name strict. See https://github.com/icebob/fastest-validator#strict-validation

ekellstrand commented 2 years ago

OK, so that gets me going. @ColinFrick

ColinFrick commented 2 years ago

$$strict is only evaluated for the root schema. As far as I can tell it is the same behavior as if you have nested objects, children don't inherit the strict property from their parent either.

If you always want strict: true for object validator you can set it by default: https://github.com/icebob/fastest-validator#default-options https://moleculer.services/docs/0.14/validating.html#Fastest-Validator (Example with options)

I only can tell you what's in the documentation, maybe @icebob can tell you more.

ekellstrand commented 2 years ago

@ColinFrick Thank you for pointing me at the docs. The default values are new since I set this all up a few years back. I think docs are good and I'm going to close this out as "RTFM Success".

Related question: It looks like the default options handles any nested objects. Do you know if there is any config setting to handle the top level $$strict: true as a default for all actions? or is my existing Middleware function still the best bet for that? (I re-read both sets of docs but didn't see anything)

icebob commented 2 years ago

Hi, @ColinFrick's explanation is right, no inheritance in properties, every property is evaluated on the given level and not affect the nested levels.

If you would like to add strict: true for every object rule, set it as a default option as Colin mentioned. You can do it in broker options, like:

// moleculer.config.js

module.exports = {
    validator: {
        type: "Fastest",
        options: {
            useNewCustomCheckerFunction: true,
            defaults: {
                object: {
                    strict: true
                }
            }
        }
    }
};
ekellstrand commented 2 years ago

Thanks! Closing this as RTFM.