I have a basic API built in Laravel and a React app that is running alongside it. I'm making a PUT request to update some data via React Query, which works fine and the data goes through. I was looking to extend it to handle server-side validation errors (essentially calling Formik's setErrors on them). Laravel back-end responds with a 422 error, as expected, and I can see JSON with the field errors in the Network tab. However, trying to get hold of the error object in react-query mutation's callback only gives me text content:
VM3965 update-form.tsx:61 Error: Request failed with status code 422
at createError (createError.js?770c:16:1)
at settle (settle.js?8768:17:1)
at XMLHttpRequest.onloadend (xhr.js?1a5c:66:1)
I sort of expected to be able to get hold of the error object containing the JSON with validation errors here. Probably missing something obvious.
Here's what the mutation hook looks like:
export const useUpdateClient = (id: string) => {
const queryClient = useQueryClient()
return useMutation(
(newClient: Client) => axios.put(`/api/clients/${id}`, newClient),
{
onSuccess: () => queryClient.invalidateQueries(['clients']),
},
)
}
and this how I call it from the component:
const updateClient = useUpdateClient(id)
const handleSubmit = (
values: Client,
{ setErrors }: FormikHelpers<Client>,
) => {
updateClient.mutate(values, {
onSuccess: () => {
onClose(),
toast({
title: 'Client updated',
status: 'success',
})
},
onError: error => console.log(error), // <<< this only prints text
})
}
Related
I'm coding in a typescript environment.
And graphql subscription sometimes not getting a response..
I guessed It had unsubscribed(in the return part) before it got a response.
Even if a log is added to the return part, no log is written to the console.
So I don't know why.
If I do not receive a response, How should I add the processing source?
Help me please...
const subscription: Observable<object> = API.graphql(graphqlOperation(onSubscription, {studentId: studentId}) as Observable<object>;
const sub = subscription.subscribe({
next: async(data: any) => {
//On success, the processing source
sub.unsubscription();
},
error: (error: any) => {
//On fail, the processing source
sub.unsubscription();
}
});
return () => {
sub.unsubscription();
}
Is there a way to see all available error messages that are returned from the #aws-amplify/auth Auth methods?
When calling Auth.forgotPassword with the correct username, I receive the verification code to reset my password. However, when I put an invalid username, there is no error. Am I doing something incorrect here? I receive the LimiteRateExceeded error when trying too many times but nothing else.
Its worth noting that I am not using the default amplify react ui and am using my own form that calls the onSubmit.
Here is my onSubmit function that calls Auth.forgotPassword
const onSubmitStep1 = async (formData: any) => {
console.log('formData1', formData)
setSubmitting(true)
await Auth.forgotPassword(formData.email)
.then(() => {
setSubmitting(false)
stepForward()
})
.catch((err) => {
console.log(err.message)
setAmplifyErrors({
...amplifyErrors,
form1: err.message,
})
})
}
As the title mention, I tried to combine react-query and react-useform.
but somehow, form data that are handled by use-form is empty when i tried to send them via api reques. I know there should be something wrong with my code since the data are perfecty sent on the next form submit.
here is my code :
const [formData, setFormData] = useState();
const {
register,
handleSubmit,
watch,
formState: { errors },
} = useForm({
criteriaMode: 'all',
});
...
const { isFetching, isSuccess, isError, refetch } = useQuery(
'login',
() => userApi.login(formData),
{
onError: (res) => {
if (res.response.data) {
setErrorData(res.response.data.errors);
}
},
onSuccess: (res) => {
const userReqData = res.data.payload.user;
setUser(userReqData);
setErrorData({ errors: {} });
localStorage.setItem(
'access_token',
`Bearer ${res.data.payload.access_token}`
);
setTimeout(() => {
if (userReqData.level === 'admin' || userReqData === 'head_admin') {
navigate('/admin');
} else {
navigate('/me');
}
}, 2000);
},
enabled: false,
retry: false,
}
);
...
function handleLogin(data, e) {
// MAYBE THIS IS THE PROBLEM, formData sould be properly set first , but somehow it doesn't. The 'setFormData' works properly, but the 'formData' state is not updated on the first request(still empty, but not empty on console.log) . Instead, 'formData' is sent on the second request, which is strange.
setFormData(data);
refetch();
// or is there any other way to make refetch send the actual data from the handleLogin parameter right to the useQuery hook?
}
...
return (
<form
onSubmit={handleSubmit(handleLogin)}
>
...
</form>
)
'userApi' is an axios request that have been modifided with custom baseurl and headers, so, basicaly it's just a normal axios request.
library that i used :
react-query : https://react-query.tanstack.com/
https://react-hook-form.com/api/useform
You should use useQuery to fetch data, not to perform actions.
From the docs:
A query is a declarative dependency on an asynchronous source of data that is tied to a unique key. A query can be used with any Promise based method (including GET and POST methods) to fetch data from a server. If your method modifies data on the server, we recommend using Mutations instead.
Unlike queries, mutations are typically used to create/update/delete data or perform server side-effects
Here is a great resource that might help you refactor the code to a mutation.
Hi I recently learned the new react toolkit with the rtk query tool, and I am trying to put in a login system together using the createApi from the rtk package.
After giving it a test on the login button pressed, I see the network request going through without any issue(status code 200), and I get a response object providing user, token, however, when I try to get the returning data using useLoginMutation I get an undefined value.
below is the code for my endpoint which is injected in a base api:
export const apiLogin = theiaBaseApi.injectEndpoints({
endpoints: (build) => ({
loginUser: build.mutation<UserReadonly, loginValuesType | string>({
query: (values: loginValuesType, redirect?: string) => {
const { username, password } = values;
const header = gettingSomeHeaderHere
return {
url: "login",
method: "GET",
headers,
crossDomain: true,
responseType: "json",
};
},
}),
}),
});
export const { useLoginUserMutation } = apiLogin
then inside my React component I destructure the mutation result such like below:
const [login, {data, isLoading}] = useLoginUserMutation();
const submitLogin = () => {
// pass in username password from the form
login({username, password});
}
Suppose if I console log out data and isLoading I assume that I will see data: {user: "abc", token: "xyz"}, because under network tab of my inspect window I can see the response of this network request, but instead I am seeing data: undefined
Does any have experience on solving this?
Oh I found the reason, it was a very careless mistake. I had to wrap the reducer to my store, which was what I was missing
In my case the issue was that I was trying to access the UseMutationResult object inside onClick callback. And the object was not updating inside the callback, even though in the component the values were accurate.
If I put the log outside it's working just fine.
here is an example for better understanding (inside handleAddPost the mutationResult is not updating)
Here is a code sample (in case link is not working):
const Component = () => {
const [addPost, mutationResult] = useAddPostMutation();
...
const handleAddPost = async () => {
...
console.log("INSIDE CALLBACK isLoading and other data is not updating:");
console.log(JSON.parse(JSON.stringify(mutationResult)))
...
};
// in the example this is wrapped in an useEffect to limit the number of logs
console.log(mutationResult.data,"OUTSIDE CALLBACK isLoading and other data is working:")
console.log(JSON.parse(JSON.stringify(mutationResult)))
return (
...
<Button
...
onClick={handleAddPost}
>
Add Post
</Button>
...
I'm trying to set up a basic graphQL subscription to update a list of messages whenever one is crated, based off the recipes in Nader Dabit’s book and in this Medium post, and my subscription is just never firing in the client. What's strange is that in the query editor in Amplify’s Admin UI, the subscription fires as expected. In the app, however, it’s crickets. No errors, nothing.
As far as I can tell, the only thing unusual about my version is the typescript (and the //#ts-ignore’s that are required to account for the SDK’s lack of an Observable type).
Creating the message:
const handleMessageSubmit = async () => {
try {
const response = await API.graphql(
graphqlOperation(mutations.createMessage, {
input: {
authorID: userState.person.id,
text: message,
messageGroupID,
},
}),
);
} catch (err) {
console.log(err);
}
};
The subscription:
useEffect(() => {
const subscription = API.graphql(
graphqlOperation(subscriptions.onCreateMessage),
// #ts-ignore
).subscribe({
next: (event: any) => {
console.log('new message:', event);
},
error: (error: any) => {
console.log(error);
},
});
return () => {
console.log('unsubscribing');
// #ts-ignore
subscription.unsubscribe();
};
}, [messages]);
Turns out it was a problem with my imports.
Incorrect: import API from '#aws-amplify/api'
Correct: import { API } from '#aws-amplify'
The incorrect API worked just fine for other graphQL queries, but it was borking subscriptions.
I should also note that the failure was generating a AWSAppSyncProvider.ts:204 Uncaught (in promise) undefined error in the console, which I hadn't noticed earlier, though that didn't help much toward finding the solution.