Cannot set property 'clientMutationId' of undefined" Error - graphql

outputFields: {
token: {
type: GraphQLString,
resolve: (token) => token
}
},
outputfields never gets called, not sure whether i am doing in a right way or not, doesn't the resolve function gets called while returning data from mutateAndGetPayload method.
mutateAndGetPayload: (credentials) => {
console.log('credentials', credentials);
userprof.findOne({email: credentials.email}).exec(function(err, r) {
if(!r) {
return new Error('no user')
} else if(r) {
if(r.password != credentials.password) {
return new Error('password error');
} else {
var token = jwt.getToken(r);
console.log(token);
return {token};
}
}
});
}

I think that you need to return something from the mutateAndGetPayload method. That could be a promise. Try to return the userprof.findOne.

Solution
token: {
type: GraphQLString,
resolve: ({token}) => token
}
},
mutateAndGetPayload: (credentials) => {
return UserProf.findOne({ email: credentials.email }).then((r) => {
if (!r) {
return new Error('no user');
} else if (r) {
if (r.password != credentials.password) {
return new Error('password error');
} else {
return { token: jwt.getToken(r) };
}
}
});
}

Related

How to add custom header in NestJS GraphQL Resolver

I want to add custom header in the response of one of my GraphQL resolver Queries in Nestjs. here is the code.
#Query(() => LoginUnion)
async login(
#Args({ type: () => LoginArgs }) { LoginInfo: { email, password } } : LoginArgs
): Promise<typeof LoginUnion> {
try {
let userInfo = await this.userModel.findOne({ email, password: SHA256(password).toString() }, { 'password': false });
if (userInfo === null) {
return new CustomErrorResponse({ message: 'Wrong password or username'});
}
if (!userInfo.isVerified) {
return new CustomErrorResponse({ message: 'User in not verified'});
}
const token = await this.authentication.sign(userInfo, config.get('Secure_JWT_Sign_Key'));
// set header here
console.log('_DEBUG_ =>', token);
} catch(error) {
console.log('user.resolver.login => ', error);
return new CustomErrorResponse({ message: 'Server Exception', additonalInfo: JSON.stringify(error) });
}
}

Call redux action in axios interceptor

I store logged in user data in localstorage. I also validate JWT token in axios interceptor and if it's expired I will refresh it. so I need to update store with new user data and JWT token and in order to do that, I need to call redux action that I have in my Auth module.
AuthRedux.js
export const actionTypes = {
Login: "[Login] Action",
Logout: "[Logout] Action",
UserRequested: "[Request User] Action",
UserLoaded: "[Load User] Auth API",
SetUser: "[Set User] Action",
};
const initialAuthState = {
user: undefined,
authToken: undefined,
};
export const reducer = persistReducer(
{ storage, key: "myapp-auth", whitelist: ["user", "authToken"] },
(state = initialAuthState, action) => {
switch (action.type) {
case actionTypes.Login: {
const { authToken } = action.payload;
return { authToken, user: undefined };
}
case actionTypes.Logout: {
// TODO: Change this code. Actions in reducer aren't allowed.
return initialAuthState;
}
case actionTypes.UserLoaded: {
const { user } = action.payload;
return { ...state, user };
}
case actionTypes.SetUser: {
const { user } = action.payload;
return { ...state, user };
}
default:
return state;
}
}
);
export const actions = {
login: (authToken) => ({ type: actionTypes.Login, payload: { authToken } }),
logout: () => ({ type: actionTypes.Logout }),
requestUser: (user) => ({ type: actionTypes.UserRequested, payload: { user } }),
fulfillUser: (user) => ({ type: actionTypes.UserLoaded, payload: { user } }),
setUser: (user) => ({ type: actionTypes.SetUser, payload: { user } }),
};
export function* saga() {
yield takeLatest(actionTypes.Login, function* loginSaga() {
yield put(actions.requestUser());
});
yield takeLatest(actionTypes.UserRequested, function* userRequested() {
const { data: user } = yield getUserByToken();
yield put(actions.fulfillUser(user));
});
}
AxiosInterceptor.js
export default function setupAxios(axios, store, props) {
axios.interceptors.request.use(
config => {
const {
auth: { authToken }
} = store.getState();
if (authToken) {
config.headers.Authorization = `Bearer ${authToken}`;
}
return config;
},
err => Promise.reject(err)
);
axios.interceptors.response.use(
(response) => {
console.log(props);
return response;
},
function (error) {
const originalRequest = error.config;
if (error.response?.status === 401) {
if (error.response.data === "refresh_token") {
// refresh token and set new user data
// question is how can I call redux setUser action in here and update state
}
else if (error.response.data === "invalid_token") {
window.localStorage.clear();
window.location.href = '/auth/login';
}
else { }
}
if (!originalRequest._retry) {
originalRequest._retry = true;
return axios(originalRequest);
}
return Promise.reject(error);
}
);
}
My question is how can I call reducer setUser action in interceptor and update state
You can dispatch actions from outside of a component when you have access to the store with store.dispatch(anAction), in your case you can do:
store.dispatch(setUser())

Unable to fetch data from API (Resource blocked by client) in Vuex

I'm trying to fetch some data from my API using vuex + axios, but the action give me a "Network Error" (ERR_BLOCKED_BY_CLIENT).
when i was using json-server it works fine, but it doesn't work with my API even with 'Allow-Access-Control-Origin': '*'
actions
const actions = {
async fetchSearch({ commit, state }) {
let res
try {
res = await axios(`http://localhost:8000/api/advertisements/search?column=title&per_page=${state.params.per_page}&search_input=${state.params.query.toLowerCase()}&page=${state.params.page}`, {
method: 'GET',
mode: 'no-cors',
headers: {
'Content-Type': 'application/json'
}
})
} catch(err) {
console.log(err)
}
commit('clearProducts')
commit('setProducts', res.data)
},
setGlobalParams({ commit }, obj) {
commit('clearParams')
commit('setParams', obj)
}
}
component
<script>
/* Vuex import */
import { mapActions } from 'vuex'
export default {
name: 'base-search-component',
data() {
return {
query_obj: {
page: 1,
per_page: 8,
query: ''
}
}
},
methods: {
...mapActions([
'fetchSearch',
'setGlobalParams'
]),
fetchData() {
if (this.query_obj.query === '') {
return
} else {
this.setGlobalParams(this.query_obj)
this.fetchSearch()
this.$router.push({ name: 'search', params: { query_obj: this.query_obj } })
}
}
}
}
</script>
Assuming your cors issue was properly resolved the reason you cannot access the data is that it is being set before the axios promise is being resolved.
Change:
async fetchSearch({ commit, state }) {
let res
try {
res = await axios(`http://localhost:8000/api/advertisements/search?column=title&per_page=${state.params.per_page}&search_input=${state.params.query.toLowerCase()}&page=${state.params.page}`, {
method: 'GET',
mode: 'no-cors',
headers: {
'Content-Type': 'application/json'
}
})
} catch(err) {
console.log(err)
}
commit('clearProducts')
commit('setProducts', res.data)
}
to:
async fetchSearch({ commit, state }) {
await axios(`http://localhost:8000/api/advertisements/search?column=title&per_page=${state.params.per_page}&search_input=${state.params.query.toLowerCase()}&page=${state.params.page}`, {
method: 'GET',
mode: 'no-cors',
headers: {
'Content-Type': 'application/json'
}
}).then(function (response) {
commit('clearProducts')
commit('setProducts', response.data)
}).catch(err) {
console.log(err)
}
}
Further you should use mapState. Assuming setProducts is setting a state object like products this would look like:
<script>
/* Vuex import */
import { mapState, mapActions } from 'vuex'
export default {
name: 'base-search-component',
data() {
return {
query_obj: {
page: 1,
per_page: 8,
query: ''
}
}
},
computed: {
mapState([
'products'
])
},
methods: {
...mapActions([
'fetchSearch',
'setGlobalParams'
]),
fetchData() {
if (this.query_obj.query === '') {
return
} else {
this.setGlobalParams(this.query_obj)
this.fetchSearch()
this.$router.push({ name: 'search', params: { query_obj: this.query_obj } })
}
}
}
}
</script>
Now you can refrence this.products in JS or products in your template.

How to call the function inside other function both defined in same export default?

My code are:-
function showData(data) {
return {
type: 'SHOWDATA',
data,
};
}
export default {
fetchData() {
return function (dispatch) {
getDataApi.getData().then((response)=>dispatch(showData(response)).catch()
};},
updateData{
return function (dispatch) {
getDataApi.getData().then((response)=>if(response.isSucess)
{dispatch(fetchData())}).catch()
};}
}
After update call of the action I want to refresh the list thats why I
called dispatch(fetchData()); but it is showing that fetchData not
defined.How can I call the method defined in same export default function.
Can this help you? Not really exported as default but its named.
export const Actions = {
getAll,
add,
update,
view,
search
}
function getAll(){
return dispatch => {
dispatch(request());
Service.getAll()
.then(
response => {
// todo...
},
error => {
// catch error
}
);
}
function request() { return { type: Constants.LIST_REQUEST } }
function success(data) { return { type: Constants.LIST_SUCCESS, data } }
function failure(error) { return { type: Constants.LIST_FAILURE, error } }
}
function add(data){
return dispatch => {
dispatch(request());
Service.add(data)
.then(
response => {
if(response.status === 'fail'){
// do something
}else{
dispatch(success(response));
dispatch(getAll());
}
},
error => {
// do something
}
);
}
function request() { return { type: Constants.ADD_REQUEST } }
function success(data) { return { type: Constants.ADD_SUCCESS, data } }
function failure(error) { return { type: Constants.ADD_FAILURE, error } }
}

How to implement Custom Async Validator in Angular4

I'm applying Angular 4 in my project and I am having trouble with Custom Validation using HTTP request.
I also tried this: How to implement Custom Async Validator in Angular2.
But it doesn't work in my project.
Here's what I've done so far:
Validation biding:
userName: ['', [Validators.required, Validators.minLength(3), this.validateUserName.bind(this)]]
Value changes event:
let userNameControl = this.individualForm.get('userName');
userNameControl.valueChanges.subscribe(value => {
this.setErrorMessagesForUserNameControl(userNameControl)
}
);
Validation function:
validateUserName(control: FormControl): Promise<any> {
let promise = new Promise<any>(
(resolve, reject) => {
if (this.oldUserNameForCheck != undefined) {
this._individualUpdateService.isUserNameExisting(this.oldUserNameForCheck, control.value).subscribe(
(res) => {
if (res.isUserNameExisting) {
console.log("existing");
resolve({'existing': true});
} else {
console.log("NOT existing");
resolve(null);
}
},
(error) => {
console.log(error);
}
);
} else {
resolve(null);
}
}
);
return promise;
}
Error Messages
I just try to validate the username by sending it to the back-end.
Here's the logs
As you can see, there's a message for "required", "minlength". Those work fine. But the message for Custom validation is not quite clear.
Async validator should be in the next parameter
userName: ['',
[ Validators.required, Validators.minLength(3) ],
[ this.validateUserName.bind(this) ]
]
Also its better to have a factory method with required dependencies that would create validator, instead of using 'bind(this)'
userNameValidator(originalUsername, individualUpdateService) {
return (control: FormControl): Promise<any> => {
return new Promise<any>((resolve, reject) => {
if (originalUsername != undefined) {
individualUpdateService.isUserNameExisting(originalUsername, control.value).subscribe(
(res) => {
if (res.isUserNameExisting) {
console.log("existing");
resolve({ 'existing': true });
} else {
console.log("NOT existing");
resolve(null);
}
},
(error) => {
console.log(error);
}
);
} else {
resolve(null);
}
})
}
}
userName: ['',
[ Validators.required, Validators.minLength(3) ],
[ this.userNameValidator(this.oldUserNameForCheck, this._individualUpdateService) ]
]

Resources