React Query always returning isError as False - react-query

We are using Axios along with react query. Can someone point me to correct example, so that all the react query keys like isError, isSuccess is properly set. As, I read through other answers, the catch block below might be the culprit.
function api<TResponse>({
method,
url,
body,
contentType = 'application/json',
}: IAccessInterceptor): Promise<TResponse> {
return new Promise((resolve, reject) => {
const payload: AxiosRequestConfig = {
method,
url,
headers: {
Accept: contentType,
'content-type': contentType,
},
};
// including 'data' if body is not null
if (body != null) {
payload.data = body;
}
axios(payload)
.then((response: { data: { message: TResponse; data: TResponse } }) => {
resolve(response.data?.message || response.data?.data);
})
.catch((error: { response: { data: IServerError } }) => {
reject(error?.response?.data);
});
});
}
// Some problem in above catch block.
const getABC = (
id: string,
): Promise<IABC> => {
const method = 'GET';
const url = `${BASE_URL}.get_abc?assignment_id=${assignmentId}`;
return api<IABC>({ method, url });
};
export const useABC = (
assignmentId: string | null,
): UseQueryResult<IABC> =>
useQuery<IABC, Error>(
queryKeys.getABC(id),
() => someFunction(id|| ''),
{ enabled: !!id},
);
"useABC().isError" is always false

Related

NEXT, upload file along with metadata (Axios and Formidable with Node JS)

I want to upload a file to NEXT apis along with metadata:
const data = new FormData();
data.append('file', file);
data.append('body', JSON.stringify({ hello: 'world' }));
console.log('Sending');
axios
.post('/api/test-route', data, {
headers: {
'content-type': 'multipart/form-data',
'Authorization': 'json-token',
},
})
.then((response: AxiosResponse) =>
console.log('data = ', response.data)
)
.catch((error: unknown) => console.log(error));
Here's my API Code:
// Backend
import formidable from 'formidable';
import { NextApiRequest, NextApiResponse } from 'next';
import {
errorResponse,
genericResponse,
getErrorDetailsFromKey,
} from '#global-backend/utils/api/responseSynthesizer';
import {
ErrorCodes,
IResponse,
} from '#constants/interfaces/gcorn/backend/apis/response.interfaces';
export const config = {
api: {
bodyParser: false,
},
};
// eslint-disable-next-line import/no-anonymous-default-export
export default async (req: NextApiRequest, res: NextApiResponse) => {
const form = new formidable.IncomingForm();
//#ts-ignore
form.uploadDir = './'; //#ts-ignore
form.keepExtensions = true;
const opsDetails = getErrorDetailsFromKey(
ErrorCodes.INVALID_OR_CORRUPTED_FILE
);
let response = errorResponse({ opsDetails });
let status_code = 400;
const payload: { response: IResponse; status_code: number; error: boolean } =
await new Promise((resolve) => {
let flag = 0;
form.parse(req, (err, _, files) => {
const isError = err?.message !== undefined;
if (isError) {
response = errorResponse({
message: err.message,
opsDetails,
});
status_code = 400;
}
console.log('Files = ', Object.keys(files.file));
const fileCheck = checkImageFileValidity(files.file as unknown as File);
if (fileCheck.error) {
opsDetails.details = fileCheck.message;
response = errorResponse({
message: fileCheck.message,
opsDetails,
});
status_code = 400;
}
response = genericResponse({
status_code: 201,
opsDetails: getErrorDetailsFromKey(
ErrorCodes.FUNFUSE_PROFILE_UPDATE_SUCESS
),
});
status_code = 201;
flag = 1;
resolve({ response, status_code, error: false });
});
});
return res.status(payload.status_code).json(payload.response);
};
const checkImageFileValidity = (
file: File
): { error: boolean; message: string } => {
const { type, size } = file;
// Must be less than 5MBs in Size and Must be Image File
if (size > 5000000)
return { error: true, message: 'File Size More than 5MBs' };
if (!type.includes('image'))
return { error: true, message: 'File is not an image' };
return { error: false, message: 'File is valid' };
};
But for some reason, I don't know how can I parse body part of my form which extracts the info: {hello:world}.
Does anyone know a way to parse it and collect in the backend ?
Assuming everything else is correct, you need to check the _ variable

Uncaught (in promise) TypeError: Cannot use 'in' operator to search for 'validateStatus' in

I am getting ** Uncaught (in promise) TypeError: Cannot use 'in' operator to search for 'validateStatus' in 5f8425a33a14f026f80133ed** where 5f8425a33a14f026f80133ed is the id passed to the axios url
I want to display the services based on the user id. My url works perfectly in postman but when i access it from the veux store it gives an error.
services.js (store)
import axios from 'axios';
const state = {
services : {},
status: '',
error: null
};
const getters = {
services : state => { return state.services }
};
const actions = {
async fetchServices({commit}, userId) {
let res = await axios.get('http://localhost:5000/api/services/displayUser' , userId)
commit('setProducts', res.data)
return res;
}
};
const mutations = {
setProducts (state, items) {
state.services= items
},
};
export default {
state,
actions,
mutations,
getters
};
This is how I am calling the action :
computed: {
...mapGetters(["services"]),
},
methods: {
...mapActions(["fetchServices"]),
getData(){
this.fetchServices(this.user._id)
},
},
async created() {
await this.getProfile();
await this.getData();
}
The axios route is defined as
router.get('/displayUser', (req,res) => {
const query = user = req.body ;
Services.find(query)
.exec((err, services) => res.json(services))
})
the error screenshot :
Error screenshot
GET request should not have a body. Either use query params, indicate an id in a path, or use POST request.
In case of query params this may look like this:
let res = await axios.get('http://localhost:5000/api/services/displayUser' , { params: { userId })
router.get('/displayUser', (req,res) => {
const query = user = req.query;
Services.find(query)
.exec((err, services) => res.json(services))
})
This worked for me too:
In front end: Vue Js
let res = axios.get("http://localhost:3000/api/v1/role/getRoleByName",
{ params: { roleName: "name of role you want to send as params" },
});
In back end: Node Js
router.get('/getRoleByName', (req,res)=>{
let roleName = req.query.roleName;
roleModule.getRoleByName(roleName).then(data =>{
response.json(res,data)
}
).catch(err=> {
response.badRequest(res, err);
})
});
it's a silly mistake axios.post req.
async addTodo({ commit }, title) {
try {
const res = await axios.post(BASE_URL, { title, complete: false });
commit("newTodo", res.data);
} catch (err) {
console.log(err.message);
}
},

Ionic formData append showing null in server

I am trying to upload an image using formData. The api is working fine. But the data is displaying null in the server.
My function is
capture_dl_front(){
this.camera.getPicture(this.cameraOptions)
.then(imageData => {
this.customer.dl_front = normalizeURL(imageData);
this.upload_dl_front(imageData);
}, error => {
this.func.showAlert('Error',JSON.stringify(error));
});
}
upload_dl_front(imageFileUri: any): void {
this.file.resolveLocalFilesystemUrl(imageFileUri)
.then(entry => (<FileEntry>entry).file(file => this.readFile_dl_front(file)))
.catch(err => console.log('Error',JSON.stringify(err)));
}
private readFile_dl_front(file: any) {
const reader = new FileReader();
reader.onloadend = () => {
const imgBlob = new Blob([reader.result], { type: file.type });
this.dl_front_imageUri = imgBlob;
this.dl_front_imageName = file.name;
alert(this.dl_front_imageName)
const img = new FormData();
img.append('image', this.dl_front_imageUri, this.dl_front_imageName)
this.api.test(img).then(data=>alert("final: "+data))
};
reader.readAsArrayBuffer(file);
}
and my api function is
test(image){
let headers = new HttpHeaders({
'Content-Type': 'application/x-www-form-urlencoded',
});
return new Promise( resolve => {
this.http.post(url, image, { headers: headers})
.subscribe(
data => {
resolve(data['message']);
},
error => {
resolve(error.statusText);
}
);
});
}
and i am getting the file in my laravel server as
$image = $request->file('image');
but i am getting null in the image parameter.
What am i doing wrong here?
You should remove the headers in the api call.
test(image){
return new Promise( resolve => {
this.http.post(url, image)
.subscribe(
data => {
resolve(data['message']);
},
error => {
resolve(error.statusText);
}
);
});
}

Angular 2 Http Post with Promise failing, not sending data

I am attempting to make a http.post call with angular 2. I have tested the call in postman, so I know that the api is working. I get an error, input empty which means that it isn't getting the data. I've read a few answers and articles, but not able to make a successful call with the data.
Can anyone give me some insight into what I am missing?
public upload(name: string, data: any, result, contentType: string) : Promise<Response> {
let headers = new Headers({ 'Content-Type': contentType });
let options = new RequestOptions({ headers: headers });
return this.http
.post(this.urlAPI, data, options)
.toPromise()
.then(this.extractData)
.catch(this.handleError);
}
extractData(res:Response) {
console.log('res: ', res);
let body = res.json();
return Promise.resolve(res);
}
handleError(err: any): Promise<any> {
console.error('An Error has occured: ', err);
return Promise.reject(err);
}
I am not sure what is the type of your 'data'. Data has to be stringified before sent. Below is a workable version for me.
saveNote(note: ApprovalNoteModel): Observable<ApprovalNoteModel> {
let body = JSON.stringify(note);
let headers = this.utilsSvc.getAuthHeaders();
headers.set('Content-Type', 'application/json');
return this.http.post('cloud/api/approval/note', body,
{ headers: headers }
).map(response => response.json());
}
If it is a file, then you can not do that thru 'http', I believe. Here is my workable version.
addFileRequest(referenceId: number, licenseId: number, url: string, files: File[]): Observable<any> {
return Observable.create(observer => {
this.progressObserver = observer;
let formData: FormData = new FormData(),
xhr: XMLHttpRequest = new XMLHttpRequest();
formData.append('referenceId', referenceId);
formData.append('licenseId', licenseId);
for (let i = 0; i < files.length; i++) {
formData.append("uploads[]", files[i], files[i].name);
}
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
observer.next(xhr.response);
observer.complete();
} else {
if (xhr.response.status)
observer.error(xhr.response);
else
observer.error({ 'status': xhr.status, '_body': xhr.response });
}
}
};
xhr.upload.onprogress = (event) => {
this.progress = Math.round(event.loaded / event.total * 100);
this.progressObserver.next(this.progress);
};
xhr.open('POST', url, true);
xhr.setRequestHeader('Authorization', this.utilsSvc.getToken());
xhr.send(formData);
});
}

How to test node.js-mongodb app using Mocha, Chai and Sinon? I am having difficulty with Sinon part

I am new to testing and having difficulty with Sinon stubs and mocks.
How can I write test for 'quote.list_quote' for following senario.
Here is the routes file : quotes.js
const express = require('express');
const request = require('request');
const async = require('async');
const validator = require('validator');
const quote_router = express.Router();
const confg = require("../../confg/confg");
const quote = require("../models/mquotes");
const quotes_model = quote.quotes;
// host name - needs to be set up using the environment variable
const hostname = confg.hostname;
// route for "quotes/"
quote_router.route("/")
// get route : display the random quote
.get((req, res) => {
// display random quote
async.waterfall([
(callback) => {callback(null, {res});},
quote.count_quotes
], check_quote_exist
);
})
// post route : create a new quote
.post((req, res) => {
const doc_json = {author : validator.escape(req.body.quote_author), quote_text : validator.escape(req.body.quote_text)};
const params = {res, doc_json, quote_action : quote.create_quote};
add_edit_quote(params);
})
// put route : edit the quote
.put((req, res) => {
const doc_json = {author : validator.escape(req.body.quote_author), quote_text : validator.escape(req.body.quote_text)};
const params = {res, doc_json, quote_action : quote.update_quote, qid : req.body.quote_id};
add_edit_quote(params);
})
// delete quote : delete the quote
.delete((req, res) => {
const qid = req.body.qid;
const condition = {_id : qid};
async.waterfall([
(callback) => {callback(null, {res, condition});},
quote.delete_quote
], request_quote_list
);
});
// route for "quotes/list" : display quotes list
quote_router.get("/list/", (req, res) => {
// mention the main operation
let operation;
if(req.body.operation != 'undefined') {
operation = req.body.operation;
} else {
operation = "list_quotes";
}
async.waterfall([
(callback) => {callback(null, {res, operation});},
quote.list_quote
], display_quotes_list
);
});
// display the quotes list
const display_quotes_list = (err, params, quotes_list) => {
if (err) {return console.log(err);}
const res = params.res;
const operation = params.operation;
const header_msg = "List of all the quotes";
let alert_msg;
if(operation == "list_quotes") {
alert_msg = null;
} else if(operation == "delete_quote") {
alert_msg = "Quote has been deleted";
}
const params_out = {
page: "quote_list",
title: 'Quotes Manager',
host: hostname,
header_msg,
alert_msg,
quotes_list
};
res.render('index', params_out);
};
// send http request for quote list page
const request_quote_list = (err, params) => {
if (err) {return console.log(err);}
const res = params.res;
const operation = "delete_quote";
request.get('http://' + hostname + '/quotes/list/', {json:{operation}},
(error, response, body) => {
if (!error && response.statusCode == 200) {
res.send(body);
}
});
};
module.exports = quote_router;
This is not complete file. I have included only a portion of it.
And her is the model file : mquotes.js
const mongoose = require('mongoose');
// Define quote schema
const quoteSchema = new mongoose.Schema({
author: String,
quote_text: {type: String, required: true}
},
{timestamps: true}
);
const quote = {};
// Define quotes model
quote.quotes = mongoose.model('quotes', quoteSchema);
// error handler
error_handler = (callback, err, params, return_value) => {
if(err) { return callback(err);}
else {callback(null, params, return_value);}
};
// add quote - create
quote.create_quote = (params, callback) => {
const res = params.res;
const doc_json = params.doc_json;
quote.quotes.create(doc_json, (err, quotes_detail) => {
error_handler(callback, err, {res, operation : 'create_quote'}, quotes_detail);
});
};
// count the number of quotes
quote.count_quotes = (params, callback) => {
quote.quotes.count({}, (err, quotes_count) => {
error_handler(callback, err, params, quotes_count);
});
};
// delete quote - delete - id
quote.delete_quote = (params, callback) => {
quote.quotes.remove(params.condition, (err, query) => {
error_handler(callback, err, params);
});
};
// list quote - find
quote.list_quote = (params, callback) => {
quote.quotes.find({}, (err, quotes_list) => {
error_handler(callback, err, params, quotes_list);
});
};
// find quote by id
quote.quote_by_id = (params, callback) => {
quote.quotes.findById(params.qid, (err, quotes_detail) => {
error_handler(callback, err, params, quotes_detail);
});
};
// returns the detail of random quote
quote.random_qoute = (params, callback) => {
const random_number = params.random_number;
// select one quote after skipping random_number of times
quote.quotes.findOne({}, (err, quotes_detail) => {
error_handler(callback, err, params, quotes_detail);
}).skip(random_number);
};
// update quote - update - id
quote.update_quote = (params, callback) => {
const options = {new: true};
const qid = params.qid;
const update_json = params.doc_json;
quote.quotes.findByIdAndUpdate(qid, {$set: update_json}, options, (err, quotes_detail) => {
params.operation = 'update_quote';
error_handler(callback, err, params, quotes_detail);
});
};
module.exports = quote;
I have installed mocha globally. Now, I want to test the model. Lets take the quote.list_quote function for example.
const mongoose = require('mongoose');
const chai = require('chai');
const sinon = require('sinon');
const expect = chai.expect; // use the "expect" style of Chai
const mquotes = require('./../../app/models/mquotes');
describe('Tests for quote models', () => {
describe("List quote", () => {
it('list_quote() should return list of quotes', () => {
});
});
});
Can anyone tell me about my coding practice too. I mean the way I use functions and modules.
First of all, you should try to use statics methods. And after that, you should use sinon-mongoose and sinon-as-promised if you want to use Promise in mongoose.
And this is my sample code and test with mocha, chai, and sinon. Hope useful for you.
model.js
var Schema = new mongoose.Schema({
name: String,
created_at: {
type: Date,
default: Date.now
},
updated_at: {
type: Date,
default: Date.now
}
});
Schema.statics.findByName = function(name, cb) {
this.findOne({
name: name
})
.exec()
.then(function getTemplate(template) {
if (!template) {
var error = new Error('Not found template by name: "' + name + '"');
error.status = 404;
return cb(error);
}
return cb(null, template);
})
.catch(function catchErrorWhenFindByTemplateName(error) {
error.status = 500;
return cb(error);
});
}
module.exports = mongoose.model('model', Schema);
test.js
var expect = require('chai').expect,
sinon = require('sinon'),
mongoose = require('mongoose');
require('sinon-as-promised');
require('sinon-mongoose');
var Model = require('../../app/models/model');
describe('Model', function () {
describe('static methods', function () {
describe('#findByName', function () {
var ModelMock;
beforeEach(function () {
ModelMock = sinon.mock(Model);
});
afterEach(function () {
ModelMock.restore();
});
it('should get error status 404 if not found template', function (done) {
var name = 'temp';
ModelMock
.expects('findOne').withArgs({name: name})
.chain('exec')
.resolves(null);
Model.findByName(name, function (error) {
expect(error.status).to.eql(404);
ModelMock.verify();
done();
});
});
it('should get message not found template if name is not existed', function (done) {
var name = 'temp';
ModelMock
.expects('findOne').withArgs({name: name})
.chain('exec')
.resolves(null);
Model.findByName(name, function (error) {
expect(error.message).to.match(/Not found template by name/gi);
ModelMock.verify();
done();
});
});
it('should get template when name is existed', function (done) {
var name = 'temp';
ModelMock
.expects('findOne').withArgs({name: name})
.chain('exec')
.resolves('SUCCESS');
Model.findByName(name, function (error) {
expect(error).to.be.null;
ModelMock.verify();
done();
});
});
it('should get error status 500 when model crashed', function (done) {
var name = 'temp';
ModelMock
.expects('findOne').withArgs({name: name})
.chain('exec')
.rejects(new Error('Oops! Crashed'));
Model.findByName(name, function (error) {
expect(error.status).to.eql(500);
ModelMock.verify();
done();
});
});
});
});
});