nuxt generate payload undefined - static

I have a Nuxt project, in nuxt.config.js file, I have a function like this:
generate: {
async routes() {
function postRoutes() {
return axios
.post('https://my-server.com/api/posts')
.then((r) => r.data.map((post) => {
// I log post data here, it exist
console.log(post)
return {
route: `post/${post.id}`,
payload: 'post'
}
}))
}
const response = await axios
.all([postRoutes()])
.then(function (results) {
const merged = [].concat(...results)
return merged
})
return response
}
},
Then, in pages/post/_slug.vue, in asyncData, when receiving payload object, it returns undefined
async asyncData({ params, error, payload }) { {
console.log(payoad) // return undefined
}
I don't know whether I pass the payload the wrong way or something wrong with Nuxt payload, please help !! thank you in advance

Related

Return the fetch response from another file

I am trying to call a function that calls fetch to an API from a React component in a separate file and am not finding the correct solution to get the correct response back.
When I debug, the result returns before the updateAccount function has completed and the final result is never returned to my update function.
Inside the fetch, the API returns the correct response whether it is successful or has validation errors and those results are correctly assigned to result.success and result.errors but the result doesn't get returned from the function so that the caller can make use of those values.
Inside of my React component:
import { updateAccount } from '../services/requests';
...
const update = (account: EditAccountModel) => {
const result = updateAccount(account);
if(result.errors.length > 0) {
// will notify of errors
console.log(result.errors); // is an empty array instead of validation errors
} else {
// will notify of success
console.log(result.success); // is an empty string instead of success message
}
}
...
My request file
export const updateAccount = (account: EditAccountModel | undefined): EditAccountResponseModel => {
const result = new EditAccountResponseModel();
fetch(baseUrl, {
method: 'PUT',
body: JSON.stringify(account),
headers
})
.then(response => {
if (!response.ok) {
return Promise.reject(response);
}
result.success = `${account?.name} was updated successfully!`
})
.catch(error => {
if (typeof error.json === "function") {
error.json().then(jsonError => {
result.errors.push(jsonError);
}).catch(genericError => {
result.errors.push(genericError);
});
}
});
return result;
}
The result reassignment happens inside then catch but it won’t be affective in the way you expected. The guaranteed way to return correct result is via a callback() passed to your updateAccount() if you could afford it:
export const updateAccount = (
account: EditAccountModel | undefined,
callback: Function
): EditAccountResponseModel => {
const result = new EditAccountResponseModel();
fetch(baseUrl, {
method: 'PUT',
body: JSON.stringify(account),
headers
})
.then(response => {
if (!response.ok) {
return Promise.reject(response);
}
result.success = `${account?.name} was updated successfully!`
callback(result);
})
.catch(error => {
if (typeof error.json === "function") {
error.json().then(jsonError => {
result.errors.push(jsonError);
callback(result);
}).catch(genericError => {
result.errors.push(genericError);
callback(result);
});
}
});
}
And inside your React component:
const update = (account: EditAccountModel) => {
const handleResult = (res) => {
// your result callback code
// ...
};
updateAccount(account, handleResult);
// ...
}
Alternative way that keeps your current structure is to change your current updateAccount() to an async function, then return await fetch().
You need to wait for the response . I'll let read more about how Promise work in JavaScript.
I wouldn't code updateAccount the same way you did, especially where you use the variable result and update it inside the flow of the promise (you really don't need that). You're also using React so you can use the state to store and update the result of the update function. But let's fix your problem first:
export const updateAccount = async (account: EditAccountModel | undefined): EditAccountResponseModel => {
const result = new EditAccountResponseModel();
await fetch(baseUrl, {
method: 'PUT',
body: JSON.stringify(account),
headers
})
.then(response => {
if (!response.ok) {
return Promise.reject(response);
}
result.success = `${account?.name} was updated successfully!`
})
.catch(error => {
if (typeof error.json === "function") {
error.json().then(jsonError => {
result.errors.push(jsonError);
}).catch(genericError => {
result.errors.push(genericError);
});
}
});
return result;
}
First make your function updateAccount async then await the result of the promise.
Now the same thing for the function update:
const update = async (account: EditAccountModel) => {
const result = await updateAccount(account);
if(result.errors.length > 0) {
// will notify of errors
} else {
// will notify of success
}
}

How to Create Middleware for refresh token in Reactjs with axios and redux

i am working with reactjs on front end the issue is after certain time period the accessToken is expired and server send status of 401(unauthorized) then i need to send refresh token back to server it works fine until i manually send the refresh token i set the setInterval function but thats not a good approach how to automatically send it when token is expired.
i also google it but everyone is talking about creating middleware anyone please give me the hint how to create that middleware or any other solution or link any article related to it . i created this but this didnt works for me however when server send status of 401 then middleware ran but it dosent dispatch my refreshToken() function
const customMiddleWare = store => next => action => {
axios.interceptors.response.use(function (response) {
return response;
}, function (error) {
if(error.status === 401) {
// do something when unauthorized
store.dispatch(refreshToken());
}
return Promise.reject(error);
});
console.log("Middleware triggered:", action);
next(action);
}
By the way i am using redux, redux-thunk and axios. thanks,
some time ago i used to use the next way:
First of all i created some api folder, where each function returns data for axios requests
// /api.js
export function signIn (data) {
return {
method: 'post',
api: '/sign-in'
data: data
}
}
export function signUp (data) {
return {
method: 'post',
api: '/registration'
data: data
}
}
then i generated action type by specific rule, like: SIN_IN_REQUEST, where: SIGN_IN means signIn function in /api.js; REQUEST means that you need to do api request. As result my middleware looked like the next:
// request middleware
const instance = axios.create({
baseURL: '/api'
});
function camelize(str) {
return str.replace(/(?:^\w|[A-Z]|\b\w)/g, function(word, index) {
return index === 0 ? word.toLowerCase() : word.toUpperCase();
}).replace(/\s+/g, '');
}
const customMiddleWare = store => next => action => {
if (!action.type.endsWith('_REQUEST')) {
next();
return;
}
const methodName = action.type.replace('_REQUEST', ''); // removed _REQUEST from action type
const camelCaseMethodName = camelize(methodName); // the result is "signIn"
const method = api[camelCaseMethodName];
if (!method) {
next();
return;
}
const dataForRequest = method(action.payload);
try {
const response = await instance(dataForRequest);
const newActionType = action.type.replace('_REQUEST', '_SUCCESS');
dispatch({
type: newActionType,
payload: {
requestPayload: action.payload,
response: response,
}
})
} catch(error) {
if (error.status === '401') {
dispatch(refreshToken());
next();
return;
}
const newActionType = action.type.replace('_REQUEST', '_FAILURE');
dispatch({
type: newActionType,
payload: {
requestPayload: action.payload,
error: error,
}
})
}
next();
}
After that you can easily manage any api request in your application like that:
function someTHunkMethod(username, password) {
return (dispatch, getState) => {
dispatch({
type: 'SIGN_IN_REQUEST',
payload: {
username,
password
}
})
}
}
function oneMoreThunk(data) {
return (dispatch, getState) => {
dispatch({
type: 'GET_USERS_REQUEST',
payload: data
})
}
}
And in reducer do something like that
...
switch (action.type) {
case 'SIGN_REQUEST':
return {
isLoading: true,
user: null
}
case 'SIGN_SUCCESS':
return {
isLoading: false,
user: action.payload.response.data
}
case 'SIGN_FAILURE':
return {
isLoading: false,
user: null
}
default:
return state
}

Axios Error Networ error on request Google place api

im trying to make a request to google api but returns me network error. If i put the url in the browser, brings me the information correctly.I tryed to formate the request without success. The google places search works correctly too.
export const fetch_information = (skip, limit, filter) => async (dispatch) => {
try {
var url = `https://maps.googleapis.com/maps/api/place/details/json?place_id=ChIJk0aJYPbk3JQRLpKN20Jecko&fields=name,rating,formatted_phone_number&key=MyKey`;
const {data} = await axios.get(url)
console.log(data)
} catch (error) {
console.log(error.message)
}
}
and
export const fetch_information = (skip, limit, filter) => async (dispatch) => {
try {
var url = `https://maps.googleapis.com/maps/api/place/details/json?`;
let config = {
params: {
place_id: 'ChIJk0aJYPbk3JQRLpKN20Jecko',
key: 'myKey',
},
}
const {data} = await axios.get(url, config)
console.log(data)
} catch (error) {
console.log(error.message)
}
}
I think that the request looks a bit messy. I'm under the impression that you are trying to pass results to a redux store. Let's see if we can clean this up a bit.
export const fetch_information = async () => dispatch => {
const req = await axios.get("https://maps.googleapis.com/maps/api/place/details/json?place_id=ChIJk0aJYPbk3JQRLpKN20Jecko&fields=name,rating,formatted_phone_number&key=MyKey");
const data = await req.json();
return data;
//or, for your purpose...
console.log(data);
//can also dispatch for store
}
I didn't see anything you were passing as necessary for this.

Testing fetch using Jest- React Native

I have a common api class that i use for handling api calls in React Native. It will make the call and get the json/ error and return it. See the code below.
// General api to acces data from web
import ApiConstants from './ApiConstants';
export default function api(path,params,method, sssid){
let options;
options = Object.assign({headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}},{ method: method }, params ? { body: JSON.stringify(params) } : null );
return fetch(ApiConstants.BASE_URL+path, options).then( resp => {
let json = resp.json();
if (resp.ok) {
return json;
}
return json.then(err => {
throw err;
}).then( json => json );
});
}
But when i write the jest test to mock the api as folllows in tests folder.
test('Should login',() => {
global.fetch = jest.fn(() => new Promise((resolve) => {
resolve( { status: 201, json: () => (mock_data_login) });
}));
return Api(ApiConstants.LOGIN,{'un':'test1','pwd':'1234'},'post', null).then((data1)=>{
expect(data1).toBeDefined();
expect(data1.success).toEqual(true);
expect(data1.message).toEqual('Login Success');
});
});
it fails with:
TypeError: json.then is not a function
When I change the fetch return to this, the test passes:
return fetch(ApiConstants.BASE_URL+path, options).then( resp => {
let json = resp.json();
return json
});
}
Why is this type error error popping up? I can't change the API module, because that will my redux saga code to change. What should I do?
In your code, json is just an Object and not a Promise, so then is undefined. That's the complain you are getting because you are trying to use undefined as a function. The problem is not in the test but in your code that ha san error. Try the following instead.
return fetch(ApiConstants.BASE_URL+path, options)
.then(resp => resp.json())
.then( json => json)
.catch((error) => error);
});
Edit: oh, just read you can't make changes to the component where the error occurs?
Try converting your fetch like this:
return fetch(ApiConstants.BASE_URL+path, options)
.then(resp => {
let json = resp.json();
if (resp.ok) {
return json;
} else {
throw Error(resp.error) // assuming you have some kind of error from endpoint?
}
})
.then(/*handle your ok response*/)
.catch(/*handle your error response*/);
I faced the same issue, The problem is that you are mocking only response.json as function but it should be a Promise, Like this,
global.fetch = jest.fn(() => new Promise((resolve) => {
resolve( { status: 201, json: () => {
return Promise.resolve(mock_data_login);
}
});
}));
This will return a Promise for you json function.
Hope this fix your problem.

How to chain 2 API calls with redux thunk?

I'm making a weather app, which detects your current location's coordinates by making an API call to freegeoip.com, then takes those coordinates to make an API call to openweathermap.org to fetch your current location's weather.
How would I do this with redux thunk?
This is my current action creator code:
import axios from 'axios';
export const FETCH_CURRENT_CITY = 'FETCH_CURRENT_CITY';
const API_KEY = '95108d63b7f0cf597d80c6d17c8010e0';
const ROOT_URL = `http://api.openweathermap.org/data/2.5/weather?appid=${API_KEY}`;
export function fetchCurrentCityCoords() {
const request = axios.get('http://freegeoip.net/json/');
console.log('Request coords:', request);
return (dispatch) => {
request.then(({response}) => {
dispatch(fetchCurrentCityWeather(response));
});
};
}
export function fetchCurrentCityWeather(coords) {
const lat = coords.data.latitude;
const lon = coords.data.longitude;
const url = `${ROOT_URL}&lat=${lat}&lon=${lon}`;
const request = axios.get(url);
console.log('Request weather:', request);
return (dispatch) => {
request.then(({response}) => {
dispatch({
type: FETCH_CURRENT_CITY,
payload: response
})
});
};
}
Console logs:
Request coords: Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
Uncaught (in promise) TypeError: Cannot read property 'latitude' of undefined
at fetchCurrentCityWeather (bundle.js:26131)
at bundle.js:26125
Are you sure the API response holds a data property?
try debugging the first line of fetchCurrentCityWeather function and check what coords holds, or just try console.log(coords); to see it's object structure.
maybe this:
const lat = coords.data.latitude;
const lon = coords.data.longitude;
should be like that:
const lat = coords.latitude;
const lon = coords.longitude;
Edit
following your comment,
for debug purpose try editing your fetchCurrentCityWeather function to this code and see what is printed to the console:
export function fetchCurrentCityWeather(coords) {
console.log(coords);
//const lat = coords.data.latitude;
//const lon = coords.data.longitude;
//const url = `${ROOT_URL}&lat=${lat}&lon=${lon}`;
//const request = axios.get(url);
//console.log('Request weather:', request);
//return (dispatch) => {
//request.then(({response}) => {
// dispatch({
//type: FETCH_CURRENT_CITY,
// payload: response
//})
//});
// };
}
EDIT #2
following your comment, you are getting undefined hence you can't use .map on it. this is your answer to the error.
As for why you are getting undefined, i think it's because this block of code:
return (dispatch) => {
request.then(({response}) => {
dispatch(fetchCurrentCityWeather(response));
});
};
You are doing "Destructuring" to the response parameter with this {response}.
try this instead:
return (dispatch) => {
request.then((response) => {
dispatch(fetchCurrentCityWeather(response));
});
};
Uncaught (in promise) TypeError: Cannot read property 'latitude' of undefined
at fetchCurrentCityWeather (bundle.js:26131)
at bundle.js:26125
Problems appears to be your const lat = coords.data.latitude it's undefined.
So you have to check if the
return (dispatch) => {
request.then(({response}) => {
dispatch(fetchCurrentCityWeather(response));
});
CallsfetchCurrentCityWeather with correct response object you expect to have properties data.latitude & data.longitude you seem to incorrectly refer.
Advise.
console.log(coords); inside fetchCurrentCityWeather function to see if it has those properties.

Resources