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.
Related
The problem:
Nothing happends when throwing throw redirect(302, '/auth/sign-up-success') in SvelteKit's actions if onSuccess: () => {...} is set in Felte's createForm({...}).
Example:
// +page.server.ts
export const actions: Actions = {
default: async (event) => {
...
throw redirect(302, '/auth/sign-up-success');
}
}
// SignUpForm.svelte
const { form, errors } = createForm({
onSuccess: (response) => {
invalidate('app:auth')
},
...
}
If I would delete the onSuccess part, then redirect would happend.
Question:
Is there a way to reuse that redirect form success response logic from default Felte form config without writing it again myself?
Action responses are JSON objects with a type, you could read the response and redirect on the client:
async onSuccess(response) {
const { type, location } = await response.json();
if (type == 'redirect') {
goto(location); // from '$app/navigation'
return;
}
}
I would not recommend using this library though. It appears to be incompatible with SSR and one of its main actions shares the name of the form data property used by SvelteKit form actions.
Depending on why you are using this, there might be more suitable tools for SvelteKit in particular (if you even need any, SvelteKit does many things out of the box).
I need to show a toast notification whenever an API call encounters an error. With RTK Query, I can either wrap the query in another function or use a listener middleware.
Wrapping the query function:
const loadFooWithToast = async () => {
const { error } = await loadFooQuery()
if (error) showErrorToast("Error loading Foo")
}
Note: To make this more generic (like the example below) I could create a custom hook which accepts the query function and the error message as arguments but the logic would stay the same.
Using a listener middleware:
startAppListening({
predicate: (action) => {
return action.type === "api/executeQuery/rejected"
},
effect: ({
meta: {
originalArgs: { errorMessage }
},
}) => {
showErrorToast(errorMessage)
},
})
loadFooQuery({ errorMessage: "Error loading Foo" })
Is one method preferable to the other and why?
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();
}
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
})
}
I am using a context configuration (not redux) that consists of three files. A state file, reducer file, and context file. It makes an axios call to my Atlas MongoDB collection. I have tested the API using Postman and the get request works as intended, returning a series of transaction data.
The getTransactions() function in the useEffect hook will only return the requested data once. If I make any modifications to the code and save or navigate to a different page and return, the transactions array of objects is now defined as null. My first instinct was that I had an asynchronous syntax error but my understanding of useEffect is that it mitigates async issues.
The function in question looks like this:
const initialState = {
transactions: null,
current: null,
filtered: null,
error: null
};
const getTransactions = async () => {
try {
const res = await axios.get("/api/transactions");
dispatch({ type: GET_TRANSACTIONS, payload: res.data });
} catch (err) {
dispatch({ type: TRANSACTION_ERROR, payload: err.response.msg });
}
};
The reducer handles the type dispatched by the state function inside a switch statement:
case GET_TRANSACTIONS:
return {
...state,
transactions: action.payload,
loading: false,
};
I make the following call in my react component:
useEffect(() => {
getTransactions();
// eslint-disable-next-line
}, []);
My API is running on a node server that uses a route that first checks for user auth and then queries the database. Again, the API has been tested and returns the data as expected given there is a valid JWT auth token in the headers. The route is below:
router.get("/", auth, async (req, res) => {
try {
const transactions = await Transaction.find({ user: req.user.id }).sort({
date: -1,
});
res.json(transactions);
} catch (err) {
console.error(err.message);
res.status(500).send("Server Error");
}
});
I need to be able to have the data returned consistently in my component in an array of objects called transactions so it can be mapped to populate a DOM element. I have tried to provide as much of the code here as I felt was relevant but if I'm missing something, I can share that. All required imports have been doublechecked and are correct. I have not included the import lines in this question to conserve space. Thanks in advance!