I'm having a bit of trouble managing an API request for a new project. I'm trying to practice making POST requests, and I wanted to pass multiple parameters in one POST. So far, I've tried making a for loop that loops through an array to make multiple requests, but that doesn't seem to be working. I've handled simple GET requests before, but I can't seem to figure out to pass multiple parameters to a post without rewriting the whole thing.
Here's what I have so far:
let URL = "www.exampleapi.com";
Here's the array I'm working with, they are supposed to be dogs in a kennel.
let dogArray = [
{"id": 1,
"name": "Max" },
{"id": 2,
"name": "Jack"},
{"id": 3,
"name": "Bones" }
];
The kennel the dogs are in currently has an id of 777
let kennelId = 777;
The POST request for this API requires the kennelId and the dogId (dogArray.id), so I wanted to write a function that loops though the dogArray and records the individual ids.
function getDogsInKennel(kennelId, dogArray) {
for (let i = 0; i < dogArray.length; i++) {
//the API would assign a different dogId every time it looped through
dogId = dogArray[i].id;
}
fetch(URL, {
method: 'POST',
body: JSON.stringify(({ dogId: dogId, kennelId: kennelId })),
headers:{
'Content-Type': 'application/json'
}
}).then(result => result.json())
}
getDogsInKennel(kennelId, dogArray);
As you can tell, this method isn't working. Should I scrap the entire function and try something else, or is there a way this can be rewritten to make multiple POST calls using the same array?
The main issue I am seeing is that you are not placing your code to POST inside the for look, so it will only POST once, using the last dogId assigned by the for loop
Additionally, you are not doing anything with the returned data after converting the result to JSON. If you checkout the fetch documentation here you can see that you need to add another .then to handle the returned value.
So you would end up with something a bit more like this for your function:
function getDogsInKennel(kennelId, dogArray) {
for (let i = 0; i < dogArray.length; i++) {
dogId = dogArray[i].id;
fetch(URL, {
method: 'POST',
body: JSON.stringify(({ dogId: dogId, kennelId: kennelId })),
headers:{
'Content-Type': 'application/json'
}
}).then(result => result.json())
.then((data) => {
// Process the result here
})
}
The .then is only needed if you are doing something with the result, like handling a success message/status.
I'm also not sure if you are intending to use promises to do this or not, the fetch method is promise-based. Something simpler to use may be $.post available in jQuery (more about that here)
Hope this helps:
function getDogsInKennel(kennelId, dogArray) {
let dogIds = []
for (let i = 0; i < dogArray.length; i++) {
dogIds.push(dogArray[i].id);
}
fetch(URL, {
method: 'POST',
body: JSON.stringify(({ dogId: dogIds, kennelId: kennelId })),
headers:{
'Content-Type': 'application/json'
}
}).then(result => result.json()).then((data) => {
console.log(data)
})
}
getDogsInKennel(kennelId, dogArray);
Related
I have an API call returning 1 movie name at random... The code has it set up so it returns 1 movie name only.
I then have a second API call that uses that movie name in a second axios request to find streaming services available for this specific movie title.
My issue is, the second API call returns an array of 20 or so choices. For example, if I searched for 'Jaws' it delivers results for Jaws, all the other Jaws movies and any other movie with Jaws in the name.
My question is, how do I filter through this return information, to find a perfect match with the right movie title and just show that info? I hope you can help and sure it is going to be some filtering logic. Thankyou! I am new to React so trying to learn.
const optionsParams = { method: 'GET', url: 'https://mdblist.p.rapidapi.com/', params: [], headers: { 'X-RapidAPI-Host': 'mdblist.p.rapidapi.com', 'X-RapidAPI-Key': '384177d302msh9d8e58dffccp1bfa57jsnf3cea9fef042', }, }; axios .request({ ...optionsParams, params: { s: ${movieData.title}} }) .then(function (response) { console.log(response.data); const traktid = response.data.search.traktid; const traktidOptions = { ...optionsParams, params: { t: ${traktid}` }
};
axios.request(traktidOptions).then(function (response) {
const streamingServices = response.data.streams;
setStreamingState(streamingServices);
//console.log(streamingState);
console.log(response.data.streams)
let temporaryArray = [];
for (let i = 0; i < response.data.streams.length; i++){
temporaryArray.push(response.data.streams[i].name)
console.log(temporaryArray);
}
setStreamingState(streamingState => [...streamingState, `${temporaryArray}`])
if (streamingState) {
console.log(streamingState)
} else return false;
})
})`
Array methods are the perfect tool for iterating and organising array data.
In this case the Array.prototype.find() will help you look through your array and return a single item based on your criteria.
For example:
const yourArray = ["jaws", "not this jaws", "definitely not jaws"];
const found = yourArray.find(arrayItem => arrayItem === "jaws");
This is a simple example without objects, so you would just need to set the criteria based on an object property.
I'm trying to add a new object to the end of an array that I'm dynamically fetching over my API. Users complete a form so the data is passed from the form to the state.
The initial first fetch is storing the original array to some react state which is fine, then at some point, a single object should be added to the end of the original array, so the whole array will contain the original data, plus the new object added.
Naturally, I'm trying to use array.push() to try and achieve this, but I keep getting the index rather than the data object.
// declare state will be an array
const [originalPages, setOriginalPages] = useState([]);
// Get all the existing data
loadInitialValues() {
return fetch(`example.com/api/collections/get/testing_features?token=${process.env.REACT_APP_API_KEY}`)
.then((res) => {
return res.json();
})
.then((res)=>{
// set state to be the whole array for this post
setOriginalPages(res.entries[4].pagebuild);
return res.entries[4].pagebuild[0].settings;
})
.catch((err)=>{
console.error(err);
})
}
At this point the data is all working completely fine, the collection of the new data from the forms works fine too. However, this is the point when the data goes to get posted back to update the API but just returns a number:
onSubmit(formData) {
// Dynamically hook all the newly collected form data to this new data object
let theData = {
component: 'page',
settings: {
title: formData.title,
pageOptions: {
pageSideImg: formData.pageOptions.pageSideImg,
isReversed: formData.pageOptions.isReversed,
paraGap: formData.pageOptions.paraGap,
paraFont: formData.pageOptions.paraFont,
},
pageNavigation: {
pageSlug: formData.pageNavigation.pageSlug,
nextPage: formData.pageNavigation.nextPage,
prevPage: formData.pageNavigation.prevPage,
},
globalOptions: {
projectName: formData.globalOptions.projectName,
transType: formData.globalOptions.transType,
menuTrans: formData.globalOptions.menuTrans,
},
blocks: formData.blocks
}
};
cms.alerts.info('Saving Content...');
return fetch(`example.com/api/collections/save/testing_features?token=${process.env.REACT_APP_API_KEY}`, {
method: 'post',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
data: {
// Only returning the array count as a number
pagebuild: originalPages.push(theData),
_id: "610963c235316625d1000023"
}
})
})
.then(response => response.json())
.catch((err) => {
cms.alerts.error('Error Saving Content');
console.log(err);
});
},
If anyone has any ideas as to why this is happening id greatly appreciate it!
For reference, I've checked here and maybe I should use spread instead?
The Array.push doesn't return the final array you would need, but the final length of modified array (that's why you thought it was an index).
Replace this string pagebuild: originalPages.push(theData), with this one:
pagebuild: [...originalPages, theData],
Of course, if you want to update the internal originalPages state value, call this within your onSubmit():
setOriginalPages(x => [...x, theData]);
Here is an API call, which needs some values to return a specific set of products,
issue
"category_slug" has to be an array but for some reason, the API says it's not. what is the problem here?
const url = new URL(
"https://someApi/products"
);
let params = {
"limit": "10",
"page": "1",
"category_slug": ["shoes"]
};
// "limit" is "how many products in on one page".
// "page" is the fetched page with the specific "limited" products.
//issue
// "category_slug" is a specific products category, this has to be an array but for
// some reason, the API says it's not. what is the problem here?
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
//here I'm appending the specific value in {params} to the URL.
let headers = {
"Accept": "application/json",
"Content-Type": "application/json",
};
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
See, you expect too little and too much at the same time of such a beautiful thing as URLSearchParams.
Too little, because usually you can just pass the whole params object into its constructor without wasting time on keys, forEach, etc...
const url = new URL('https://example.com/');
const params = {
limit: 10,
page: 1
};
url.search = new URLSearchParams(params); // yes, that easy
console.log(url.toString());
// https://example.com/?limit=10&page=1
Too much, because URLSearchParams is not designed to work with arrays. When appended element is an array, it's just stringified:
const url = new URL('https://example.com/');
const params = {
slug: [1, 2, 3]
};
url.search = new URLSearchParams(params);
console.log(url); // https://example.com/?slug=1%2C2%2C3
In this case, slug param got 1,2,3 (result of [1, 2, 3].toString()) assigned to it (and all the commas were urlencoded - replaced by %2C sequence).
Your API might actually work with this, but there's a huge chance it expects array args to be passed in the following format:
https://example.com/?slug=1&slug=2&slug=3
... yet even this might not work, if API expects array args to be passed with [] appended to each key, like this:
https://example.com/?slug[]=1&slug[]=2&slug[]=3
So you'll have to check your API (it's hard to debug such things just by looking into crystal ball, you know...), take its flavor into account - and process your items separately. For example,
const url = new URL('https://example.com/');
const params = {
limit: 10,
page: 1
};
url.search = new URLSearchParams(params);
const slugs = [1, 2, 3];
url.search += ['', ...slugs.map(
slug => `category_slug[]=${encodeURIComponent(slug)}`)].join('&');
console.log(url.toString());
Via a microservice, I retrieve several packages of JSON data and spit them out onto a Vue.js-driven page. The data looks something like this:
{"data":{"getcompanies":
[
{"id":6,"name":"Arena","address":"12 Baker Street","zip":"15090"},
{"id":7,"name":"McMillan","address":null,"zip":"15090"},
{"id":8,"name":"Ball","address":"342 Farm Road","zip":"15090"}
]
}}
{"data":{"getusers":
[{"id":22,"name":"Fred","address":"Parmesean Street","zip":"15090"},
{"id":24,"name":"George","address":"Loopy Lane","zip":"15090"},
{"id":25,"name":"Lucy","address":"Farm Road","zip":"15090"}]}}
{"data":{"getdevices":
[{"id":2,"name":"device type 1"},
{"id":4,"name":"device type 2"},
{"id":5,"name":"device type 3"}]}}
...and I successfully grab them individually via code like this:
getCompanies() {
this.sendMicroServiceRequest({
method: 'GET',
url: `api/authenticated/function/getcompanies`
})
.then((response) => {
if(response.data) {
this.dataCompanies = response.data.getcompanies
} else {
console.error(response)
}
}).catch(console.error)
}
...with getUsers() and getDevices() looking respectively the same. getCompanies() returns:
[{"id":6,"name":"Arena","address":"12 Baker Street","zip":"15090"},
{"id":7,"name":"McMillan","address":null,"zip":"15090"},
{"id":8,"name":"Ball","address":"342 Farm Road","zip":"15090"}]
...which I relay to the Vue template in a table, and this works just fine and dandy.
But this is obviously going to get unwieldy if I need to add more microservice calls down the road.
What I'm looking for is an elegant way to jump past the response.data.*whatever* and get to those id-records with a re-useable call, but I'm having trouble getting there. response.data[0] doesn't work, and mapping down to the stuff I need either comes back undefined, or in bits of array. And filtering for response.data[0].id to return just the rows with ids keeps coming back undefined.
My last attempt (see below) to access the data does work, but looks like it comes back as individual array elements. I'd rather not - if possible - rebuild an array into a JSON structure. I keep thinking I should be able to just step past the next level regardless of what it's called, and grab whatever is there in one chunk, as if I read response.data.getcompanies directly, but not caring what 'getcompanies' is, or needing to reference it by name:
// the call
this.dataCompanies = this.getFullData('companies')
getFullData(who) {
this.sendMicroServiceRequest({
method: 'GET',
url: 'api/authenticated/function/get' + who,
})
.then((response) => {
if(response) {
// attempt 1 to get chunk below 'getcompanies'
Object.keys(response.data).forEach(function(prop) {
console.log(response.data[prop])
})
// attempt 2
// for (const prop in response.data) {
// console.log(response.data[prop])
// }
let output = response.data[prop] // erroneously thinking this is in one object
return output
} else {
console.error(response)
}
}).catch(console.error)
}
...outputs:
(63) [{…}, {…}, {…}] <-- *there are 63 of these records, I'm just showing the first few...*
0: {"id":6,"name":"Arena","address":"12 Baker Street","zip":"15090"}
1: {"id":7,"name":"McMillan","address":null,"zip":"15090"},
2: {"id":8,"name":"Ball","address":"342 Farm Road","zip":"15090"}...
Oh, and the return above comes back 'undefined' for some reason that eludes me at 3AM. >.<
It's one of those things where I think I am close, but not quite. Any tips, hints, or pokes in the right direction are greatly appreciated.
I feel it's better to be explicit about accessing the object. Seems like the object key is consistent with the name of the microservice function? If so:
getData(functionName) {
return this.sendMicroServiceRequest({
method: 'GET',
url: "api/authenticated/function/" + functionName
})
.then( response => response.data[functionName] )
}
getCompanies(){
this.getData("getcompanies").then(companies => {
this.dataCompanies = companies
})
}
let arrResponse = {data: ['x']};
let objResponse = {data: {getcompanies: 'x'}};
console.log(arrResponse.data[0]);
console.log(Object.values(objResponse.data)[0]);
response.data[0] would work if data was an array. To get the first-and-only element of an object, use Object.values(response.data)[0] instead. Object.values converts an object to an array of its values.
Its counterparts Object.keys and Object.entries likewise return arrays of keys and key-value tuples respectively.
Note, order isn't guaranteed in objects, so this is only predictable in your situation because data has exactly a single key & value. Otherwise, you'd have to iterate the entry tuples and search for the desired entry.
firstValue
Let's begin with a generic function, firstValue. It will get the first value of an object, if present, otherwise it will throw an error -
const x = { something: "foo" }
const y = {}
const firstValue = t =>
{ const v = Object.values(t)
if (v.length)
return v[0]
else
throw Error("empty data")
}
console.log(firstValue(x)) // "foo"
console.log(firstValue(y)) // Error: empty data
getData
Now write a generic getData. We chain our firstValue function on the end, and be careful not to add a console.log or .catch here; that is a choice for the caller to decide -
getData(url) {
return this
.sendMicroServiceRequest({ method: "GET", url })
.then(response => {
if (response.data)
return response.data
else
return Promise.reject(response)
})
.then(firstValue)
}
Now we write getCompanies, getUsers, etc -
getCompanies() {
return getData("api/authenticated/function/getcompanies")
}
getUsers() {
return getData("api/authenticated/function/getusers")
}
//...
async and await
Maybe you could spruce up getData with async and await -
async getData(url) {
const response =
await this.sendMicroServiceRequest({ method: "GET", url })
return response.data
? firstValue(response.data)
: Promise.reject(response)
}
power of generics demonstrated
We might even suggest that these get* functions are no longer needed -
async getAll() {
return {
companies:
await getData("api/authenticated/function/getcompanies"),
users:
await getData("api/authenticated/function/getusers"),
devices:
await getData("api/authenticated/function/getdevices"),
// ...
}
}
Above we used three await getData(...) requests which happen in serial order. Perhaps you want all of these requests to run in parallel. Below we will show how to do that -
async getAll() {
const requests = [
getData("api/authenticated/function/getcompanies"),
getData("api/authenticated/function/getusers"),
getData("api/authenticated/function/getdevices")
]
const [companies, users, devices] = Promise.all(requests)
return { companies, users, devices }
}
error handling
Finally, error handling is reserved for the caller and should not be attempted within our generic functions -
this.getAll()
.then(data => this.render(data)) // some Vue template
.catch(console.error)
I've been trying to get a POST request from an API, and I'm not having that much luck in pushing it through. I'm wondering if it's because one of the parameters I'm passing is an array of objects. Been trying to get this to work for a few hours with no luck.
This post function requires two parameters, userId and classId.
//here's the api I'm calling, obviously not the actual URL
let apisource = www.exampleapi.com
//this is the class
let classId = 12345;
//these are students in the class
let userArray = [{
"name": "user1",
"userId": 101
}, {
"name": "user2",
"userId": 102
}]
I'm writing a function that takes this userArray and matches it up to a class that contains the userIds.
Here's my API call so far:
function getStudents(classId, userArray) {
$.post(apisource) + "classes"), {
userId: userArray.userId,
classId: classId
}, function(data, status) {
console.log("students in class loaded)
}
}
Nothing ever loads. Anyone have any suggestions or pointers for something I might be doing wrong?
There are a few issues here.
For example:
userArray.userId
This part of the code is definitively invalid. Arrays have indexes, not keys like objects, for example. This means you cannot access the userId param, as you haven't defined in which index it is.
Considering your array has two items:
let userArray = [
{ name: 'user1', userId: 101 }, // index 0
{ name: 'user2', userId: 102 } // index 1
];
You would need to access the user id in the following fashion:
userArray[0].userId // Returns 101
userArray[1].userId // Returns 102
As for the request itself, it could look like something like this:
let apisource = www.exampleapi.com;
let classId = 12345;
$.ajax({
type: 'POST',
url: apisource,
data: JSON.stringify({ userId: userArray[0].userId, classId: classId }),
contentType: "application/json"
});
Fist of all, you cant access to userId property of the userArray, you need to pick the object first like "userArray[0].userId" or any logic to get one element.
In other hand, i recommed you to use the fetch function, is easier to use and the code look more clean with promise.
var apisource = 'https://example.com/';
var data = {}; // the user picked
fetch(apisource , {
method: 'POST', // or 'PUT'
body: JSON.stringify(data), // data can be `string` or {object}!
headers:{
'Content-Type': 'application/json'
}
}).then(res => res.json())
.catch(error => console.error('Error:', error))
.then(response => console.log('Success:', response));
source: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
It looks like you need to refactor your post implementation this way to avoid some syntax errors.
function getStudents(classId, userArray) {
$.post( apisource + "classes", {
userId: userArray.userId,
classId: classId
})
.done(function( data, status ) {
console.log("students in class loaded")
});
}