How can you integrate a variable in a JSON path in JavaScript - javascript

First of all, it's connecting to a url and just sanitizing it all in the Front-End. The Hypixel API works so, that you take the api url for the wanted request, in this case api.hypixel.net/player?name=USERNAME&key=APIKEY, and get back a big JSON file, which my code should sanitize. So, if you're using the Hypixel API, yeah you're sending the API-Key through the browser, but that is a security flaw in the Hypixle API and not in my code. The sole purpose of my code is to learn more about JavaScript an show it to others.
I'm working on an API access to the Hypixel API.
This gets me a JSON, in which I want to get a specific game, that was inputted in a field an is saved in a dict.
I'm trying to integrate this like this (console.log is only for test purposes, until I give back the data to HTML):
let values = Array.from(document.querySelectorAll('#apiForm input'))
.reduce((acc, input) => {
return { ...acc, [input.id]: input.value };
}, {})
fetch(`https://api.hypixel.net/player?name=${values.name}&key=${values.key}`)
.then(result => result.json())
.then(result => {
if (result.success) {
if (values.game in result.player.stats) {
console.log(result.player.stats.$(values.game)) //not working
} else {
console.log(result.player.stats)
console.log('Game not available or not played yet')
}
} else {
console.log('Something went wrong, please check your name and API-Key or try again later')
}
})
How can I do this here?
The API-Form looks like this:
And the JSON file looks like this:
So when I input Bedwars for example, the path I want should result in result.player.stats.Bedwars:

Replace result.player.stats.$(values.game) with
result.player.stats[values.game]
Also, when putting user input into URI paths, sanitize it with encodeURIComponent or build the query string with new URLSearchParams({ ...props }).toString().

Related

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.

Downloading the response from an api call as a csv onClick

I am attempting create a button for downloading a csv file when an item is selected from a dropDown list. Ive done this before but the response returned this time is different than what im use to. I could use some help understanding how to format things to correctly download and display the data in a csv file when the api is hit.
so far I have an onClick function that looks like this:
const onDownloadReport = (type) => {
const org = type === "All" ? "" : type;
api.providerPayroll
.reports({
date: activePayPeriod,
org: org,
})
.then((res) => {
window.open("data:text/csv;charset=utf-8," + res);
});
};
this works to download the csv file. However it doesnt contain the actual data in the response it shows null in the csv. When i try to console out the res I get null as well. Im not sure what Im missing here for capturing the response.
And the code for the endpoint reports()
reports: (payload) => requests.post("/reporting/download-payroll-report", payload),
Reports follows the same patter as all other api calls in the project.
If I need to add more information on this please let me know.

Is it possible to validate user in backend without user providing credientals?

I need to make a page with a button that fills certain text area with data from database. However I need it to also require administrator privileges.
Is it possible to have an API method that doesn't require credientals, but an Identity session instead? Ideally something that gets a HttpContext.User?
I don't know anything about JavaScript, I managed to put together this thing:
const url = '/api/clients/';
function getItems() {
fetch(url + document.getElementById('input').value)
.then(response => response.json())
.then(data => _displayItems(data));
}
function _displayItems(arrayOfResults) {
const textbox = document.getElementById('textbox');
textbox.value = "";
arrayOfResults.forEach(json => {
textbox.value += json.deviceIdentifier + "\n";
});
}
I have an API endpoint at http://localhost/api/clients/{string} that does a database query and it works as expected. But I can not allow just about anybody to access that data and I have trouble figuring out how to make user:
not provide his credentials
be able to use it with minimal effort (ie. just click the button and get results)
be unable to use this endpoint while not currently logged in on the website
Normally I just use this line to get the user that tries to access the controller:
var currentUser = await _userManager.FindByNameAsync(_userManager.GetUserName(HttpContext.User));
and go from there. But when my JS script is accessing the API it doesn't provide a way to validate using HttpContext, from what I'm seeing.

How to limit the amount of data returned from a JSON file using fetch?

I have this fetch statement that returns 19 building names, but I only want 10; the following is what I attempted, but I still get 19 building names.
fetchBuildings(energyProgramId) {
fetch(`http://localhost:1001/api/energyprograms/${energyProgramId}/buildings/?results=10`)
.then(res => res.json())
.then(json => {
this.setState({
isLoaded: true,
buildings: json,
})
});
}
Is there something extra I need to add?
Here is an example:
1.fetch('http://jsonplaceholder.typicode.com/posts/')
The above URL gives array of objects with 100 elements because it originally is an array of 100 elements.
2.fetch('http://jsonplaceholder.typicode.com/posts/?_limit=10')
This URL gives array of objects with 10 elements.
Notice the difference?
I only did this : ?_limit=10 ----> Add any number in place of 10 and hopefully you will get desired results.
As the other answer already points out the best/most normal solution would be to change on the backend how the API returns data. Typically REST API's support query parameters such as limit and start or page and resultsPerPage.
If this is not available - e.g. when you're fetching an external resource - an alternative which is often supported by static file servers and sometimes by API's is the Range header which allows you to retrieve only a specific byte range of the resource (do note, in the case that an API supports this it will still load the entire resource on the server, but it will not transmit the entire resource). An example with fetch would look like
fetch('', { headers: { range: 'bytes=0-1000'} })
When doing this on XML or JSON resources it can be somewhat difficult to work with, but with for example CSV files it's ideal.
No different from fetch to XHR or axios or anything else. actually, no different from react or angular or vue or anything else.
This is an API that backend developers wrote it and it is based on REST API, so when you call it as GET or POST and anything else you just fetch the JSON that the backend developers designed it. BUT
There is a new technology that name is GraphQL. you can call API and then you just fetch the JSON what you want. Also, it must be implemented in backend but it is possible.
It's not closely bound up with React. If you need less data you must reduce data before set the state.
const reducedBuildings = [];
fetch(`http://localhost:1001/api/energyprograms/${energyProgramId}/buildings/?results=10`)
.then(res => res.json())
.then(json => {
json.forEach(building => {
if (reducedBuildings.length < 10) {
reducedBuildings.push(building);
}
});
this.setState({
isLoaded: true,
buildings: reducedBuildings,
})
});

Retrieving the client request ip address

This post isn't really a question anymore; I just want to post this to help other people out in the future to avoid lost time.
Goal: Retrieve the client IP address and set some specific values based on certain octet in IP.
I was developing a react web-app for my company and needed to support three facilities. The three locations of-course existed in different geographical regions and had slightly different IP schema's.
I needed to set some session identifier based on an octet value from the client IP. To do so, I did the following steps.
Setup express route for user to hit on initial visit of app.
Get client IP and store in const/var.
Explode IP string by ".".
Perform If/Then or Switch to determine value of desired octet.
Set some session/logic within matching condition.
Thanks to express, the req object contains an ip key with the value of the requests IP address. We can utilize this or some other third party library to get the needed info. Of course there are better/more secure ways to do this, but this is a simple method I've researched and setup. Definitely thanks to community for helping me resolve my issue with this.
apiRouter.route('/test')
.get((req, res) => {
const request_ip = req.ip; // Returns string like ::ffff:192.168.0.1
const ip_array = request_ip.split('.') // Returns array of the string above separated by ".". ["::ffff:192","168","0","1"]
// The switch statement checks the value of the array above for the index of 2. This would be "0"
switch(ip_array[2]) {
case('0'):
res.json({'request-ip':ip_array, 'location':'Location A'});
break;
case('1'):
res.json({'request-ip':ip_array, 'location':'Location B'});
break;
case('2'):
res.json({'request-ip':ip_array, 'location':'Location C'});
break;
default:
res.json({'request-ip':ip_array, 'location':'Default Location'});
}
})
One of my main issues was that I was developing on my local laptop. My node server was running express here. I was also trying to get my request ip from my local machine. This didn't make sense because I was constantly getting back "::1" as my request IP. Baffled, I did much research and finally found it to be an obvious PEBKAC issue. Thanks to nikoss in this post, it made all the sense in the world.
You can get this information by fetching it from an open IP
https://api.ipdata.co/
fetch("https://api.ipdata.co")
.then(response => {
return response.json();
}, "jsonp")
.then(res => {
console.log(res.ip)
})
.catch(err => console.log(err))
This works!
async componentDidMount() {
const response = await fetch('https://geolocation-db.com/json/');
const data = await response.json();
this.setState({ ip: data.IPv4 })
alert(this.state.ip)
}
use it in jsx as
{this.state.ip}
It seems like https://api.ipdata.co doesn't work anymore, even when specifying a key. I ended up using Ipify (typescript):
private getMyIp() {
fetch('https://api.ipify.org?format=json').then(response => {
return response.json();
}).then((res: any) => {
this.myIp = _.get(res, 'ip');
}).catch((err: any) => console.error('Problem fetching my IP', err))
}
This is a good reference for alternative IP retrieval services: https://ourcodeworld.com/articles/read/257/how-to-get-the-client-ip-address-with-javascript-only
If https://api.ipdata.co doesn't work you can use geolocation-db.com/json. Advantage of geolocation it also gives you other important values like latitude, longitude, country, state, zip
fetch(`https://geolocation-db.com/json/`)
.then(res => res.json())
You can console.log(...) the res.json() to view the JSON values.
You can use this one as well.
fetch('https://get-ip-only.herokuapp.com/') .then(r => r.json()) .then(resp => console.log(resp.ip))
https://get-ip-only.herokuapp.com/
This API provides you the IP only.

Categories