tedeh / jayson Goto Github PK
View Code? Open in Web Editor NEWJayson is a simple but featureful JSON-RPC 2.0/1.0 client and server for node.js
Home Page: https://jayson.tedeh.net
License: MIT License
Jayson is a simple but featureful JSON-RPC 2.0/1.0 client and server for node.js
Home Page: https://jayson.tedeh.net
License: MIT License
Hi there. I need a JSON-RPC connection where the TCP server is the RPC client and vice versa. Basically, this means I want to create a JSON-RPC server around a WebSocket object in the browser. Can I do this with jayson or any other JSON-RPC library you know of? Right now the only way I'm finding to do this would be to manually invoke the middleware function, but I'm not sure how to prepare the request and response objects to do that, and there's no point figuring out how to make that work if there's an easier way.
Thanks. :)
Hello
I wonder if you could make https protocol supported, it doesn't seem to be supported.
Given this simple test.js which tries to connect to a https JSON server:
'use strict';
var jayson = require('jayson');
var client = jayson.client.http('https://mywebsite.com/api/');
client.request('test1', ['value1', 'value2'], function (error, value) {
if(error) {
console.log(error);
}
else {
console.log(value);
}
});
I get this response:
http.js:1821
throw new Error('Protocol:' + options.protocol + ' not supported.');
^
Error: Protocol:https: not supported.
at Object.exports.request (http.js:1821:11)
at /Users/angel/Documents/cloud_manager/server/node_modules/jayson/lib/client/http.js:50:20
at Object.Utils.JSON.stringify (/Users/angel/Documents/cloud_manager/server/node_modules/jayson/lib/utils.js:340:3)
at HttpClient._request (/Users/angel/Documents/cloud_manager/server/node_modules/jayson/lib/client/http.js:37:14)
at Client.request (/Users/angel/Documents/cloud_manager/server/node_modules/jayson/lib/client.js:107:8)
at Object.<anonymous> (/Users/angel/Documents/cloud_manager/server/test.js:8:8)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
node v0.10.15
jayson v1.0.10
I am new to NodeJS and I cannot work out how to enable it in your code. Thanks!
In PromiseMethod
the test is: wasPromised = promise instanceof Promise;
.
This does not work when using babel
and ES7 async
promises.
Instead we should just test for if ("then" in promise)
...
I've noticed an inconsistency between classes name and the documentation for the respective classes:
Class Name | Documented As |
---|---|
HttpClient |
ClientHttp |
HttpServer |
ServerHttp |
HttpsClient |
ClientHttps |
HttpsServer |
ServerHttps |
TcpServer |
ServerTcp |
Example: TcpServer
& ServerTcp
TcpClient
does not follow this convention:
Class Name | Documented As |
---|---|
TcpClient |
TcpClient |
I think they should all be like the TcpClient
(documentation name matching class name) but would like to run it by you before you take my tls-support PR so I can follow the proper documentation naming convention.
When using collect: false
to not collect parameters into a single argument, if no parameters are supplied the error TypeError: Cannot read property 'length' of undefined
is raised due to a length check on params which is null.
The JSON RPC 2.0 spec (here) says that params
may be omitted.
/Users/mike/git/project/node_modules/jayson/lib/method.js:130
if(handler.length !== (params.length + 1)) {
^
TypeError: Cannot read property 'length' of undefined
at Method.execute (/Users/mike/git/project/node_modules/jayson/lib/method.js:130:32)
at /Users/mike/git/project/node_modules/jayson/lib/server/index.js:294:12
at maybeParse (/Users/mike/git/project/node_modules/jayson/lib/server/index.js:411:5)
at Server.call (/Users/mike/git/project/node_modules/jayson/lib/server/index.js:237:3)
at /Users/mike/git/project/node_modules/jayson/lib/utils.js:189:14
at /Users/mike/git/project/node_modules/jayson/node_modules/lodash/index.js:7173:25
at /Users/mike/git/project/node_modules/jayson/lib/utils.js:162:7
at Object.Utils.JSON.parse (/Users/mike/git/project/node_modules/jayson/lib/utils.js:284:3)
at IncomingMessage.<anonymous> (/Users/mike/git/project/node_modules/jayson/lib/utils.js:160:16)
at emitNone (events.js:80:13)
Hey,
While named parameters might be a good feature for some people, they should not be the responsibility of a JSON-RPC library. Named parameters are a different concern and don't belong to the session layer.
Hey,
Have you thought of allowing dynamic methods on the server? Methods that are not predefined as they are now but rather resolved dynamically by the user's code? That would make it easier to delegate to preexisting objects and handle larger API more conveniently.
Something like:
function handler(name) {
obj[name].apply(obj, Array.prototype.slice.call(arguments, 1))
}
handler.has = function(name) { return typeof obj[name] == "function" }
Jayson.server(handler)
JSON-RPC supports TCP transport as of 2.0 so it would be good if it is supported in this library as well.
The server chokes when it doesn't get the right number of arguments. For example, say you have a very simple server that defines an add
method:
var jayson = require("jayson");
var server = jayson.server({
add: function(a, b, callback) {
callback(null, a + b);
},
});
server.http().listen(3000);
Using the CLI we can send it a request with the wrong number of parameters:
jayson -u http://localhost:3000 -m add -p [1]
Th result is that the server throws an unhandled exception, and then eventually the client dies because of a closed TCP connection.
$ jayson -u http://localhost:3000 -m add -p [1]
-> add(1)
<- Error: socket hang up
at createHangUpError (http.js:1472:15)
at Socket.socketOnEnd [as onend] (http.js:1568:23)
at Socket.g (events.js:180:16)
at Socket.EventEmitter.emit (events.js:117:20)
at _stream_readable.js:920:16
at process._tickCallback (node.js:415:13)
$ node simpleserver.js
.../simpleserver.js:6
callback(null, a + b);
^
TypeError: undefined is not a function
at jayson.server.add (.../simpleserver.js:6:5)
at Method.execute (.../node_modules/jayson/lib/method.js:124:20)
at .../node_modules/jayson/lib/server.js:284:12
at maybeParse (.../node_modules/jayson/lib/server.js:401:5)
at Server.call (.../node_modules/jayson/lib/server.js:229:3)
at .../node_modules/jayson/lib/utils.js:180:14
at .../node_modules/jayson/node_modules/lodash/index.js:7173:25
at .../node_modules/jayson/lib/utils.js:153:7
at Object.Utils.JSON.parse (.../node_modules/jayson/lib/utils.js:273:3)
at IncomingMessage.<anonymous> (.../node_modules/jayson/lib/utils.js:151:16)
Shouldn't it handle this and return an error to the client?
Hey,
I noticed that when the server crashes in the response
event handler, the client's callback is still called, just without the response
argument. But because notification requests also call the callback without the response
argument, it's kind of hard to distinguish an error condition from the normal case. Not to mention there should be an error given to the callback when this happens.
If I want to set a cookie with a req/res, is the best option to use the middleware approach with Express/Connect? I tried out using Express, but the cookie was only written if my middleware module came before the Jayson middleware. Unfortunately, the data I need to write into the cookie is retrieved in the method of the request. Any way to access the headers on the raw response?
I've looked through the tests, the examples, and the documentation, and there's nothing specified about how to use the error
argument of the callback.
Through trial and error I've narrowed it down to this:
callback({ code: CODE, message: MESSAGE });
Where CODE
is a numerical code like -32602 and MESSAGE
is an arbitrary string. Omitting MESSAGE
causes a { code: -32603, message: 'Internal error' }
to be returned instead.
Adding a simple example for handling errors would go a long ways towards resolving this ambiguity. All the calls I found were callback(null, ...)
.
The latest published version 1.2.0
does not contain the TLS support added in #47. Can a new version be published?
"POST / HTTP/1.1 Content-Length: 90 Content-Type: application/json Accept: application/json Host: 127.0.0.1:9040 Connection: keep-alive {"method":"hello","jsonrpc":"2.0","params":[],"id":"2cf4c22b-453d-4b0a-92ee-6566ede19403"}"
POST / HTTP/1.1 Content-Length: 90 Content-Type: application/json Accept: application/json Host: 127.0.0.1:9040 Connection: keep-alive
I don't want bold part.
I don't know if I'm not able to find or it can't be changed.
Please let me know how to fix this behavior.
-Yash
I'm trying to use Jayson with Express library, but there is no any example of it. Can you add it to examples directory?
In the client library, when jayson got error: null response it assumes request returned an error because it only checks if typeof(res.error) !== 'undefined'. Another thing is I don't see in the code any id of response validation, etc.
The jayson server returns Content-Type
header application/json
with utf-8
body
Some http clients default to ISO_8859_1
as default charset which cause issues
The specs seem to be a bit unclear on this:
http://stackoverflow.com/questions/2325571/for-http-responses-with-content-types-suggesting-character-data-which-charset-s
As far as I know the JSON-RPC spec has no specific charset defined.
In any case I think it would not be bad to explicitly set Content-Type
to application/json; charset=utf-8
(or the encoding defined in the options)
I am using Jayson to authenticate with a JSON-RPC service, where I need to get the first server responses' set-cookie header and set it in subsequent requests headers. Something like this:
client.request('Tinebase.login', [username, password], function(err, error, result) {
if(err) throw err;
console.log(result);
client.options.headers = client.options.headers || {};
client.options.headers[ 'X-Tine20-JsonKey' ] = result['jsonKey']; // Set http.client.headers for subsequent requests
client.options.headers[ 'cookie' ] = result.headers[ 'set-cookie' ]; // access headers of the reponse object
});
for this to work I patched lib/client/http.js. I wanted to ask you if you can provide headers or apply the patch in Jayson source?
If I use named function when create a server, e.g.:
var server = jayson.server({
add: function add( a, b, callback ) {
callback( null, a + b );
}
});
it does not work, b/c method Utils.getParameterNames
in lib/utils.js
has incorrect RegExp for this case. May be you change this regex to something like this /^function [\w\d]+\((.+?)\)/
. Thanks.
According to this: http://nodejs.org/api/http.html#http_request_settimeout_timeout_callback
http sockets are automatically closed after 120 seconds of inactivity by default, how is it possible to send an http RPC request throught jayson with any desired timeout (more than 120 seconds of course)
I used:
this.rpcClient = jayson.client.http({
port: port,
hostname: ip
});
this.rpcClient.on('http request', function(req){
req.setTimeout(VALUE) ;
});
but did not work for me
\jayson\lib\client\http.js line : 38
utils.JSON.stringify(request, options, function(err, body) {
if(err) return callback(null, str);
what is the second param (str) of callback used for?
Hello,
First, thanks for your wonderfull work.
I'm trying to have a both communication point from Golang (client - serv) and Node (with your lib) (client serv)
When I try from my program in Go to call 127.0.0.1 3000 (because I'm running the node server on local). I got the following message ๐
[{"jsonrpc":"2.0","id":null,"error":{"code":-32600,"message":"Invalid request"}},{"jsonrpc":"2.0","id":null,"error":{"code":-32600,"message":"Invalid request"}}]
Have you any doc that could allow me to bind a valid request because for now I just send to the server (in json) an array of int like =>
[10, 10]
The server code =>
// create a server
var server = jayson.server({
add: function(args, callback) {
callback(null, args[0] + args[1]);
}
});
server.tcp().listen(3000);
Client code in go =>
var reply int
conn, err := net.Dial("tcp", r.Client[0].Addr)
if err != nil {
fmt.Println(err)
return
}
defer conn.Close()
c := jsonrpc.NewClient(conn)
err = c.Call("add", []int{10, 10}, &reply)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("Add: %d", reply)
Thank you :)
For now, it is possible to transfer parameters in an Array. The dictionary should be the first object in this array.
client.request('somemethod', [{"param1","param1_value"}], function(err, error, response) {
if(err) throw err;
});
Is it possible to make the following feasible?
client.request('somemethod', {"param1","param1_value"}, function(err, error, response) {
if(err) throw err;
});
As per specifications jsonrpcx, it would be interesting to add an example of how to implement an authentication system.
It would be very welcome also the possibility to manage the methods as middleware, in order to separate the layer of validation from the rest of the method.
Hey!
I'm using the promise-based interface and I'm having some troubles logging exceptions my methods throw. Currently I have to .then my own promise in every method in order to log a potential exception. What do you think of a callback property on the server object that gets called whenever a method "throws" an exception?
Can I access to the client information when server function is called (e.g. client IP-address)?
Thanks.
var server = jayson.server({
some: function(callback) {
// client info need here
callback();
}
});
Currently the requests will never timeout if the server didn't respond. After getting stream object, call req.timeout:
This is from http.js, line 51:
var req = self._getStream(options);
Just add this after it:
req.setTimeout(10000, function(){callback(new Error('timeout'));});
How I can use "Callback syntactic sugar" with 3 arguments? I'd tested it by
callback( null, {'code': 100, 'message': "Some error"}, null );
but it does not work right, it returns error object in result
field.
Thanks)
Hey,
I don't have time to currently jump into this, but on Node v0.11.11 I'm getting Error: This socket has been ended by the other party
on the server side when ccf9a8e is applied.
var credentials = {
key: fs.readFileSync('./certs/key.pem'),
cert: fs.readFileSync('./certs/cert.crt'),
ca: fs.readFileSync('./certs/intermediate.crt')
};
server.https(credentials).listen(8000);
That doesn't work. Please update your documentation to describe the proper way to support HTTPS
Hi,
How to access request object from inside the called method on server.
I use jayson with expressjs as middleware . I need to access request object for security and session info.
Hi,
When I wrote to the tcp server with some string not a JSON format, it didn't respond me an 'Parse Error', but the server crashed with 'Error: Unexpected "a" at position 0 in state START'.
The error was thrown from jsonparse
module, but unhandled in Utils.parseStream
I fix this with the fellowing code, more details in the comment.
Utils.parseStream = function(stream, options, onRequest) {
var result = JSONStream.parse();
stream.pipe(result);
result.on('data', function(data) {
// apply reviver walk function to prevent stringify/parse again
if(typeof(options.reviver) === 'function') {
data = Utils.walk({'': data}, '', options.reviver);
}
onRequest(null, data);
});
// the jsonparse module always parse until buffer end,
// because the thrown error has passed to JSONStream stream emit,
// it never stop while parsing error.
// e.g.
// if buffer is 'abc', it will emit error three times:
// Unexpected "a" at position 0 in state START
// Unexpected "b" at position 1 in state START
// Unexpected "c" at position 2 in state START
//
// add a errored flag to prevent onRequest error from calling more than once
var errored = false;
result.on('error', function(err) {
if (!errored) {
onRequest(err);
errored = true;
}
});
};
I'm not sure it is graceful, so I just submit a issue not pr. Hope you fix it in a better way.
Hi,
I can't find a way to writeHead and send a cookie to the client. I've tryied by using connect() and use a security module before using the jayson module, but when I call res.writeHead('myheaders') and call next() to let jayson do its job, I get this exception :
_http_outgoing.js:331
throw new Error('Can\'t set headers after they are sent.');
I'm wondering how you protect against a situation where an RPC supplies more arguments than the target function's signature defines...
e.g
function TargetFunc(arg1, arg2, arg3, callback)
{ "jsonrpc": "2.0", "method": "TargetFunc", "params": [ "arg1", "arg2", "arg3", "arg4" ], "id":1 }
In the above example, callback
will be populated with "arg4"
and the real callback object will not be accessible.
This means it's difficult to report "too many arguments were supplied" (or indeed anything at all) to the RPC consumer.
Thanks
Hi, could you update the changelog to the latest version?
Let's say this is my rpc server.
var jayson = require('jayson');
var server = jayson.server({
add: function(a, b, callback) {
callback(null, a + b);
}
});
server.http().listen(3000);
If I were to have a client post this:
{"jsonrpc":"2.0","method":"add","params":[1, 2]}
That would work correctly and I would get back 3
.
But if I make a simple mistake like this:
{"jsonrpc":"2.0","method":"add","params":[]}
This will always throw a fatal error and crash the server.
What I would expect to be correct behavior is that a
and b
should become set to undefined
because they weren't passed as params. That would be okay... worst case scenario you get a nonsensical response back like null
because that's the result of undefined + undefined
. But what actually happens is: b
and callback
become undefined
and a
becomes the callback function.
So when the callback
is called you get a Fatal error message telling you undefined
is not a function, and the server crashes.
There is an absolutely ridiculous way to get around it, and at least keep the server running.
var jayson = require('jayson');
var server = jayson.server({
add: function(a, b, callback) {
if (typeof a === 'function') {
callback = a;
a = undefined;
}
if (typeof b === 'function') {
callback = b;
b = undefined;
}
callback(null, a+b);
}
});
server.http().listen(3000);
I've looked through your module a little bit. I've also looked at other json-rpc modules on npm and I have to say, code clarity wise yours is by far the best. So ๐ to you!
I would like to make a fork and do a pull request to address this issue. Do you see this as an actual issue? Or is this the intended behavior. As long as I'm running my server as a daemon which restarts when it fails, I'm not really too concerned about it. But yeah I kind of see it as a bad thing to have a simple typo or mistake in the request payload cause a server crash.
A simple circular reference will respond with an error, refering to https://github.com/tedeh/jayson/blob/master/lib/utils.js#L295-L299
Could we leverage something like https://github.com/isaacs/json-stringify-safe to send a valid JSON response regardless of circular references in the response?
I have a short patch to lib/utils.js that enables Jayson to support CORS requests.
It allows requestHeaders to be added to responses and supports requests with the HTTP OPTIONS methods.
I am a bit of a GITHUB newbie, so I am open to the best approach to submitting the patch if the project is open to receiving them.
With my changes CORS requests can be enabled by doing the following in server code:
var server = jayson.server({/* json rpc implementation*/});
var allowCors = {"Access-Control-Allow-Origin":"*", "Access-Control-Allow-Headers": "Origin, X-Requested-With, Content-Type, Accept"};
server.http( allowCors ).listen( 3000 );
Thank you,
Rob
Hey,
Having \"
show up in the request JSON kills Utils.parseBody
which seems to be a hand-rolled JSON parser. That in turn hangs the connection.
Thanks for sharing your code, but seriously, dude, don't reinvent wheels. And if you do, make sure you have tests for it. ;-)
The CLI currently only supports unix domain socket servers and http servers, but not TCP servers.
I want to be able to access debug information about a response. Currently whatever I return from the handler must be what will be the reply. To work around it I must make my results into objects and attach an info
property, and then in the server.call
callback I must filter this from being sent.
server.call(message, (error, success, info) => {
}
Maybe adding an info field to the callback as above would resolve this?
I think the more generic concept to enable this functionality would be to allow middleware in the request/response flow like Express/Koa.
Use the tcp connection is a good way to have a two-way socket, with which you can go about taking an open connection.
After the fix to issue #41 was inserted "_.once()" on this line.
Is there a particular reason for this?
Removing "_.once()" the server responds to subsequent calls while keeping the same connection.
I noticed that the event is handled "error" of tcp socket. If this is not done the error arrives at global "uncaughtException" of process.
I added this to fix the problem:
function getTcpListener(self, server) {
return function(conn) {
var options = self.options || {};
conn.on('error', function() {
conn.end();
});
...
I opened an issue because I don't know if these are appropriate fix.
Great module, saved me a lot of time!
.
.
var jsonrpc = require('jayson');
var rpc = jsonrpc.client.http({
host: 'http://www.mywebsite.com/api/',
port: 80
});
rpc.request('ping', [], function(err, response) {
if (err)
console.log("RPC Error: ", err);
// request was received successfully
console.log("From RPC: ", response);
});
.
.
Above request was throwing following error,
RPC Error: { [Error: getaddrinfo EADDRINFO] code: 'EADDRINFO', errno: 'EADDRINFO', syscall: 'getaddrinfo' }
Can you provide an example of how to use the CLI? I just keep getting errors with regard to how to pass parameters.
Hey,
I tried to pass es6 class instead of function - I've got
TypeError: Class constructor GetMethod cannot be invoked without 'new'
It happened because Method.prototype.execute
expects that a handler is a function (it just calls it and replaces a context). I've checked why it does not work properly for my code and I found this:
https://github.com/tedeh/jayson/blob/master/lib/method.js#L120
First problem for me is that it overrides my context - if I use for handling a class which inherits prototype from any abstract class, it also overrides this prototype.
For example, I have the handler defined this way:
var AbstractMethod = function () {
this.randomprop = 'kex';
}
var AbstractMethod = require('./AbstractMethod.js');
var GetMethod = function (args, callback) {
AbstractMethod.call(this);
console.log('GetMethod', this);
// prints "GetMethod { jayson server props }"
this.test(callback);
//TypeError: this.test is not a function (because prototype was replaced by 'call' in #120)
};
GetMethod.prototype = Object.create(AbstractMethod.prototype);
GetMethod.prototype.test = function (callback) {
console.log('test/callback')
callback(null, 'ok')
}
Changing lib/method.js#120
from
return handler.call(server, params, callback);
to
return new handler(server, params, callback);
solves my problem, but it's not good solution for people who currently use it. server
object is available in the constructor (I can use it if I want and drop if I don't need it), my this
context is not affected and it creates an instance when class is defined with class
operator.
What do you think about new options (for es6 support with backward compatibility), for example:
es6_classes_support
- enables possbility to pass es6 class as handlerrewrite_context
- rewrites context of handler (true
as default, because it currently works this way)Of course, I can make a PR, but I want to know what do you think about it. It's ~20 lines of code.
Best Regards
Hi,
i have problem with this line:
/node_modules/jayson/lib/server/middleware.js
// 405 method not allowed if not POST
if(!utils.isMethod(req, 'POST')) return error(405, { 'allow': 'POST' });
Can u make small new version, with something like this ?
if (options.allowGet) {
if(!utils.isMethod(req, 'POST') && !utils.isMethod(req, 'GET')) return error(405, { 'allow': 'POST or GET' });
} else {
if(!utils.isMethod(req, 'POST')) return error(405, { 'allow': 'POST' });
}
Hi there, Is it possible for you to explain how to add a websocket based json rpc v2 layer.
Thanks in advance.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.