Iterate through promise object in react component - javascript

How can I iterate through the promise object I have returned from my API call.
const [productData, setProductData] = useState(null)
useEffect(() => {
getProductdata()
}, [])
async function getProductdata(){
const secret = "SECRET"
const request = await fetch(`https://app.myapi.com/api/products/id`, {
headers: {
'Authorization': `Basic ${btoa(secret)}`,
'Accept': 'application/json'
}
}).then((request)=>{setProductData(request.json())})
}
console.log("pdata",productData)

If you're using Promise with then then you should do as:
function getProductdata() {
const secret = "SECRET";
fetch(`https://app.myapi.com/api/products/id`, {
headers: {
Authorization: `Basic ${btoa(secret)}`,
Accept: "application/json",
},
})
.then((res) => res.json())
.then(data => setProductData(data);
}
console.log("pdata", productData);

Just await the promise before you call setProductData:
const request = await fetch(`https://app.myapi.com/api/products/id`, {
headers: {
'Authorization': `Basic ${btoa(secret)}`,
'Accept': 'application/json'
}
})
const json = await request.json();
setProductData(json);

Related

Add additional headers in Axios create function

I have this already made function to send requests from Axios,
export const http = axios.create({
baseURL: 'https://someurl/api',
headers: {
'Content-type': 'application/json',
Accept: 'application/json',
},
});
So I can call this method anywhere in my application,
import {http} from 'src/helpers/HttpHelper';
http
.post(
'/users',
{name: 'mishen'},
)
.then(res => console.log(res))
.catch(error => console.log());
Since there are protected routes too which require a bearer token I tried to do something like this inside my component,
import {useContext} from 'react';
import {http} from 'src/helpers/HttpHelper';
const MyComponent = () => {
const {userToken} = useContext(AuthContext);
const signUpUser = () => {
http
.post(
'/app_user_role_selection',
{name: 'mishen'},
{headers: {Authorization: `Bearer ${userToken}`}}
)
.then(res => console.log(res))
.catch(error => console.log());
}
...
}
However, this is not working.
You can use axios interceptors.
export const http = axios.create({
baseURL: "url",
headers: {
"Content-type": "application/json",
Accept: "application/json"
}
});
http.interceptors.request.use(async (config) => {
const value = await AsyncStorage.getItem("your key");
if (value !== null) {
config.headers["Authorization"] = `Bearer ${value}`;
}
return config;
});
const MyComponent = () => {
const signUpUser = () => {
http
.post(
"/app_user_role_selection",
{ name: "mishen" }
)
.then((res) => console.log(res))
.catch((error) => console.log());
};
};

Why does fetch call with Formdata empty map in testing fetch call using react?

Trying to test a fetch call with Formdata in react app with jest.
export const submitform = async (url:string, file:File, params:{}) => {
const body = new FormData()
body.append('file', file)
if (Object.keys(params).length > 0) {
Object.keys(params).forEach(key => {
body.append(key, params[key])
})
}
const res = await fetch(url, {
method: 'post',
headers: {
authorization: `Bearer ${'abc'}`
},
body
})
return res.json()
}
I have a file, that I will be getting in the form and few additional parameters.
Here is the test that I have set up.
test.js
const myParams = { a: 'a', b: 'b' }
const response = await submitform(postUrl, file, myParams)
expect(fetch).toHaveBeenCalledTimes(1)
expect(fetch).toHaveBeenCalledWith(
"/url",
expect.objectContaining({
method: 'post',
headers: {
authorization: `Bearer ${'abc'}`
},
body: myParams
})
)
I get this error In logs:
Error: expect(jest.fn()).toHaveBeenCalledWith(...expected)
Expected: "/url", ObjectContaining {"body": {"a": "a", "b": "b"}, "headers": {"authorization": "Bearer abc"}, "method": "post"}
Received: "/url", {"body": {}, "headers": {"authorization": "Bearer abc"}, "method": "post"}
Number of calls: 1
I have tried logging at different steps.
I have received the data in the function and right before the function call.
console.log('BODY', body)
console.log('FILE', body.get('file'))
console.log('A', body.get('a'))
console.log('B', body.get('b'))
const res = await fetch(url, {
method: 'post',
headers: {
authorization: `Bearer ${'abc'}`
},
body
})
The output is like so:
BODY FormData {}
FILE File {}
A a
B b
So why does the fetch call with empty body?
You can try this:
index.ts:
export const submitform = async (url: string, file: File, params: Record<string, any>) => {
const body = new FormData();
body.append('file', file);
if (Object.keys(params).length > 0) {
Object.keys(params).forEach((key) => {
body.append(key, params[key]);
});
}
const res = await fetch(url, {
method: 'post',
headers: {
authorization: `Bearer ${'abc'}`,
},
body,
});
return res.json();
};
index.test.ts:
import { submitform } from '.';
describe('73309858', () => {
test('should pass', async () => {
expect.assertions(3);
const mResponse = { json: jest.fn().mockResolvedValue({}) };
const mFetch: jest.MockedFunction<typeof fetch> = jest.fn().mockReturnValueOnce(mResponse);
global.fetch = mFetch;
const myParams = { a: 'a', b: 'b' };
const postUrl = '/url';
const file = new File(['a'], 'avatar');
await submitform(postUrl, file, myParams);
expect(mFetch).toHaveBeenCalledTimes(1);
expect(mFetch).toHaveBeenCalledWith(
'/url',
expect.objectContaining({
method: 'post',
headers: {
authorization: `Bearer ${'abc'}`,
},
body: expect.any(FormData),
})
);
const callArgs = mFetch.mock.calls[0][1];
if (callArgs) {
const body = callArgs.body as FormData;
const formData = Array.from(body.entries()).reduce(
(acc, f) => ({ ...acc, [f[0]]: f[1] }),
{} as Record<string, any>
);
expect(formData).toMatchObject(myParams);
}
});
});
package version:
"jest": "^26.6.3",

Uncaught (in promise) TypeError: res.map is not a function

I'm trying to fetch a list of departments from an url in a react native application
import React,{ useState,useEffect} from 'react';
import { StyleSheet, LogBox,View,Text } from 'react-native';
export default function App() {
var [department,setDepartment]=useState([])
const token = /* my token here */
const getDepartments=()=>{
const url = /*my api's url here*/
return fetch(url, {
method: 'GET',
headers: { "Authorization": "Bearer" + token ,
'Accept': 'application/json',
'Content-Type':'application/json'
}
})
.then(response => response.json())
.then(data=>console.log(data)) // returns the correct data
.catch(error => console.error(error))
}
const getdepartment = async () => {
await getDepartments().then((res) => //here lays the problem
{res.map((p, key) => {
department.push({
name: p.name,
id: p.id,
});
});
});
};
useEffect(() => {
getdepartment();
}, []);
return (
<View>
<Text>
{department[0]}
</Text>
</View>
)
}
here res in the getdepartment() function is undefined despite the getDepartments() function returning correct data from the url
You are not returning a value from getDepartments, just a simple console.log.
You can convert the function in async/await:
const getDepartments = async () => {
const url = /*my api's url here*/
try {
const response = await fetch(url, {
method: 'GET',
headers: { "Authorization": "Bearer" + token ,
'Accept': 'application/json',
'Content-Type':'application/json'
}
})
return await response.json();
} catch(e){
// error
}
}
or return a value from your function:
const getDepartments=()=>{
const url = /*my api's url here*/
return fetch(url, {
method: 'GET',
headers: { "Authorization": "Bearer" + token ,
'Accept': 'application/json',
'Content-Type':'application/json'
}
})
.then(response => response.json())
.catch(error => console.error(error))
}
If you are returning the result of the fetch then just return the result obtained from it, the issue is along with fetch, the response is also handled and the complete thing post to that is being returned which is not the result so you just need to skip this line .then(data=>console.log(data))
const getDepartments=()=>{
const url = /*my api's url here*/
return fetch(url, {
method: 'GET',
headers: { "Authorization": "Bearer" + token ,
'Accept': 'application/json',
'Content-Type':'application/json'
}
}).then(response => response.json()).catch(error =>
console.error(error))
}
// Here after fetching the result you can map the data
const getdepartment = async () => {
await getDepartments().then((res) =>
{res.map((p, key) => {
department.push({
name: p.name,
id: p.id,
});
});
});
};

Fetch inside map in react

I'm trying to fetch each campaign stats by its campaignId. campaignId is pulled from first api call and then while iterating i'm passing that id to next api call for each campaign stats. First api call gives the right result but while iterating and fetching it from second api call it throws and error of
Unhandled Rejection (TypeError): ids.map is not a function
export const loadStats = async () => {
const ids = await (await fetch('https://api.truepush.com/api/v1/listCampaign/1', {
method: "GET",
headers: {
Authorization: `${TOKEN}`,
"Content-Type": "application/json"
}
})).json()
const data = Promise.all(
ids.map(async (i) => await (await fetch(`https://api.truepush.com/api/v1/campaignStats/${i.data.campaignId}`, {
method: "GET",
headers: {
Authorization:`${TOKEN}`,
"Content-Type": "application/json"
}
})).json())
)
return data
};
I'm expecting all such stats while iterating:
https://i.stack.imgur.com/8kjwy.png
https://i.stack.imgur.com/VJni7.png (result of listCampaign/1)
Try this:
export const loadStats = async () => {
const ids = await (await fetch('https://api.truepush.com/api/v1/listCampaign/1', {
method: "GET",
headers: {
Authorization: `${TOKEN}`,
"Content-Type": "application/json"
}
})).json()
const data = Promise.all(
ids.data.map(async (i) => await (await fetch(`https://api.truepush.com/api/v1/campaignStats/${i.campaignId}`, {
method: "GET",
headers: {
Authorization:`${TOKEN}`,
"Content-Type": "application/json"
}
})).json())
)
return data
};

Why i got the output as "\"userName\"" and not like that "userName"?

Why i got output "\"userName\"" and not as "userName" ?
in my example i try to do an get api that attach to it some data and that data comes from the async-storage.
when i console the output so its shows the data like that :
"\"userName\""
but it should output "userName" .
what is the way to fix that issue ?
so what is wrong in my way ?
const getSaveUserTokenData = async (data) => {
const url =
'https://URL/userName,userToken,PlatformType,DeviceID?' +
'userName=' +
data.userName +
'&userToken=' +
data.googlToken +
'&PlatformType=' +
data.platformId +
'&DeviceID=' +
data.deviceId;
await fetch(
url,
{
method: 'GET',
headers: {
Authorization: data.azureToken,
},
}
)
.then((response) => response.json())
.then((data) => {
console.log('Success:', data);
})
.catch((error) => {
console.error('Error:', error);
});
};
You can write this way as well:
fetchFunction = async () => {
let data = {
userName: 'jon',
userToken: 'bee22',
PlatformType: 'os-ios',
DeviceID: '222222'
}
const url = `https://yoururl.com/?userName=${encodeURIComponent(data.userName)}&userToken=${encodeURIComponent(data.userToken)}&PlatformType=${encodeURIComponent(data.PlatformType)}&DeviceID=${encodeURIComponent(data.DeviceID)}`;
const response = await fetch(url, {
method: 'GET',
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Accept': 'application/json',
'Content-Type': 'application/json',
},
});
const json = await response.json();
console.log(json);
}
If your variable names are the one you want in your url, try this:
const getData = async () => {
let userName = 'jon';
let userToken = 'bee22';
let PlatformType = 'os-ios';
let DeviceID = '222222';
const queryString = Object.entries({
userName,
userToken,
PlatformType,
DeviceID,
})
.map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
.join('&');
const response = await fetch(
'https://url...?' + queryString
);
};
};
Note: user token should not be in the url but usually in the headers of your request, like so:
fetch(someUrl, {
headers: {
Authorization: userToken
}
});
fetch(`https://yoururl.com/${userName}`,
{ method: 'GET',
headers: myHeaders,
mode: 'cors',
cache: 'default'
})
.then(function(response) {
//your code here
});
A more generic solution would be something like this:
async function get(route, ...params) {
const url = `${route}${params.map(p => `/${p}`)}`;
const response = await fetch(url, { method: "GET", headers });
if (!response.ok)
throw new Error(`Http error status: ${response.status}`);
return response.json();
}
by using ...params you can pass a generic amount of parameters that will then be combined with:
const url = `${route}${params.map(p => `/${p}`)}`;
In your case you would call the method like this:
const result = await get("https://url..", "jon", "bee22", "os-ios", "222222");

Categories