You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@thrift.apache.org by Jayku <ja...@gmail.com> on 2016/07/14 15:33:26 UTC

Thrift JS .write is not a function

Hey Guys,

I encountered a strange problem using JSONProtocol, where I get "someObject.
*write* is not a function" error when I send a JSON payload using Thrift JS
client library.
Thrift CPP server excepts a Struct whose fields are optional.

I somehow got reference to this post
http://stackoverflow.com/questions/21416438/convert-json-to-thrift-object-in-nodejs
which
is the same problem I deal with. I Couldn't understand what the proposed
solution in this stack overflow post.

Can someone please help me out?

Thanks,
Jay.

Re: Thrift JS .write is not a function

Posted by Benjamin Tousley <be...@fiscalnote.com>.
Randy and Thrift folks,
  TL; DR - While I understand this is a requirement in other languages
where Thrift structs are proper classes, I wonder if it is a good idea to
handle this IDL object "casting" within Thrift, at least for the Javascript
autogenerated code.  Read on for explanation why...

  Sorry to revive a somewhat old thread, but I also recently discovered
this error when using the Node.js generated Thrift implementation for a few
services I own.  The issue was because I was passing a JSON object as an
argument to the Thrift client, as in:

> var userInfo = {sess: {thing1: "a", thing2: "b"}};
> thriftClient.sampleFunc(userInfo);


rather than an instance of the type defined in my .idl as in:

> thriftClient.sampleFunc(new commonTypes.UserInfo(userInfo));

(commonTypes was the name of the required generated file with the UserInfo
struct type and all of its dependent nested struct types.)

The nested JSON object does not have the read/write functions, whereas the
instance of UserInfo gets read() and write() from its generated prototype.
That may help Jayku with his problem, however I'd like to question whether
this should be a hard requirement.

I dug into the autogenerated code and found that service function _args
structs already support casting an object argument to its proper Thrift
type:

> Example.ExampleService_sampleFunc_args = function(args) {
>   this.userInfo = null;
>   if (args) {
>     if (args.userInfo !== undefined && args.userInfo !== null) {
>       *this.userInfo = new common_ttypes.UserInfo(args.userInfo);*
>     }

...
>   }
> };

UserInfo's constructor, in turn, supports the same casting for each of its
nested structs, recursively as deep as necessary.
However, the service function's send_sampleFunc for some reason does not
use the constructor args.  It just does this:

> Example.ExampleServiceClient.prototype.send_sampleFunc =
> function(userInfo) {
> ...
>   var args = new Example.ExampleService_sampleFunc_args();
>   args.userInfo = userInfo;
>   args.write(output);
> ...
> };

And the userInfo arg misses out on its opportunity to be casted to the
required Thrift type.  It crashes when userInfo.write() is called within
args.write().  Is there a particular reason that I haven't thought of that
the above snippet of code is not instead:

> var args = new Example.ExampleService_sampleFunc_args({
>     userInfo : userInfo
> });

It does not appear, in fact, that
the ExampleService_sampleFunc_args() constructor is ever called with
arguments, meaning that the if (args) block is useless code - but its
existence implies that somebody wanted it to be usable in this way.  With
this change, then the initial

> var userInfo = {sess: {thing1: "a", thing2: "b"}};
> thriftClient.sampleFunc(userInfo);

would work fine.  It requires a very simple change to  t_js_generator.cc to
do this and appears to work fine in at least my usecase when I recompiled
it in my local thrift install.

The added benefit to this change, and the reason why I ran into it at
first, is that it allows a Thrift service handler to take the arguments it
was passed (which are set up as Thrift types in the process_*'s args.read()
functions), add nested struct fields to it (e.g. userInfo.added is an
optional struct that the handler receives as null, but then creates as an
object and assigns to userInfo's 'added' field), and then pass it as an
argument to *another* Thrift client function, without having to explicitly
instantiate each such new nested struct.  I was attempting this in a
pass-through API Gateway using Thrift on both sides.

To be clear, I know the current solution is to do 'new
IDLType(nestedStruct)' for each field, but I wonder if Thrift's Javascript
autogenerated code might by improved by the above change, to make it a bit
easier and more intuitive for developers.

Thoughts?  Is this worthy of a pull-request to Thrift?  Or let me know what
I'm missing.

Thanks,
Ben

On Thu, Jul 14, 2016 at 2:51 PM, Jayku <ja...@gmail.com> wrote:

> Thanks Randy.  The type is already in the IDL,  but I still get that
> error.  May be I am missing something else.  I will relook at it.
>
> On Thu, Jul 14, 2016, 22:09 Randy Abernethy <ra...@apache.org> wrote:
>
> > Greetings Jay,
> >
> > Put simply: Apache Thrift can only send/receive IDL based objects, so you
> > should never pass parameters or return results that are not defined in
> IDL.
> >
> > IDL objects have read() and write() methods that self serialize, the JSON
> > protocol tries to call these methods on any objects it needs to transmit.
> > If these methods do not exist the error you received is produced.
> >
> > Solution: define the type you want to send/receive in IDL and then use
> that
> > type.
> >
> > -Randy
> >
> > On Thu, Jul 14, 2016 at 8:33 AM, Jayku <ja...@gmail.com> wrote:
> >
> > > Hey Guys,
> > >
> > > I encountered a strange problem using JSONProtocol, where I get
> > > "someObject.
> > > *write* is not a function" error when I send a JSON payload using
> Thrift
> > JS
> > > client library.
> > > Thrift CPP server excepts a Struct whose fields are optional.
> > >
> > > I somehow got reference to this post
> > >
> > >
> > http://stackoverflow.com/questions/21416438/convert-
> json-to-thrift-object-in-nodejs
> > > which
> > > is the same problem I deal with. I Couldn't understand what the
> proposed
> > > solution in this stack overflow post.
> > >
> > > Can someone please help me out?
> > >
> > > Thanks,
> > > Jay.
> > >
> >
>



-- 
*Benjamin Tousley* | Software Engineer
*FiscalNote <http://www.fiscalnote.com/> *| We're hiring!
<https://www.fiscalnote.com/careers/>

Re: Thrift JS .write is not a function

Posted by Jayku <ja...@gmail.com>.
Thanks Randy.  The type is already in the IDL,  but I still get that
error.  May be I am missing something else.  I will relook at it.

On Thu, Jul 14, 2016, 22:09 Randy Abernethy <ra...@apache.org> wrote:

> Greetings Jay,
>
> Put simply: Apache Thrift can only send/receive IDL based objects, so you
> should never pass parameters or return results that are not defined in IDL.
>
> IDL objects have read() and write() methods that self serialize, the JSON
> protocol tries to call these methods on any objects it needs to transmit.
> If these methods do not exist the error you received is produced.
>
> Solution: define the type you want to send/receive in IDL and then use that
> type.
>
> -Randy
>
> On Thu, Jul 14, 2016 at 8:33 AM, Jayku <ja...@gmail.com> wrote:
>
> > Hey Guys,
> >
> > I encountered a strange problem using JSONProtocol, where I get
> > "someObject.
> > *write* is not a function" error when I send a JSON payload using Thrift
> JS
> > client library.
> > Thrift CPP server excepts a Struct whose fields are optional.
> >
> > I somehow got reference to this post
> >
> >
> http://stackoverflow.com/questions/21416438/convert-json-to-thrift-object-in-nodejs
> > which
> > is the same problem I deal with. I Couldn't understand what the proposed
> > solution in this stack overflow post.
> >
> > Can someone please help me out?
> >
> > Thanks,
> > Jay.
> >
>

Re: Thrift JS .write is not a function

Posted by Randy Abernethy <ra...@apache.org>.
Greetings Jay,

Put simply: Apache Thrift can only send/receive IDL based objects, so you
should never pass parameters or return results that are not defined in IDL.

IDL objects have read() and write() methods that self serialize, the JSON
protocol tries to call these methods on any objects it needs to transmit.
If these methods do not exist the error you received is produced.

Solution: define the type you want to send/receive in IDL and then use that
type.

-Randy

On Thu, Jul 14, 2016 at 8:33 AM, Jayku <ja...@gmail.com> wrote:

> Hey Guys,
>
> I encountered a strange problem using JSONProtocol, where I get
> "someObject.
> *write* is not a function" error when I send a JSON payload using Thrift JS
> client library.
> Thrift CPP server excepts a Struct whose fields are optional.
>
> I somehow got reference to this post
>
> http://stackoverflow.com/questions/21416438/convert-json-to-thrift-object-in-nodejs
> which
> is the same problem I deal with. I Couldn't understand what the proposed
> solution in this stack overflow post.
>
> Can someone please help me out?
>
> Thanks,
> Jay.
>