I would like to make a request about the api rick and morty. To get the details of a character, you have to specify an id as a parameter:"https://rickandmortyapi.com/api/character/id"
I use redux-saga to fetch my request, but the request fails with a message:
" Hey! that parameter is not allowed, try with a number instead;)"
I tried the request with the id received in my component and the request is effective. I think it comes either from my action or my saga.......
here is my action :
export const getCharactersDetails = () => {
return { type: GET_CHARACTER_DETAILS }
}
here is my saga :
const getLatestDetails = (id) =>
fetch('https://rickandmortyapi.com/api/character/' + id);
export function* fetchCharacterDetails() {
try {
let myCharacter;
const response = yield call(getLatestDetails);
const result = yield response.json();
if (result.error) {
yield put({ type: DETAILS_REQUEST_FAILED, error: result.error });
} else {
myCharacters = result.results
yield put({ type: DETAILS_RECEIVED, character: myCharacter });
}
} catch (error) {
yield put({ type: DETAILS_REQUEST_FAILED, error: error.message });
}
}
function* actionWatcher() {
yield takeLatest(GET_CHARACTERS, fetchCharacters)
yield takeLatest(GET_CHARACTER_DETAILS, fetchCharacterDetails)
}
and i call my action like that:
let CharacterId = this.props.navigation.state.params.id
this.props.dispatch(getCharactersDetails(CharacterId))
any idea what I'm not doing right?
You are not passing any ID to your getLatestDetails function.
Add the ID to the action you are creating:
export const getCharactersDetails = id => {
return { type: GET_CHARACTER_DETAILS, id }
}
…then add the ID from the action as parameter to your saga and pass it as second argument to your call effect:
export function* fetchCharacterDetails({ id }) {
try {
let myCharacter;
const response = yield call(getLatestDetails, id);
const result = response.json();
if (result.error) {
yield put({ type: DETAILS_REQUEST_FAILED, error: result.error });
} else {
myCharacters = result.results
yield put({ type: DETAILS_RECEIVED, character: myCharacter });
}
} catch (error) {
yield put({ type: DETAILS_REQUEST_FAILED, error: error.message });
}
}
Additional explanation:
The saga gets the action as argument; we are using destructuring here to get just the ID (note the curly braces)
call accepts the function to be called as first parameter, followed by additional arguments passed to the function, this is how getLatestDetails gets the ID
I removed yield before response.json(), this is just a plain old synchronous operation
Related
In trying to execute this action, and while I'm getting the correct data in response on the backend, the data variable is coming back undefined. I'm also getting a TS error saying Property 'data' does not exist on type 'void'
action/churches.js
export const getChurchesBySearch = (searchQuery) => async (dispatch) => {
try {
const { data } = await apis.getChurchesBySearch(searchQuery);
dispatch({ type: "FETCH_BY_SEARCH", payload: data });
} catch (error) {
console.log(error.message);
}
};
Like I mentioned, the correct response is being returned on the backend, but when assigning it to data, data is undefined.
Here are the other files:apis/churches.js
export const getChurchesBySearch = (searchQuery) => {
console.log(searchQuery.city);
axios.get(
`${url}/search?city=${searchQuery.city}&denom=${searchQuery.denom}`
);
};
controller/churches.js
export const getChurchesBySearch = async (req, res) => {
const { city, denom } = req.query;
try {
const churches = await Church.find({
$or: [{ city: city }, { denom: denom }],
}).sort({ attend: -1 });
res.status(200).json(churches);
} catch (error) {
res.status(404).json({ message: error.message });
}
};
You are missing the return statement in the getChurchesBySearch function.
export const getChurchesBySearch = (searchQuery) => {
console.log(searchQuery.city);
return axios.get(
`${url}/search?city=${searchQuery.city}&denom=${searchQuery.denom}`
);
};
I'm trying to fetch some data from a endpoint. But when i console.log my response i get undefined. And when I run console.log(g.next().value) I get this in the console {##redux-saga/IO: true, combinator: false, type: "CALL", payload: {…}}. Is the Yield call not executing or?
export function* g2(filterKey: string, filterValue: string) {
try {
const response: Response = yield call(fetchEnglishFilterValue, appSettings.language, filterKey, filterValue);
console.log("response: ", response);
const data: string = yield call([response, response.json]);
console.log("data: ", data);
return data;
} catch (e) {
console.log(e)
}
}
I need to test redux saga with jest. But it's not working. Here is what I tried
service.js
class Login {
login = async (user: any) => {
try {
const response = await axios({
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
url: `${API.BASE_URL}signIn`,
data: JSON.stringify({
LoginID: user.LoginID,
Password: user.Password,
}),
});
return Bluebird.resolve(response.data);
} catch (err) {
return Bluebird.reject(err);
}
}
}
export default new Login();
worker.js
export function* loginWorker(action) {
try {
const response = yield call(service.login, action.payload);
if (response.Success) {
yield put({type: actionTypes.LOGIN_SUCCESS_ACTION, response});
} else {
toastr.showToast(response.Message);
yield put({type: 'LOGIN_FAILURE', response});
}
} catch (err) {
// dispatch a failure action to the store with the error
yield put({type: 'LOGIN_FAILURE', err});
toastr.showToast(err);
}
}
test.js
describe('test login', () => {
const action = {
type: actionTypes.LOGIN_ACTION,
payload: user,
};
it('login', () => {
const gen = loginWorker(action);
expect(gen.next().value).toEqual(call(service.login, action.payload));
expect(gen.next().value).toEqual(put({type: actionTypes.LOGIN_SUCCESS_ACTION, response}));
});
});
But this function service.login not to be called and I get this error
Cannot read property 'Success' of undefined
Where is my wrong? Please help
I tried to make an API call, but the yield put fired before the yield call finished the execution. Here is my code:
Api.js
function callApi(endpoint, token = null) {
const fullUrl =
endpoint.indexOf(API_ROOT) === -1 ? API_ROOT + endpoint : endpoint;
return axios
.get(fullUrl, { headers: { Authorization: token } })
.then(resp => {
return Object.assign([], resp.data);
})
.catch(error => ({ error: error.message || "Something bad happened" }));
}
export const checkOpenRegister = (branchId, userId, token) => {
console.log("in check open");
callApi(
`Branches/${branchId}/registers?filter[where][status]=1&filter[where][userId]=${userId}`,
token
);
};
and in my saga index.js
function* doCheckAuthInfo() {
try {
const user = yield select(getUser);
if (user.token) {
yield put({
type: CHECK_AUTH_INFO_SUCCEED,
payload: { token: user.token }
});
yield put({ type: CHECK_OPEN_REGISTER_REQUESTED });
} else {
//redirect to login
yield put(NavigationActions.navigate({ routeName: "Login" }));
}
} catch (error) {
yield put({ type: CHECK_AUTH_INFO_FAILED, error });
}
}
function* doCheckOpenRegister() {
try {
const user = yield select(getUser);
const response = yield call(
checkOpenRegister,
user.branchId,
user.userId,
user.token
);
yield put({ type: CHECK_OPEN_REGISTER_SUCCEED, payload: response });
} catch (error) {
yield put({ type: CHECK_OPEN_REGISTER_FAILED, error: error.message });
}
}
function* watchCheckAuthInfo() {
yield takeLatest(CHECK_AUTH_INFO_REQUESTED, doCheckAuthInfo);
}
function* watchCheckOpenRegister() {
yield takeLatest(CHECK_OPEN_REGISTER_REQUESTED, doCheckOpenRegister);
}
// use them in parallel
export default function* rootSaga() {
yield all([
fork(watchCheckAuthInfo),
fork(watchCheckOpenRegister)
]);
}
In my saga, on function doCheckOpenRegister, yield PUT fired with no payload but I can find the payload in my network debugger.
I need the payload to trigger action to redirect. In this case, when there is a value in response I need to redirect to main page.
you forgot return Promise from function checkOpenRegister
export const checkOpenRegister = (branchId, userId, token) => {
console.log("in check open");
return callApi(
`Branches/${branchId}/registers?filter[where][status]=1&filter[where][userId]=${userId}`,
token
);
};
I have a redux-saga as below:
export function* loadApplianceSaga() {
try {
let {request, success, error} = yield take(ActionTypes.APPLIANCE.LOAD);
request.url = yield select(getResourceLink, request.resource);
const response = yield call(makeRequest, request);
if (!response.error) {
yield put({type: success, payload: response.body});
} else {
yield put({type: error, payload: response});
}
} catch (e) {
yield put({type: ActionTypes.REQUEST.CALL_ERROR, error: e});
}
}
export function* watchLoadAppliance() {
while (true) {
yield* takeEvery(ActionTypes.APPLIANCE.LOAD, loadApplianceSaga);
}
}
and root saga:
export default function* rootSaga() {
yield [
fork(watchLoadAppliance)
]
}
I'm facing a problem that loadApplianceSaga doesn't work at the first time. I logged and saw that in the first time it only dispatched ActionTypes.APPLIANCE.LOAD action then no action is dispatched. But in the second time, I can see success action or failed action which are dispatched.
Could anyone tell me what was wrong? Thanks in advance!
Updated action:
export const loadAppliances = () => {
return {
type: ActionTypes.APPLIANCE.LOAD,
request: {
resource: Resources.Appliances,
param: {
page: 0,
size: 5,
sort: 'name,desc'
},
header: {
Accept: 'application/json'
}
},
success: ActionTypes.APPLIANCE.LOAD_SUCCESS,
error: ActionTypes.APPLIANCE.LOAD_ERROR
}
};
you have used take two times.
try
export function* loadApplianceSaga(action) {
try {
let {request, success, error} = action;
request.url = yield select(getResourceLink, request.resource);
const response = yield call(makeRequest, request);
if (!response.error) {
yield put({type: success, payload: response.body});
} else {
yield put({type: error, payload: response});
}
} catch (e) {
yield put({type: ActionTypes.REQUEST.CALL_ERROR, error: e});
}
}
export function* watchLoadAppliance() {
while (true) {
yield* takeEvery(ActionTypes.APPLIANCE.LOAD, loadApplianceSaga);
}
}