How to filter type-graphql subscription using context, instead of args? - typegraphql

I am trying to send notification to different users and want every user to see only his. I have already succeeded to do you with #Args.
Heres the subscribtion:
#Subscription(() => Notification, {
topics: "NOTIFICATIONS",
filter: ({ payload, args }: ResolverFilterData<Notification, NewNotificationArgs>) => {
return payload.userId === args.userId;
},
})
newNotification(
#Root() notification: Notification,
#Args() { userId }: NewRequestArgs
): Notification {
return notification;
}
And the mutation:
#Mutation(() => Boolean)
async createNotification(
#PubSub("NOTIFICATIONS") notifyAboutNewNotification: Publisher<Notification>
): Promise<Boolean> {
const notification = await Notification.create({
userId: <some id>,
message: <some message>
}).save();
await notifyAboutNewRequest(notification);
return true;
}
Now I want you use a userId, that I have stored in the context.req.session.userId as a cookie.

ResolverFilterData contains payload, args, context and info. So you can access that by filter: ({ context }) => { ... }.

I logged my context and It looks like I was getting the values, but undefined. You need to use the onConnect event to upgrade the context.
Links than helped me:
Discussion
Youtube

Related

Can I return value from action creator using redux-thunk?

I've seen a lot of examples of async action creators, but they all do some sort of fetching and pushing data to redux store and return nothing. I need another logic that looks something like:
const createUserAction = (user) => {
firestore().collection('users').add(user)
.then(result => {
dispatch({type: 'SET_USER', payload: {...user, id: result.id}})
})
}
I need to return result.id from createUserAction to navigate to page that displays user by his id. In my imagine it should work like
createUserAction({name: John}).then(id => navigation.navigate('UserDetailPage', {userId: id}))
I don't know how to implement that and I'll be glad if somebody can help
Returning values from action creators is a No-Go. The solution for this scenario that I've used and think is better is to do the redirect in the async action itself:
// afterCreation = callback function with one argument, the created user
const createUserAction = async (user, afterCreation) => {
const createdUser = await firestore().collection('users').add(user);
dispatch({type: 'SET_USER', payload: {...user, id: createdUser.id}});
afterCreation(createdUser);
};
createUserAction(
{name: John},
// Pass callback to action creator
(user) => navigation.navigate('UserDetailPage', {userId: user.id})
);

Vuex: Does dispatch return a promise so that you can chain them?

I am not coding my app yet so I can't test it out but if I wanted to chain dispatches, is that possible to make my dispatches run synchronously?
example:
this.$store.dispatch('doSomething', {
'url': '/admin/do-something',
'user_id': userId,
})
.then(response => {
this.$store.dispatch('doSomething2', {
'url': '/admin/do-something-2',
'user_id': userId,
})
})
Answer
According to the vuex documentation:
dispatch
dispatch(type: string, payload?: any, options?: Object): Promise<any>
dispatch(action: Object, options?: Object): Promise<any>
Meaning, dispatch will always return a Promise so, theoretically, yes you can chain the dispatches to ensure a specific order
Extra
Going further, if these actions always need to happen in this order, consider making a single action that will dispatch each of these individually for you:
someVuexModule.js
...
export const actions = {
async doSomethingMaster({ dispatch }) {
await dispatch('doSomething');
await dispatch('doSomething2');
await dispatch('doSomething3');
},
doSomething() {},
doSomething2() {},
doSomething3() {},
}
...

Vuex action cannot commit mutation

I am working on an authentication function for a website, i am doing this with Firebase. Whenever the user logs into firebase my action in my store gets triggered and commits my mutation so the state gets set with the userID. Somehow whenever i try to commit my mutation i keep getting the error: commit is not defined. I can't seem to find a solution to this problem, all the forums i have been on havent helped so i really hope someone on here can help me with my problem, i would really appreciate it.
My action:
async login({ dispatch }, user) {
const token = await auth.currentUser.getIdToken(true);
const idTokenResult = await auth.currentUser.getIdTokenResult();
let approved = false;
const userData = await firestore.collection('users').doc(user.email).get();
if (userData) {
approved = userData.data().isApproved
}
const userInfo = {
name: user.displayname || null,
email: user.email || null,
avatar: user.photoURL || null,
uid: user.uid,
approved
};
Cookies.set('access_token', token); // saving token in cookie for server rendering
commit('saveUID', userInfo.uid);
}
};
My mutation:
saveUID (state, uid) {
state.uid = uid;
},
The first parameter of the action is the context, which has functions like commit and dispatch. You extract (destructuring assignment) the dispatch by using { dispatch } as your parameter. You can use { dispatch, commit } to fix this and actually assign commit to a local variable.
destructuring assignment
async login({ dispatch, commit }, user) {
commit('your_mutation')
}
using context
async login(context, user) {
context.commit('your_mutation')
}

Type and payload are being dispatched without calling it

I'm currently working on a react-native app with a chat feature. I'm using redux to store my states. So after pressing the send-button to send a message, an action is called to send the message to firebase and show it on the screen afterwards.
My current problem is that while the action I called dispatches the right type/payload, another type/payload is also being dispatched, which is not being dispatched in the called action. Apparently somehow another action is being called containing the type/payload.
The code of the action which is not being called is the following:
const getChatData = (chatIDs, userName, uid) => async dispatch => {
console.log('hasdhkhwerljlkbgkanndhadndngknnjnjsnfjskdnfjsuvhshdifhuishiduhfuishdkfnkjsndf')
const chatData = []
for (const key of chatIDs) {
[...]
// get message
firebase.database().ref('messages/' + key)
.orderByChild('timestamp').limitToLast(1)
.on('child_added', snapshot => {
const { text, timestamp, user } = snapshot.val();
const { name } = user;
chatData.push({ key, members: displayNameArray, text, timestamp, name })
dispatch({
type: GET_CHAT_DATA,
payload: chatData
})
})
})
}
}
As I said, the type GET_CHAT_DATA is being dispatched eventhough this action is not being called. Furthermore, the console.log doesn't show the long test message, which should mean that this action is not being called, right?
What could cause this weird behaviour?
Thank you so much!
So the thing is even though you did not execute the function but in there you registered an event on firebase
.on('child_added', snapshot => { })
Now whenever this child_added event will trigger, the handler will be executed.
That is why your dispatcher is running because its inside the event handler.
firebase.database().ref('messages/' + key)
.orderByChild('timestamp').limitToLast(1)
.on('child_added', snapshot => {
// this is the event handler which is executing
// when the "child_added" event is triggered
const { text, timestamp, user } = snapshot.val();
const { name } = user;
chatData.push({ key, members: displayNameArray, text, timestamp, name })
dispatch({
type: GET_CHAT_DATA,
payload: chatData
})
})
})

Relay subscriptions not working with react-native

I'm using Express Graphql server with react native and Relay. My device does connects to the subscription but it does not subscribe to it. Here's my index.js on the server
const subscriptionServer = SubscriptionServer.create(
{
execute,
subscribe,
schema,
onOperation: (message, params, webSocket) => {
console.log(params)
return params;
},
onConnect: () => {
// My device does connects
console.log("client connected")
}
},
{
server,
path: '/subscriptions'
},
);
app.use('/graphql', graphqlHTTP({
schema,
graphiql: true
}));
app.use('/graphiql', graphiqlExpress({
endpointURL: '/graphql',
subscriptionsEndpoint: `ws://127.0.0.1:8080/subscriptions`
}));
server.listen(PORT, ()=> {
console.log("Groceries running on port " + PORT)
console.log(
`subscriptions is now running on ws://localhost:${PORT}/subscriptions'}`
);
});
The resolver for subscription on the server, it was quite troublesome to figure out since everyone is using executable schema from apolloGraphql.
export default {
type: OrderEdges,
args: {
ShopId: {type: GraphQLID},
},
subscribe: withFilter(() => pubsub.asyncIterator('orderConfirmed'), (payload, variables) => {
console.log(payload)
console.log(variables)
return payload.orderConfirmed.node.ShopId == variables.ShopId;
}),
}
Now the react-native client. My subscription setup with relay environment.
const setupSubscriptions = (config, variables, cacheConfig, observer) => {
const query = config.text; //does console logs the query
const subscriptionClient = new SubscriptionClient(`ws://192.168.0.100:8080/subscriptions`, {reconnect:true});
subscriptionClient.request({query, variables}, (err, result) => {
console.log(err) // doesn't get call inside the request method
observer.onNext(data:result)
})
}
My subscription method,
export default function() {
const variables = {
ShopId: shop.getShop()[0].id
}
requestSubscription(
environment,
{
subscription,
variables,
onCompleted: (res, err) => {
console.log(res)
console.log(err)
},
updater: (store) => {...},
onError: error => console.error(error),
onNext: (response) => {console.log(response)}
});
}
the component where I'm calling to subscribe,
import subscription from '../../GraphQLQueries/subscriptions/orderConfirmed';
class OrdersBox extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
//initializing subscription
orderSubscriptions();
}
When the device starts the app, my device is connected to the web socket as I can see the console.log statement inside the onConnect method in SubscriptionServer. But when the payload is published after a mutation, the subscribe method doesn't get called. I can't seem to figure out what I'm doing wrong. Maybe it's some react-native specific config that I'm missing cuz everything seems to work fine when I test it on graphiql.
I can't find any example of react-native and relay subscriptions used with express graphql.
note: Everything is working when I use subscription with graphiql. But not with react-native and relay.
Thanks in advance guys
....
I wasn't returning the subscriptionClient.request method. Adding a return statement solved the problem. You don't have to return when using subscribe method in subscriptions-transport-ws#0.8.3. But version 0.9.1 replaces the subscribe function with request which does require it to return.
try:
function setupSubscription(config, variables, cacheConfig, observer) {
const query = config.text;
const subscriptionClient = new SubscriptionClient(websocketURL, {
reconnect: true
});
const client = subscriptionClient.request({ query, variables }).subscribe({
next: result => {
observer.onNext({ data: result.data });
},
complete: () => {
observer.onCompleted();
},
error: error => {
observer.onError(error);
}
});
return {
dispose: client.unsubscribe
};
}
subscriptions-transport-ws#0.9.1