[solved ]mdg:validated-method issue in validation during client simulation

I’m using the following packages:
Validated-Method: https://github.com/meteor/validated-method
SimpleSchema (node version): https://github.com/aldeed/simple-schema-js

When a validation error occurs during client simulation (after calling Meteor.call()), there are two issues I observed:

  1. A console error is reported in the browser:
Exception while simulating the effect of invoking 'business.add' Error: Please input the name of your business
    at modules.js?hash=f9961a6b698e892abfa59a00f79ebf36f4f75ded:3429
    at Array.forEach (<anonymous>)
    at SimpleSchema.validate (modules.js?hash=f9961a6b698e892abfa59a00f79ebf36f4f75ded:3417)
    at MethodInvocation.<anonymous> (modules.js?hash=f9961a6b698e892abfa59a00f79ebf36f4f75ded:3492)
    at ValidatedMethod._execute (validated-method.js:86)
    at MethodInvocation.business.add (validated-method.js:54)
    at DDP._CurrentMethodInvocation.withValue (livedata_connection.js:664)
    at Meteor.EnvironmentVariable.EVp.withValue (meteor.js?hash=0504f43f667698535416b00eb44eb6f53161cb63:1196)
    at Connection.apply (livedata_connection.js:653)
    at Connection.call (livedata_connection.js:556)
  1. The method call continue to execute in the server. Supposedly, validated-method won’t continue the call in the server side because an error happened during the client simulation.

I think the error is with #1 above wherein instead of returning the error, an exception is being logged. Any idea on how to solve this?

Is someone here doing client simulations? or running methods both in client and server?

I tested version 1.8-rc.14, 1.7.0.5, and 1.6.1.4 and got the same results. I also tested both SimpleSchema node version and meteor package and got the same results.

In the end, I am now considering that I might be misunderstanding how the client simulation and meteor method lifecycle works

My high-level understanding of the “client simulation” is that the calls are done in parallel at both the client and server and then Meteor tries to consolidate the results and invalidate the client if it conflicts with the server. The motivation behind this design is to support optimistic UI updates.

So I think in your case, the server did update, but the client fails due to an exception.

That was also how I understand it before. Another forum member posted about validated-method and his post made me read the documentation again until I saw the part about Meteor Method lifecyle: https://guide.meteor.com/methods.html#call-lifecycle

If an exception is thrown from the Method simulation, then by default Meteor ignores it and continues to step (2). If you are using ValidatedMethod or pass a special throwStubExceptions option to Meteor.apply , then an exception thrown from the simulation will stop the server-side Method from running at all.

I am not using Optimistic UI so I was not using methods in the client. But I realized, the input validation can save a trip to server if the ValidatedMethod calls can stop the server method for running as indicated in the docs. So I tried it and I was trying to run it the entire day and I am getting the exception but the server call is still being done

Hmm interesting, I’m using Validated-Method with SimpleSchema, and I had few bad input passed to those methods but as far as I can recall, the server didn’t run and an error was thrown at the client.

I’ll give this a test.

So I just did a quick test by passing invalid param, and the error was thrown at the client and nothing ran on the server. I’ve everything wrapped with isServer block. Here is the error I got:

Error: About must be of type String
    at modules.js?hash=c8e7bff3d9282566837585ea8b761f89dfb84c99:132292
    at Array.forEach (<anonymous>)
    at SimpleSchema.validate (modules.js?hash=c8e7bff3d9282566837585ea8b761f89dfb84c99:132280)
    at MethodInvocation.<anonymous> (modules.js?hash=c8e7bff3d9282566837585ea8b761f89dfb84c99:132355)
    at ValidatedMethod._execute (validated-method.js:86)
    at MethodInvocation.updateProfile (validated-method.js:54)
    at DDP._CurrentMethodInvocation.withValue (livedata_connection.js:664)
    at Meteor.EnvironmentVariable.EVp.withValue (meteor.js?hash=0504f43f667698535416b00eb44eb6f53161cb63:1196)
    at Connection.apply (livedata_connection.js:653)
    at ValidatedMethod.call (validated-method.js:67)

But I think in your case the error is being generated in the this.isSimulation block and not the SimpleSchema? maybe it helps to share how are you actually using the validated method.

Thanks for testing. Glad to know that it is working as expected so the mistake is in my implementation.

Initially, I also thought it was working. But just to test that no server validation is happening, I changed the messages using Meteor.isServer and I got a different exception message in the browser and another different validation error message through my default error handler suggesting it comes from the server.

Here a sample method: note that validator() is just a mixin that creates a new SimpleSchema().validator() call

new ValidatedMethod({
        name: 'business.add',
        validate: validator(
            {
                name: {
                    type: String,
                    optional: !Meteor.isServer
                },
                contactNumber: {
                    type: String,
                    regEx: /^((\+?639|09)\d{9})|((\+?63|0)\d{8,9})|\d{7}$/,
                    optional: true
                },
                description: {
                    type: String
                },
                url: {
                    type: String,
                    optional: true
                }
            },
            {
                required: {
                    name: `Please input the name of your business ${
                        Meteor.isServer ? 'server' : 'client'
                    }`
                },
                regEx: 'Please input the correct format for {{label}}'
            }
        ),
        run(params) {
            const { name, contactNumber, description, url } = params;
            accessCheck({ userId: this.userId });

            if (Meteor.isServer) {
                const businessId = createBusiness(
                    name,
                    this.userId,
                    contactNumber,
                    description,
                    url
                );

                const storeId = createStore(
                    'Main Business',
                    businessId
                );

                return {
                    businessId,
                    storeId
                };
            }

            return null;
        }
    })

Comparing your error message, the start of your call is this:

Mine was this:

Seems like I’m doing something wrong here

Aha that’s what I guessed, let us see if that solves it.

1 Like

Oh, I think I got it. I am still using Meteor.call() :worried:

Hopefully, that’s it.

2 Likes

It did. Thanks, bro. I can sleep now. Thank you, thank you, thank you

1 Like

Glad it worked :smile: cheers!

1 Like

One thing you need to be mindful of when using import for validated method is that the method code will get bundled to the client. So I usually use Meteor.call for sensitive logic or when the method has a heavy NPM dependency, in addition to using dynamic imports to keep the bundle size small.

Thanks for this heads up. I’ve started to encounter issues with npm packages and my own code meant for server only. Currently, I’m separating the schema and the run() functions are empty in client since I’m only interested with validation.

I’m to test later my code structure for cases when I need to implement optimistic ui where publications are used

1 Like