js function calling an api doesn't respond with expected values - javascript

I am trying to collect all the market pairs from a crypto exchange using its API, but I'm not sure how to select the proper line in the JSON object as it does not seem to work.
the api : https://ftx.com/api/markets
my code :
requests.js
import axios from 'axios';
import parsers from './parsers';
async function ftxMarkets() {
const ftxResponse = await axios.get('https://ftx.com/api/markets');
return parsers.ftxMarkets(ftxResponse.data);
}
parsers.js
function ftxMarkets(data) {
const [ftxMarketPairs] = data;
let ftxPairs = data.map(d => d.name );
console.log(ftxPairs);
};
I'm not sure about d.name in the parsers.js file, but I tried with another exchange with the same code, changing just that part and it worked, so I guess that's where the problem comes from, although can't be sure and I don't know by what to replace it.
Thanks

I ran the api call and after looking at the response I see a result key with the list of all crypto data. So I am guessing it'll work if you call the parser with the result object like this
return parsers.ftxMarkets(ftxResponse.result);
// try parsers.ftxMarkets(ftxResponse.data.result) if the above one doesnt work
and then in the parser it should work normally
function ftxMarkets(data) {
let ftxPairs = data.map(d => d.name );
console.log(ftxPairs);
};
Update:
Since fxtResponse.data.result works. Your issue should be a CORS issue and to fix that there are two options.
CORS plugin in web browser(not recommended in production)
Proxy it through a server. By requesting the resource through a proxy - The simplest way, what you can do is, write a small node server (or if you already have a back-end associate it with your front-end you can use it) which does the request for the 3rd party API and sends back the response. And in that server response now you can allow cross-origin header.
For 2 If you already have a nodeJs server. You can use CORs Npm package and call the third party api from the server and serve the request to the front end with CORS enabled.

Related

Is it possible to link a random html site with node javascript?

Is it possible to link a random site with node.js, when I say that, Is it possible to link it with only a URL, if not then I'm guessing it's having the file.html inside the javascript directory. I really wanna know if it's possible because the html is not mine and I can't add the line of code to link it with js that goes something like (not 100% sure) <src = file.html>
I tried doing document = require('./page.html'); and ('./page') but it didn't work and when I removed the .html at the end of require it would say module not found
My keypoint is that the site shows player count on some servers, and I wanna get that number by linking it with js and then using it in some code which I have the code to (tested in inspect element console) but I don't know how to link it properly to JS.
If you wanna take a look at the site here it is: https://portal.srbultras.info/#servers
If you have any ideas how to link a stranger's html with js, i'd really appreciate to hear it!
You cannot require HTML files unless you use something like Webpack with html-loader, but even in this case you can only require local files. What you can do, however, is to send an HTTP Request to the website. This way you get the same HTML your browser receives whenever you open a webpage. After that you will have to parse the HTML in order to get the data you need. The jsdom package can be used for both steps:
const { JSDOM } = require('jsdom');
JSDOM.fromURL('https://portal.srbultras.info/')
.then(({ window: { document }}) => {
const servers = Array.from(
document.querySelectorAll('#servers tbody>tr')
).map(({ children }) => {
const name = children[3].textContent;
const [ip, port] = children[4]
.firstElementChild
.textContent
.split(':');
const [playersnum, maxplayers] = children[5]
.lastChild
.textContent
.split('/')
.map(n => Number.parseInt(n));
return { name, ip, port, playersnum, maxplayers };
});
console.log(servers);
/* Your code here */
});
However, grabbing the server information from a random website is not really what you want to do, because there is a way to get it directly from the servers. Counter Strike 1.6 servers seem to use the GoldSrc / Source Server Protocol that lets us retrieve information about the servers. You can read more about the protocol here, but we are just going to use the source-server-query package to send queries:
const query = require('source-server-query');
const servers = [
{ ip: '51.195.60.135', port: 27015 },
{ ip: '51.195.60.135', port: 27017 },
{ ip: '185.119.89.86', port: 27021 },
{ ip: '178.32.137.193', port: 27500 },
{ ip: '51.195.60.135', port: 27018 },
{ ip: '51.195.60.135', port: 27016 }
];
const timeout = 5000;
Promise.all(servers.map(server => {
return query
.info(server.ip, server.port, timeout)
.then(info => Object.assign(server, info))
.catch(console.error);
})).then(() => {
query.destroy();
console.log(servers);
/* Your code here */
});
Update
servers is just a normal JavaScript array consisting of objects that describe servers, and you can see its structure when it is logged into the console after the information has been received, so it should not be hard to work with. For example, you can access the playersnum property of the third server in the list by writing servers[2].playersnum. Or you can loop through all the servers and do something with each of them by using functions like map and forEach, or just a normal for loop.
But note that in order to use the data you get from the servers, you have to put your code in the callback function passed to the then method of Promise.all(...), i.e. where console.log(servers) is located. This has to do with the fact that it takes some time to get the responses from the servers, and for that reason server queries are normally asynchronous, meaning that the script continues execution even though it has not received the responses yet. So if you try to access the information in the global scope instead of the callback function, it is not going to be there just yet. You should read about JavaScript Promises if you want to understand how this works.
Another thing you may want to do is to filter out the servers that did not respond to the query. This can happen if a server is offline, for example. In the solution I have provided, such servers are still in the servers array, but they only have the ip and port properties they had originally. You could use filter in order to get rid of them. Do you see how? Tell me if you still need help.

Sending an array with axios.get as params is undefined

I am making a get request with additional params options, since I am using that request on a filter, so the params are filters for what to get back:
const res = await axios.get("http://localhots:3000/getsomedata", {
params: {
firstFilter: someObject,
secondFilter: [someOtherObject, someOtherObject]
}
});
The request goes through just fine, on the other end, when I console.log(req.query); I see the following:
{
firstFilter: 'someObject',
'secondFilter[]': ['{someOtherObject}', '{someOtherObject}'],
}
If I do req.query.firstFilter that works just fine, but req.query.secondFilter does not work and in order for me to get the data, I have to do it with req.query["secondFilter[]"], is there a way to avoid this and be able to get my array of data with req.query.secondFilter?
My workaround for now is to do:
const filter = {
firstFilter: req.query.firstFilter,
secondFilter: req.query["secondFilter[]"]
}
And it works of course, but I don't like it, I am for sure missing something.
Some tools for parsing query strings expect arrays of data to be encoded as array_name=1&array_name=2.
This could be a problem if you have one or more items because it might be an array or might be a string.
To avoid that problem PHP required arrays of data to be encoded as array_name[]=1&array_name[]=2 and would discard all but the last item if you left the [] out (so you'd always get a string).
A lot of client libraries that generated data for submission over HTTP decided to do so in a way that was compatible with PHP (largely because PHP was and is very common).
So you need to either:
Change the backend to be able to parse PHP style
Change your call to axios so it doesn't generate PHP style
Backend
The specifics depend what backend you are using, but it looks like you might be using Express.js.
See the settings.
You can turn on Extended (PHP-style) query parsing by setting it to "extended" (although that is the default)
const app = express()
app.set("query parser", "extended");
Frontend
The axios documentation says:
// `paramsSerializer` is an optional function in charge of serializing `params`
// (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
paramsSerializer: function (params) {
return Qs.stringify(params, {arrayFormat: 'brackets'})
},
So you can override that
const res = await axios.get("http://localhots:3000/getsomedata", {
params: {
firstFilter: someObject,
secondFilter: [someOtherObject, someOtherObject]
},
paramsSerializer: (params) => Qs.stringify(params, {arrayFormat: 'repeat'})
});
My example requires the qs module
This has to do with params not being serialized correctly for HTTP GET method. Remember that GET has no "body" params similar to POST, it is a text URL.
For more information I refer to this answer, which provides more detailed info with code snippets.

Node JS sending data via URL

Recently i started programming with Node JS and found it an amazing replacement for php . In php i used to send get requests with Data in the url .
Something like : http://sample.com/public.php?x=helloworld
How to perform something like this in Node JS or is there a better way to send data to node unlike using the url in the above case .
Also , I have noticed that in some cases like stackoverflow , queries are different and dont include the file name
like /public?= instead of /public.php?=
How is this achieved , i always thought this was something related to REST . Also , if you have the answer you might as well guide me if it could be done with Node and a few sources to learn could be of help too .
the most regular way to use REST api
req.query
// GET /search?q=foo+bar
req.query.q
// => "foo bar"
// GET /phone?order=desc&phone[color]=black&shoe[type]=apple
req.query.order
// => "desc"
req.query.phone.color
// => "black"
req.params
// GET /user/william
req.params.name
// => "william"
req.body(for form data)
// POST /login
req.body.username
// => "william"
req.body.password
// => "xxxxxx"
You'll probably be much better off using a pre-existing module as your web server. You can set one up manually, but you have to know about a lot of potential edge cases and really understand web servers. Most people in node use express. In node, as in any server-side language, you can pass data around in a few ways. The query string is one. You can also put some parameters directly in the url (like "/users/12" where 12 is a user id). Depending on the type of request, you can put data in the body of the request. You can also pass cookies. These are not node-specific. Explaining how express works in a post like this would be crazy, so I'll just give you a short example of a what a route handler matching your example route might look like:
var express = require('express');
var app = express();
app.get('/public', function(req, res, next) {
// Get the value from the query string. Express makes the query
// available as an object on the request parameter.
var x = req.query.x;
// Execute your main logic
doSomethingWithX(x);
// Send a response
res.status(200).json({ foo: 'bar' });
});

javascript - make facebook page post

I am not using the Javascript SDK because that is client-side whereas I'm making a server-side call.
I want to make a page post so that I can make an ad creative with it. I can do the call perfectly fine in the Graph API Explorer tool, but I cannot make the same call (with the same long-lived access tokens that continue to work in the Graph Explorer) from Javascript. Here is my code:
tok = <valid and never expiring user token>;
var pg_tok = <valid and never expiring page token>;
var act_id = <account_id>;
var pg_id = <page_id>;
var call_to_action = 'INSTALL_MOBILE_APP';
var fb_app_url = 'https://itunes.apple.com/us/app/id284882215';
var msg = 'Test creative, ya see';
var pic_url = 'https://s3.amazonaws.com/<path_to_my_image>';
var ROOT = 'https://graph.facebook.com/';
var pagepost_endpoint = ROOT+pg_id+'/feed';
console.log(pagepost_endpoint);
var pagepost_params = {
access_token: pg_tok,
call_to_action: {
type: call_to_action,
value: {link: fb_app_url}
},
message: msg,
picture: pic_url,
published: false
};
console.log(pagepost_params);
var pagepost_res = HTTP.post(pagepost_endpoint, {params: pagepost_params});
console.log(pagepost_res);
I have played around a bunch with params vs. data for where pagepost_params goes in the HTTP.post that is giving the error (that is Meteor's HTTP btw).
-Putting everything in params gives the error: {"error":{"type":"Exception","message":"No Call To Action Type was parseable. Please refer to the call to action api documentation","code":1373054,"is_transient":false}}.
-Putting everything in data gives the error: {"error":{"message":"(#200) This API call requires a valid app_id.","type":"OAuthException","code":200}}.
-Putting access_token in params and everything else in data gives the error: {"error":{"message":"Invalid parameter","type":"FacebookApiException","code":100,"error_subcode":1349125}}.
One more clue for everyone, if I change the HTTP.post to HTTP.get, and just put access_token in params and include no other parameters (in params or in data), the call succeeds and I see past posts I have made on this page through the Graph Explorer (only the ones with published: true, though), so the access token and endpoint do work, just something is faulty about POST-ing instead of GET-ing and the specific parameters I'm using.
Have you tried posting to /photos instead of /feed? The error subcode is the same as mentioned here Posting to facebook wall using graph api
Hope this helps
Turned out to be an issue with Meteor's HTTP. It does not handle nested JSON very well, and we're going to submit a pull request for that. But for those seeing this, the important thing to take away is that the call_to_action may not be a valid JSON object, and even if it is, it may not be being stringified/parsed as expected. My fix was using request.post instead of HTTP.post. (then instead of params or data, you use form. look up node's request https://github.com/mikeal/request)

Struggling to build a JS/PHP validation function for my app

I have a web service that returns a JSON object when the web service is queried and a match is found, an example of a successful return is below:
{"terms":[{"term":{"termName":"Focus Puller","definition":"A focus puller or 1st assistant camera..."}}]}
If the query does not produce a match it returns:
Errant query: SELECT termName, definition FROM terms WHERE termID = xxx
Now, when I access this through my Win 8 Metro app I parson the JSON notation object using the following code to get a JS object:
var searchTerm = JSON.parse(Result.responseText)
I then have code that processes searchTerm and binds the returned values to the app page control. If I enter in a successful query that finds match in the DB everything works great.
What I can't work out is a way of validating a bad query. I want to test the value that is returned by var searchTerm = JSON.parse(Result.responseText) and continue doing what I'm doing now if it is a successful result, but then handle the result differently on failure. What check should I make to test this? I am happy to implement additional validation either in my app or in the web service, any advice is appreciated.
Thanks!
There are a couple of different ways to approach this.
One approach would be to utilize the HTTP response headers to relay information about the query (i.e. HTTP 200 status for a found record, 404 for a record that is not found, 400 for a bad request, etc.). You could then inspect the response code to determine what you need to do. The pro of this approach is that this would not require any change to the response message format. The con might be that you then have to modify the headers being returned. This is more typical of the approach used with true RESTful services.
Another approach might be to return success/error messaging as part of the structured JSON response. Such that your JSON might look like:
{
"result":"found",
"message":
{
"terms":[{"term":{"termName":"Focus Puller","definition":"A focus puller or 1st assistant camera..."}}]}
}
}
You could obviously change the value of result in the data to return an error and place the error message in message.
The pros here is that you don't have to worry about header modification, and that your returned data would always be parse-able via JSON.parse(). The con is that now you have extra verbosity in your response messaging.

Categories