Json RPC request via jquery getJSON - php

I am trying to send json-rpc request to remote server with jquery getJSON method. Here is my code:
json_string=JSON.stringify(obj);
var jqxhr = $.getJSON("https://91.199.226.106/ssljson.php?jsoncallback=?", json_string, function(data){
alert("aaaaaa");
});
jqxhr.error(function() { alert("error"); })
Here is my json-rpc string example:
{"jsonrpc":"2.0","method":"merchant_check","params":[{"hostID":150999,"orderID":116,"amount":"150","currency":"051","mid":15001038,"tid":15531038,"mtpass":"12345","trxnDetails":""}],"id":116}
And here is the error I get:
{"jsonrpc":"2.0","id":null,"error":{"code":-32600,"message":"Invalid JSON-RPC 2.0 request error (-32600)"}}
I can`t get what is the issue. Am I doing something wrong? Maybe I need to send request with php and not jquery? Then how should I do it?

The getJSON as the name say will send GET request if you want to use JSON-RPC you need to use POST like:
var json_string = JSON.stringify(obj);
$.post('https://91.199.226.106/ssljson.php', json_string, function(response) {
// process response
}, 'json');
but this will only work if your page is on the same server, unless you use CORS.

That specific error message is supposed to tell you that the message envelope is invalid per the JSON-RPC 2.0 spec, or that there's a parse error in the JSON itself.
Unfortunately, in practice, many services return this error under a much wider variety of circumstances. (e.g.: missing authentication token, etc)
Specific problems with your example message?
Does the web-service accept GET requests? (i.e: should this be a POST instead?)
Does the web-service actually require the ?jsoncallback=? bit? That's normally for a JSONP request rather than JSON-RPC. The service is returning a real JSON-RPC error status, so I'd be really surprised if it needed that GET parameter, and (depending on the web-service configuration) might be interpreted as part of the envelope, which would make it an invalid JSON-RPC request!
Does merchant_check take an array of one-or-more transactions as its only parameter? If not, then you've got the syntax wrong for params. Some services want params to be an Array, some services want it to be an Object. Consult the SMD/documentation to determine which is the case.
The service might require text/json (or something else) as the mime-type for the request.
Recommended Approach:
To avoid these issues, you should probably start by using a purpose-built JSON-RPC library, like the one provided in Dojo toolkit, and use the SMD published by the web-service if it has one. (I recommend against hand-constructing JSON-RPC messages).

Related

Is it possible to call http API by websocket?

I was asked me to make an api call using websocket with php Ratchet at work. Since I'm totally unfamilier with websocket so I googled and watched youtube videos to solve this problem, but The more I searched, the more I felt it is impossible to call api with websocket.
Am I missing something or is it really impossible to call api by websocket?
If it is possible, can you please show me an example how to do it
I know i might sound awkward since I don't have a solid understanding of websockets, English isn't even my first language, but i'm really desperate please help me
A REST API is fundamentally different from a WebSocket API.
REST API
Calls are made through HTTP(S). You can use AJAX (see here: https://en.wikipedia.org/wiki/Ajax_(programming)) to access HTTP endpoints directly from the browser. In JavaScript you would use the Fetch-API (see here: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) to make calls. Each and every call is stateless per definition. Cookies and special headers must be send with every request to create a context (e.g. user that is logged in).
Example (Client):
fetch('http://example.com/my-rest-api/endpoint1')
.then(response => response.json())
.then(data => console.log(data));
Example (Server):
app.get('/my-rest-api/endpoint1', handlerFunc);
WebSocket API
A stateful connection must be established between a client and a server. The client and server can exchange messages via the connection. Unlike a REST-API messages can be send bidirectional.
A high-level implementation of the WebSocket API is Socket.io.
An API can be designed by defining message types with payloads.
I also would not recommend to use PHP for a WS-API (even though there is a solution like Ratchet). Use a language/runtime that was developed for event-based use cases like this (e.g. nodeJS).
Example (Client):
const socket = SocketClass('example.com/my-websocket-api');
// variant 1 with callbacks
const response = socket.sendMessage('endpoint1', myData);
// variant 2 with message listener
socket.on('endpoint1Response', handlerFunc);
socket.sendMessage('endpoint1', myData);
Example (Server):
const serverSocket = SocketClass('/my-websocket-api');
serverSocket.on('connection', function (socket) {
// variant 1 with callbacks
socket.on('endpoint1', (data, callback) => {
callback(null, responseData);
});
// variant 2 with message listener
socket.on('endpoint1', (data, cb) => {
socket.emit('endpoint1Answer', responseData);
});
});

What's the right way to handle chunked json response with swagger and autogenerated php client?

I'm a bit lost between definitions, generated code and many things that are a bit of a black box, even after debugging.
But let's start at the beginning. I have an API written with node using NestJS as framework. NestJS automatically creates the swagger/openapi json file. Using swagger-codegen I create a PHP class to access the API from another server. Works like a charm for simple API request.
Now the problem are API request returning a bigger response, i.e. >1000 rows from one or more DBs. Do make the client not wait a long time and create a big JSON response on the server I've switched to NDJSON, which splits the reponse in chunks of smaller JSON parts, each on it's own line. This also works when I create my request by hand with curl or a HTTP wrapper in PHP using fopen and fread. The response type is application/x-ndjson.
But the code generated by swagger-codegen is always waiting until the whole response has been received. It's even worse, because it fails to decode NDJSON with json_decode() and just returns null. Underneath Guzzle is used, which uses PSR7 streams for the response.
Now I could just skip the autogenerated code for the NDJSON endpoints. But I'd prefer not to add special handling and lose all the useful generated checks.
So is it somehow possible to make swagger-codegen give access to the stream of the response? Am I missing a parameter to codegen or something in the swagger JSON? It does have a produce with application/x-ndjson.
Do answer my own question it is possible, but not easily - meaning there is no option or parameter.
First create a class that extends the autogenerated API class. There you have access to all of the protected methods. We assume the endpoint or api method is called testMethodGet. The only thing that can be reused is the request method, i.e. testMethodGetRequest, but it does all of the client side validation and transforming of input data, so that's already a big win. Do also get some of the boilerplate result validation you can copy the "http info method", i.e. testMethodGetWithHttpInfo (use async version if you wish). Remove the if/else block after $responseBody = $response->getBody(); and in the return replace the ObjectSearializer line with just $responseBody.
What you are now getting back is the body as PSR7 stream, but there is one last catch. By default the whole response is drained into a temporary file. To really stream the result body from the server in the created method add an option to $options: $options['stream'] = true; Now the method returns as soon as the body is started. No need to wait for the whole body content.
One more thing. As the result is a PSR7 stream you can use $stream->detach() to get the PHP stream resource if you prefer to use the normal file and stream methods.

Laravel forcing json response for api

I'm building an api at my company using laravel.
The problem I'm encountering is that if you send an api request without defining the correct header with the request you will get html back if there is a failure e.g. authorization failure or findOrFail() failure.
My thinking is that you never want to return html (even if the user has the wrong header).
I have a couple of solutions. In BeforeMiddleware.php I can manually insert a header into the request such as:
// Check if we are on an api route
$apiRoute = strncmp($uri, '/api/', 5) == 0;
// Insert the request header to force json response
if ($apiRoute){
$language = $request->header->add('Accept', 'application/json');
}
The 2nd solutions would be to throw an error if they don't have the correct header.
What would be the best way to enforce a json response, what is a good practice for handling api responses in laravel?
Once you detected that you are on your api path you are out of the woods and can indeed tackle your problem in the app\Exceptions\Handler.php file like suggested on How do you force a JSON response on every response in Laravel?.
For an open source project I created JSON exception objects by Microsoft format as output, but you can choose the jsonapi format (http://jsonapi.org/examples/#error-objects-basics) as you like:
https://github.com/StadGent/laravel_site_opening-hours/blob/develop/app/Exceptions/Handler.php
(note that on this implementation it is indeed depending from the headers, but you can use your path detection I think)

Use JSONP without wrapping response

My server outputs this JSON when I put the URI in web browser. My client app will get this JSON using JSONP because it accesses the foreign domain.
{
"is_execution_successful":true,
"data": "something"
}
Is there a way to do a JSONP without wrapping the response like this:
echo $_GET['json_callback']. '('. json_encode($rtnjsonobj) . ')';
I don't have permission to edit the server output. How to get the JSON using AJAX/JQuery?
Reference I read: http://remysharp.com/2007/10/08/what-is-jsonp/
JSONP has technically nothing to do with JSON. It's simply javascript code.
So if the response is valid JSON, it will not do anything useful when you run it as javascript (JSONP). Especially in this case, the JSON causes a syntax error when executed as javascript.
You can make cross-origin ajax request to the resource, but this is only possible if the server sends this header:
Access-Control-Allow-Origin: *
The star can be replaced with your specific origin of course, it doesn't have to be a wildcard

How to get json data coming from another domain?

I want to use the google images api. In the past when I worked with json I simply used the ajax function to get the json from my own server. But now I will be getting it from an external domain:
https://ajax.googleapis.com/ajax/services/search/images?q=fuzzy monkey&v=1.0
Obviously I can't load this using js since its not from an internal url. So in these cases how does one work with json data. Are you supposed to load it via CURL using a server side script or is there another way?
You can make use of JSONP by adding a callback GET param.
https://ajax.googleapis.com/ajax/services/search/images?q=fuzzy%20monkey&v=1.0&callback=hello
Then you can request it with jQuery's $.getJSON().
$.getJSON('https://ajax.googleapis.com/ajax/services/search/images?q=fuzzy%20monkey&v=1.0&callback=?', function(response) {
console.log(response.responseData);
});
jsFiddle.
You must use Cross Origin Resource Sharing (CORS http://en.wikipedia.org/wiki/Cross-Origin_Resource_Sharing)
It's not as complicated as it sounds...simply set your request headers appropriately...in Python it would look like:
self.response.headers.add_header('Access-Control-Allow-Origin', '*');
self.response.headers.add_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
self.response.headers.add_header('Access-Control-Allow-Headers', 'X-Requested-With');
self.response.headers.add_header('Access-Control-Max-Age', '86400');

Categories