Retrieving the client request ip address - javascript

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.

Related

How can you integrate a variable in a JSON path in 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().

Javascript - Is it possible to use fetch or axios.get with a specific property path?

I am a student, in my 3rd week of learning JavaScript, and today I've been completely roadblocked by something I can't find my way around.
Suppose I have the following:
axios.get("www.examplewebsite.com/api/......")
.then((response)=>{
console.log(response)
})
The json in question contains a tremendous amount of data, and all I need is one url from it. I found the property path of:
data.data.examples[0].example.week3.uri
Is there any way to use axios, or even fetch, to grab that single piece of data?
Unless the API provides that option, the client cannot specify which bits of information are wanted. With a regular REST API you get what the server sends you.
But, you can chain .then() calls if you want to narrow your data down and disregard everything you don't care about:
axios.get("www.examplewebsite.com/api/......")
.then(response => response.data.data.examples[0].example.week3.uri)
.then(uri => {
console.log(uri)
})
Or, if you want to grab the URI from the same path for all your examples, you could narrow it down to an array of URIs:
axios.get("www.examplewebsite.com/api/......")
.then(response => response.data.data.examples)
.then(examples => examples.map(item => item.example.week3.uri))
.then(uris => {
console.log(uris)
})
It depends on the server and the backend. It might be possible to get the value, but you have to provide the required information in your request (URL).
For example, this URL (http://site.come/moives) can give you a list of movies, but this (http://site.come/moives/movieid) can give you information about a certain movie. Again it depends on the server ...

How to use array items as parameter for API call

I am currently trying to log out the names and ID of a various items for a video game using an array which holds the ID of each item.
Currently I have the following.
const URL =
"http://services.runescape.com/m=itemdb_oldschool/api/catalogue/detail.json?item=";
const items = ["4151", "2"];
items.map(item => {
fetch(`${URL}${item}`)
.then(data => data.json())
.then(({ item: { id, name } }) => console.log(`${id}: + ${name}`));
});
I should be getting 4151: Abyssal Whip as a format for each item, but it isnt working. I have done this in the past using a cryptocurrency api, but I cant get it to work here, and I am not sure where I am going wrong.
Thanks for the help in advance.
Some more detail would help. If you open dev tools and look at console output when hitting the API, you might be getting an error... maybe a Mixed-Content error? The runescape API is returning from an HTTP connection. If you are requesting from an HTTPS connection, it will not allow the resource to be delivered. Otherwise, your code should run (but the +) won't be necessary because you're using template literals.
I am sure its a typical CORS policy error. Here's how I managed to fetch the data. The heroku API enables cross-origin requests to anywhere.
const items = ["4151", "2"];
const proxyUrl = "https://cors-anywhere.herokuapp.com/",
targetUrl =
"http://services.runescape.com/m=itemdb_oldschool/api/catalogue/detail.json?item=";
items.map((item) => {
fetch(proxyUrl + targetUrl + item)
.then((data) => data.json())
.then(({ item: { id, name } }) => console.log(`${id}: + ${name}`));
});

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,
})
});

meteor.js - temporary server-side app state

I need to use some data from a 3rd party API in my app, poll for the needed data with certain frequency from the server, and make it available to the client. The easiest way would be to create a collection and update it, and make the data available to the client via pub/sub. But, in this particular case I don't need to store that data or keep track of it, and it updates very frequently, so storing it to db would actually be just additional unneeded work. I would prefer to store it somehow in the RAM, and make it available to the client in some other way except collections (perhaps, return from a method call). But I'm not sure, how to do that. Could someone suggest some nice approach?
You could use this package meteor-publish-join to fetch data from external API and publish to client periodically (disclaimer: I am the author):
Server:
import { JoinServer } from 'meteor-publish-join';
Meteor.publish('test', function() {
// Publish a random value from an external API, plays well with promise, re-run every 10 seconds
JoinServer.publish({
context: this,
name: 'withPromise',
interval: 10000,
doJoin() {
const id = parseInt(Math.random() * 100, 10);
return fetch(`https://jsonplaceholder.typicode.com/posts/${id}`)
.then(res => res.json())
.then(data => data.title)
.catch(err => console.error(err));
},
});
});
Client:
import { JoinClient } from 'meteor-publish-join';
Meteor.subscribe('test');
// Get the values published within `test` publication. All these values are reactive
JoinClient.get('withPromise')

Categories