senecajs / seneca-transport

Seneca micro-services message transport over TCP and HTTP.
MIT License
63 stars 45 forks source link

Impossible to send regular expression because of JSON stringify #130

Closed ChrisTerBeke closed 5 years ago

ChrisTerBeke commented 8 years ago

Because data is transported as stringified JSON and parsed again at the other end, it's impossible to send a regular expression from one service to another. Since we need this functionality, we have basically used the following snippets to make it work:

// this function extracts flags from a regular expression
RegExp.prototype.flags = function () {
    return (this.ignoreCase ? "i" : "")
        + (this.multiline ? "m" : "")
        + (this.global ? "g" : "");
};

// serialize RegEx before sending through Seneca Transport
for (var i in conditions) {
    if (conditions[i] instanceof RegExp)
        conditions[i] = {
            regex: true,
            pattern: conditions[i].source,
            flags: conditions[i].flags()
        };
}
for (var i in args.conditions) {
    if (typeof args.conditions[i] == 'object' && args.conditions[i] !== null && args.conditions[i].regex)
        args.conditions[i] = new RegExp(args.conditions[i].pattern, args.conditions[i].flags);
}

In this example, conditions is an object with our custom data that we add to the transported arguments.

It would be great if this (or similar) behaviour would be implemented in the TCP/HTTP transport itself as it is quite useful for microservices that use for example Mongoose to query a database, where the original request comes from a gateway service (we use https://github.com/mguella/generic-query-parser to parse HTTP query params into a Mongoose find query).

Let me know what you think!

ChrisTerBeke commented 8 years ago

I've changed my implementation on the client side to the follow the 'middleware' pattern:

// parse regular expressions before calling real handler
// function handler need to call this.prior to use it
seneca.add({ role: plugin, cmd: '*' }, function (args, next) {
    for (var i in args.conditions) {
        if (typeof args.conditions[i] == 'object' && args.conditions[i] !== null && args.conditions[i].regex)
            args.conditions[i] = new RegExp(args.conditions[i].pattern, args.conditions[i].flags);
    }
    return next(null, args);
});

seneca.add({ role: plugin, cmd: 'find' }, function (args, cb) {
    this.prior(args, function(err, args) {
        // args now contains a correct regular expression
    });
}

This is already better than my initial solution, but still doesn't feel right...

mcdonnelldean commented 8 years ago

@ChrisTerBeke This is a limitation on purpose. If you wanted to override it would be best to make custom transports.

ChrisTerBeke commented 8 years ago

OK thanks for your reply. I'll probably fork the TCP transport then.

mcdonnelldean commented 8 years ago

Sounds good! Let us know if you need any help

Kindest Regards,

Dean

On 7 Sep 2016, at 09:29, ChrisTerBeke notifications@github.com<mailto:notifications@github.com> wrote:

OK thanks for your reply. I'll probably fork the TCP transport then.

You are receiving this because you commented. Reply to this email directly, view it on GitHubhttps://github.com/senecajs/seneca-transport/issues/130#issuecomment-245211550, or mute the threadhttps://github.com/notifications/unsubscribe-auth/ADdT6W0WfsWHPfzZGkXacucNhUzZsHexks5qnnXlgaJpZM4J2Kjq.

vladholubiev commented 8 years ago

@mcdonnelldean The same situation is with Date objects. So you suggest creating something like seneca-transport-preserve-date ?

oliversturm commented 7 years ago

I'm just finding myself in the same situation, where messages with Date fields are not transferred correctly. I understand the approach using priors, but I find that somewhat painful because the implementation must be aware of potential priors. Creating a transport derivation seems a bit over the top as well... wouldn't it be possibly to simply add support for the JSON.parse reviver option? I could easily pass in a reviver when I initialize the transport, just like I do for bodyParser with express.

Oliver

rjrodger commented 5 years ago

JSON itself does not really support instantiated objects like Date and RegExp - you should instead serialize yourself - https://stackoverflow.com/questions/4511705/how-to-parse-json-to-receive-a-date-object-in-javascript