I'm already using RTK Query with different endpoints that return JSON which are working as expected. But there is one endpoint that returns XML. I can see in the network tab that HTTP response is correct but RTK Query's auto generated hook returns data as undefined.
Here's is my query definition:
import { myApi } from './base';
export const excel = myApi.injectEndpoints({
endpoints: (builder) => ({
fetchExcelUserList: builder.query({
query: () => ({
url: 'excel/user_list',
method: 'GET',
headers: {
'Content-Type': 'application/xml; charset:utf-8',
},
}),
}),
}),
});
export const { useFetchExcelUserListQuery } = excel;
That's how I use it:
const { data } = useFetchExcelQuery('');
console.log(data);
If this explanation isn't enough, check this link that describes the same problem.
Thanks a lot.
Your data is undefined, because your query goes into an error state - by default, everything will be parsed as json. You can provide a custom parsing function using the responseHandler functionality of fetchaseQuery though.
Related
i have two endpoints when i add new value to endpoint one i want endpoint two updated by useEffect Hook
const PostDetails = (props) => {
const id = props.match.params.id;
const [addNewComment, { isSuccess: success, isError }] = useAddNewCommentMutation();
const dispatch = useDispatch();
const selectPost = useMemo(() => postApi.endpoints.getPost.select(id), [id]);
const { data: post, isLoading } = useSelector(selectPost);
useEffect(() => {
const result = dispatch(postApi.endpoints.getPost.initiate(id));
return result.unsubscribe;
}, [id, dispatch, success]);
it said
name(pin):"ConditionError"
message(pin):"Aborted due to condition callback returning false."
That just means "there is already data and I have no reason to assume it is outdated, I'm not gonna fetch again".
You can do a
dispatch(postApi.endpoints.getPost.initiate(id, {forceRefetch: true}));
but that's not what you should do here.
What you really should use this is the invalidation feature.
So your endpoint getPost has a providesTags function that returns [{ type: 'Post', id: 5 }] and your addNewComment mutation has an invalidatesTags function that returns [{ type: 'Post', id: 5 }], too.
That way, whenever you call that addNewComment mutation, the getPost endpoint will refetch.
Please read the documentation chapter about Automated Refetching
I'm trying to update my mongodb database in javascript by accessing some documents from the database, changing a specific document and then performing a patch request via axios.
When I get to the patch request I'm able to update the database however the promise is stuck on pending and thus, the then() part of the code is not run.
This is the main structure of the code:
In the first part the documents are requested from the database via axios.get:
function updateDocument(someinputdata){
g = axios.all([axios.get('/getData1),axios.get('/getData2)])
.then(response => {
Data1 = response[0].data;
Data2 = response[1].data;
adjustData(Data1,Data2);
});
}
In the second part a specific document is changed and a patch request is called:
function adjustData(Data1,Data2){
...getting specific document and change value from specific field...
var newRec = {
title: "dummyTitle",
rate: newRateValue
};
promise = axios({
url: '/patch/The Real Title',
method: 'PATCH',
data: newRec,
headers: { "Content-Type": "application/json" }
})
.then(() => {
console.log('I want this text to display but it doesn't')
});
}
If I console.log(promise):
Promise {<pending>}
__proto__: Promise
[[PromiseState]]: "pending"
[[PromiseResult]]: undefined
On the server side I have this:
router.patch('/patch/:title', (req,res) => {
const updatedPost = Model.updateOne(
{ "title": req.params.title},
{ $set: { "rate" : req.body.rate}},
(err, result) => {
if(err) {
console.log(err);
throw err;
}
})
.then(
console.log('This text is displayed');
)
})
I want to use the first then() part to update some HTML
Why is the patch request stuck on pending (so not fulfilled or rejected)?
I've figured out what my problem was.
I needed to add
res.json({msg: "Your data has been saved"});
to the code on the server side.
Say I have a list of models:
const documents = [{}, {}, {}];
And I want to insert these into the DB, or update them all, but only if a condition is met:
Model.update({isSubscribed: {$ne: false}}, documents, {upsert:true},(err, result) => {
});
The above signature is surely wrong - what I want to do is insert/update the documents, where the condition is met.
There is this Bulk API:
https://docs.mongodb.com/manual/reference/method/Bulk.find.upsert/
but I can't tell if it will work when inserting multiple documents.
Imagine this scenario: We have a list of employees and a form of some sorts to give them all a penalty, at once, not one by one :)
On the backend side, you would have your eg addBulk function. Something like this:
Penalty controller
module.exports = {
addBulk: (req, res) => {
const body = req.body;
for (const item of body) {
Penalty.create(item).exec((err, response) => {
if (err) {
res.serverError(err);
return;
}
});
res.ok('Penalties added successfully');
}
}
Then you'll probably have an API on your frontend that directs to that route and specific function (endpoint):
penaltyApi
import axios from 'axios';
import {baseApiUrl} from '../config';
const penaltyApi = baseApiUrl + 'penalty'
class PenaltyApi {
static addBulk(penalties) {
return axios({
method: 'post',
url: penaltyApi + '/addBulk',
data: penalties
})
}
}
export default PenaltyApi;
...and now let's make a form and some helper functions. I'll be using React for demonstration, but it's all JS by the end of the day, right :)
// Lets first add penalties to our local state:
addPenalty = (event) => {
event.preventDefault();
let penalty = {
amount: this.state.penaltyForm.amount,
unit: this.state.penaltyForm.unit,
date: new Date(),
description: this.state.penaltyForm.description,
employee: this.state.penaltyForm.employee.value
};
this.setState(prevState => ({
penalties: [...prevState.penalties, penalty]
}));
}
Here we are mapping over our formData and returning the value and passing it to our saveBulkEmployees() function
save = () => {
let penaltiesData = Object.assign([], this.state.penalties);
penaltiesData.map(penal => {
penal.employeeId = penal.employee.id;
delete penal.employee;
return penaltiesData;
});
this.saveBulkEmployees(penaltiesData);
}
...and finally, let's save all of them at once to our database using the Bulk API
saveBulkEmployees = (data) => {
PenaltyApi.addBulk(data).then(response => {
this.success();
console.log(response.config.data)
this.resetFormAndPenaltiesList()
}).catch(error => {
console.log('error while adding multiple penalties', error);
throw(error);
})
}
So, the short answer is YES, you can absolutely do that. The longer answer is above :) I hope this was helpful to you. If any questions, please let me know, I'll try to answer them as soon as I can.
I'm having trouble communicating between the frontend and backend for a selected GET request.
I am using a React frontend with an express/mongoose setup out in the backend.
In the frontend, I do a GET call using axios for:
axios.get('/api/orders/', {
params : {
name: this.props.user.name // user name can be Bob
}
})
And in the backend I'm having a hard time understanding the correct method I would need to do to query the database (example below doesn't work). I found stuff with .select but even then I still can't get it to work:
router.get('/orders', function(req, res) {
Order.find({}).select(req.params).then(function (order) {
res.send(req.params);
})
});
I also tried doing this to see if I can even get the params to send properly and to no demise:
router.get('/orders/:name', function(req, res) {
res.send('client sent :',req.query.name);
});
The orders document model holds objects that house an ordered array and a name (type: String) attached to the object. The Mongoose scheme for the order:
const orderScheme = new Schema({
name : { type : String },
orders : { type : Array}
});
In my MongoDB, I can see all the "Master Orders" send back. Each master order has the name of who submitted it, plus all the orders within (there can be a ton of orders).
What I'm trying to exactly do is pull up all orders that have a certain name. So if I search "TestAccount", I'll get all of bob's orders. I've included an image below:
Any pointers?
Client-side:
axios.get('/api/orders/' + this.props.user.name)
.then(function (response) {
// handle success
console.log(response);
})
.catch(function (error) {
// handle error
console.log(error);
})
You need to handle the Promise when resolved/rejected.
Server-side:
router.get('/orders/:name', function(req, res) {
return Order.find({name: req.params.name}).then(function(orders) {
// return orders when resolved
res.send(orders);
})
.catch(function (error) {
// handle error
console.log(error);
})
});
You did not specify a named route parameter in your route path.
You also aren't accessing the name property by using req.params only.
You should use Model.find() conditions parameter to specify which document[s] you're trying to find. Query.prototype.select() is for filtering document fields.
I can't receive list of items that matches with my array of ids.
This is PART of code in Angular component:
this.orderService.getSpecyficOrders(ids)
.subscribe(orders => { ...
Where ids is an array of
[{_id : ID },{_id : ID },{_id : ID },]
ID is "5235sd23424asd234223sf44" kind of string form MongoDB documents.
In angular service file I have imported:
Http, Headers, and import 'rxjs/add/operator/map';
Here is code in service in Angular:
getSpecyficOrders(ids){
return this.http.get('/api/ordersspecyfic', ids)
.map(res => res.json());
}
In express file I have require: multer, express,router,mongojs, db
And here is part of code in express, call to mongodb:
router.get('/ordersspecyfic', function(req, res, next){
var ids = req.body;
ids = ids.map(function (obj){ return mongojs.ObjectId(obj._id)});
db.orders.find({_id: {$in: ids}}, function(err, orders){
if(err){
res.send(err);
}
res.json(orders);
});
});
And I'm getting error:
Uncaught Response {_body: "TypeError: ids.map is not a function
&n…/node_modules/express/lib/router/index.js:46:12)↵", status:
500, ok: false, statusText: "Internal Server Error", headers:
Headers…}
Console.log in express file
is showing me that req.body is an empty object {}
As far as I know req.body is not an array, but I don't know if this is only problem with that code.
All others request of get single element, get all items etc. are working fine.
I just can't get this one working..
I assume you are trying to send ids to your server side with
return this.http.get('/api/ordersspecyfic', ids)
but http.get api doesn't work like that
get(url: string, options?: RequestOptionsArgs) : Observable
In order to send this data to your back-end you should use the post api
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.post('/api/ordersspecyfic', ids, options)
post(url: string, body: any, options?: RequestOptionsArgs) : Observable
Source:https://angular.io/docs/ts/latest/api/http/index/Http-class.html
Two errors, backend and frontend.
Frontend error
You say this.http.get('/api/ordersspecific', ids);. This does nothing - or specifically, this only tries to get /api/ordersspecific. It doesn't send ids, your second parameter doesn't match any RequestOptions. In other words, your ids are ignored.
You'd want to append this as a query string. Check here how to add querystring parameters. But in short, it'd be something simple like:
return this.http.get('/api/ordersspecyfic?ids=<id1>&ids=<id2>...'
Backend error
You're reading stuff from body. It's a GET request, there should be no body. Read this from querystring:
router.get('/ordersspecyfic', function(req, res, next){
var ids = req.query.ids;
});