How to use array items as parameter for API call - javascript

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

Related

How to fetch data properly for this API? (array)

console.log screenshot
Hi, I am using "fetch" method with API for my website, and this API shows book information, if books include the input title.
Screenshot attached is console.log result when typing an example book title.
I'd like to get every title info of each array, could anyone can help me on this?
Especially I am not sure what is the proper line for this.
.then((data) => {document.getElementById("bookinfo").innerHTML=
data['documents'.authors];
Entire script for fetch is below.
<script>
function getBook(){
let bookvalue=document.getElementById("book").value;
fetch('https://dapi.kakao.com/v3/search/book?target=title&query=' + bookvalue, {
headers: {
Authorization: "KakaoAK TokenID"
}
})
.then((response) => response.json())
.then((data) => {document.getElementById("bookinfo").innerHTML=
data['documents'.authors];
});
}
</script>
You're not calling the array index correctly, data['documents'.authors] should be data.documents[0].authors to get the author of the first item and data.documents[1].authors to get the second, etc...
What do you intend to do with the titles?
EDIT: Fixed it for easier use (I think this is what you want)
.then(data => data.documents.map(book => book.title)).then(titles => document.getElementById("bookinfo").innerHTML = titles.join(", "));
Otherwise create an array
const titles = [];
push into array
.then(data => data.documents.map(book => titles.push(book.title))
But you might have issues with this and get empty array since the promise might still be pending

Issues connecting data stream to users responses in Google Voice App

I am currently developing a voice agent to be used in a smart speaker where users will ask about some items that are being stored in a data stream. The ultimate goal is that users ask about items' names in the stream and google actions through voice will tell them the details about those items as presented in another column in the stream.
To do this, I linked a spreadsheet to Axios to stream the content of the spreadsheet as data to be read in a webhook in google actions. The link to the data stream is HERE.
Honestly, I am new to developing apps for google actions and new to javascript overall so I might be doing silly mistakes.
In the graphical interface for google actions, I am setting a type for the items I want the user to ask about.
Then, I set an intent to recognize the item as a data type and be able to send this to the webhook.
The cloud function in the webhook is as follows:
const { conversation } = require('#assistant/conversation');
const functions = require('firebase-functions');
require('firebase-functions/lib/logger/compat'); // console.log compact
const axios = require('axios');
const app = conversation({debug: true});
app.handle('getItem', async conv => {
const data = await getItem();
const itemParam = app.types.Item;
// conv.add("This test to see if we are accessing the webhook for ${itemParam}");
data.map(item => {
if (item.Name === itemParam)
agent.add('These are the datails for ${itemParam}. It is located in zone
${item.Zone}, at level ${item.Level}');
});
});
async function getItem() {
const res = await axios.get('https://sheetdb.io/api/v1/n3ol4hwmfsmqd');
console.log(res.data);
return res.data; // To use in your Action's response
}
exports.ActionsOnGoogleFulfillment = functions.https.onRequest(app);
What the webhook is doing is getting the stream with the getItem function and then mapping the data to find the Name in the stream to match the item parameter (ItemParam) as identified by the user.
However, one of the main problems I have is that when trying to access the item from the user, I am using app.types.Item, but this does not work as when testing I get an error saying: "error": "Cannot read property 'Item' of undefined". I think what is happening is that I am not using the correct way to call the Item in the conversation app.
Also, I am not sure exactly how the linking to the database will work. In other works, I am not sure if
data.map(item => {
if (item.Name === itemParam)
agent.add('These are the datails for ${itemParam}. It is located in zone
${item.Zone}, at level ${item.Level}');
will work.
I have tried multiple things to solve but I am really struggling so any help with this would be really appreciated. Also, I know that I rushed to explain things, so please let me know if you need me to explain better or clarify anything.
Thank you
There are three points I am seeing that won't work.
First, app.types.Item is not the way to get this parameter. You should instead use conv.intent.params['Item'].resolved to get the user's spoken name.
Second, you are trying to use agent.add to include text, but there is no agent in your environment. You should instead be using conv.add.
Third, the text you are sending is not properly escaped between backticks ``. It is the backtick that allows you to use template literals.
Altogether your code can be rewritten as:
const { conversation } = require('#assistant/conversation');
const functions = require('firebase-functions');
require('firebase-functions/lib/logger/compat'); // console.log compact
const axios = require('axios');
const app = conversation({debug: true});
app.handle('getItem', async conv => {
const data = await getItem();
const itemParam = conv.intent.params['Item'].resolved;
data.map(item => {
if (item.Name === itemParam)
conv.add(`These are the datails for ${itemParam}. It is located in zone
${item.Zone}, at level ${item.Level}`);
});
});
async function getItem() {
const res = await axios.get('https://sheetdb.io/api/v1/n3ol4hwmfsmqd');
console.log(res.data);
return res.data; // To use in your Action's response
}
exports.ActionsOnGoogleFulfillment = functions.https.onRequest(app);

Async API call inside an infinite while loop using Axios in NODE JS

Let me begin by saying that I am a beginner to Asynchronous JavaScript and it took me quite a while to wrap my head around the concept.
Now, coming to the situation at hand. I wanted to write a code that would automatically detect text from a folder containing multiple screenshots using an OCR API, whose documentation can be found here : https://ocr.space/OCRAPI
The OCR uses two engines which can produce different results. The code should run with the default engine specified and display the contents. If the result is satisfactory, the user can chose to move on with the next screenshot, or make another api request with a different engine.
I tried to use an infinite while loop to achieve this:
const fs = require("fs")
const imageToBase64 = require("image-to-base64")
const apikey = "helloworld"
let engine = 1
fs.promises
.readdir("./screenshots")
.then((files) => {
for (const file of files) {
while (true) {
console.log("Making an API Request")
imageToBase64("./screenshots/" + file)
.then((res) => {
const form = new FormData()
form.append("base64Image", "data:image/jpeg;base64," + res)
form.append("OCREngine", engine)
axios
.post("https://api.ocr.space/parse/image", form, {
headers: { apikey, ...form.getHeaders() },
})
.then((response) => {
console.log(response.data.ParsedResults[0].ParsedText)
/*Code to ask the user whether the result is satisfactory or not.
if yes, break out of the while loop, otherwise change the engine and make the request again*/
engine = 2
})
.catch((error) => console.log(error))
})
.catch((error) => console.log(error))
}
}
})
.catch((error) => console.log(error))
The infinite while loop appears to continue the execution and not wait for the user input.
Can anyone help me out with the correct method of implementing this idea?

Endpoint strings saved in rails postgresql db and cannot make fetch() calls with them in js frontend

I have a rails application with javascript in in the asset pipeline. The rails db has saved urls and I am trying to make fetch() calls with these urls/endpoints to the JSON api. If I put the url in the browser address bar and remove the quotation marks ("") the endpoint will return the data. I can see in the console the error that the url does not exist. I am working on localhost:3000 and that appears to be appended to every fetch call as you can see here. This will appear in the console with a 404 error.
http://localhost:3000/api.openweathermap.org/data/2.5/weather?q=Seattle,us&APPID=fe2a775f427aa5fc92ce0379937b9ee9
. Any suggestions on how to get these fetch() calls working?
How can I implement this?
So far my application will work until I hit the fetch calls that are made and then return undefined
const BASE_URL = "http://localhost:3000/cities.json"
function getCityData(){
fetch(BASE_URL).then( res => res.json() ).then(function(json){
//cityArray will be an Array of cities
//formatted in a way the api can use
let cityArray = json.map(obj => obj.name);
//cityObjArray will be an array of City objects created
// by the class City with city name and api endpoint attributes
const cityObjArray = cityArray.map( city => new City(city));
//fetchArray pulls out all the api endpoints from the object
const fetchArray = cityObjArray.map( cityObj => cityObj.fetchURL);
debugger
let data = fetchArray.map(function(url){
// this will work until it hits this point
// at this point javaScript will attempt to sanitize the endpoints
//and make fetch(url) with them
//I will get 404 not found and it will show the endpoint as
//starting with localhost:3000 which is were I am running this
let rawUrl = url.replace(/['"]+/g, '');
debugger
fetch(rawUrl).then( res => res.json() )
.then(function(json){
debugger
})
.catch(function(){
console.log("ERROR")
});
});
})
}
class City {
constructor(name){
this.name = name
this.fetchURL = `api.openweathermap.org/data/2.5/weather?q=${name},us&APPID=fe2a775f427aa5fc92ce0379937b9ee9`
}
}
class Adaptor {
constructor(url){
this.url = url
this.data = fetch(url).then( res => res.json())
}
}```
[1]: https://i.stack.imgur.com/vCS0o.png
your URLs need to start with a protocol, http://, https:// or // (relative protocol). Otherwise the fetch() interprets them as relative paths at the current host (localhost:3000 in your example). Try this:
this.fetchURL = https://api.openweathermap.org/data/2.5/weather?q=${name},us&APPID=fe2a775f427aa5fc92ce0379937b9ee9
It is not Rails that was adding localhost:3000 to your paths. Since you omitted the protocol it is assumed by fetch() that you have given it a path relative to the current URL. Here is a more detailed answer about relative paths https://stackoverflow.com/a/36369553/632688.

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