Having issues with remove function on Express - express

I've recently started learning some backend and I'm having some issues with creating a delete function. I'm using Vue with Node, Express, Monk/Mongo.
I have a page where these card components are dynamically posted to. However,every time I run that said delete method to remove one specific instance of that said component in that view, I keep getting this error message:
DELETE http://localhost:1234/tips 500 (Internal Server Error)
And this is what I see in the Network Logs:
message: ""value" must be of type object"
And on my index.js: (sidenote, when I pass '/tips' to app.delete and run tips.remove(req.body) instead of tips.findByIdAndRemove... I end up deleting all instances of that component in that view.
app.delete('/:id', (req, res) => {
console.log(req.body);
tips.remove(req.params.id).then((tip) => {
res.json(tip);
}).catch((error) => {
res.status(500);
res.json(error);
});
});
And this is what I have on my vue component that has the delete method:
const API_URL = 'http://localhost:1234/tips'
methods: {
deleteMyTip(){
fetch(API_URL, {
method: 'DELETE',
body: JSON.stringify(this.tipObject),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
}).then(response => response.json()).then(result => {
console.log(result);
});
}
}

You're trying to pass a tip object as the request body, but DELETE requests aren't supposed to have any body. Your DELETE route is expecting an ID, all you need to do is pass the ID of the tip you want to delete in the URL.
deleteMyTip(){
fetch(`${API_URL}/${this.tipObject.id}`, {
method: 'DELETE',
})
.then(response => {
// Remove item from UI
});
}
It's also common practice to return an empty body with a 204 (no content) status.

Related

Next.js 500 error and Axios error when calling API that uses environment variables

I'm building a wine pairing app in Next.js—where when a user clicks on a type of wine (i.e. chardonnay), it calls an API to return the suggested food pairings. This works with no issue when I use NEXT_PUBLIC for my environment variables, but I don't want to expose my private API key.
This is my first time using server-side environment variables with Next.js I understand that this needs to happen within the pages/api folder. API routing with Next.js is still something that I'm learning, so I've been following the docs, and I also found this tutorial which I followed that resulted in the 500 (Internal Server Error). I'm also getting an Axios error. This is a screenshot of both errors—please let me know if anything should be expanded, and I'll post another screenshot.
I also understand that I can use getStaticProps(), but this call is coming from a component rather than a page, and I understand from the docs that getStaticProps() must be called from a page.
This is what my .env.local looks like:
API_KEY=<my api key>
BASE_URL=https://api.spoonacular.com/
This is what my API call looks like (pages/api/wineWithFood.js)
import axios from 'axios';
export default async function wineWithFood(req, res) {
const {
query: { wine },
} = req;
const url = `${process.env.BASE_URL}food/wine/dishes?wine=${wine}&apiKey=${process.env.API_KEY}`;
const response = await axios.get(url);
res.status(200).json({
data: response.data,
});
}
This is the relevant code for what that call looks like in my component which is properly imported into the page where it belongs:
const getPairing = async () => {
axios.get(`/api/wineWithFood?wine=${wine}`, {
headers: {
Accept: 'application/json',
'Access-Control-Allow-Origin': '*',
},
})
.then((response) => response)
.then((response) => {
setData(response.data.pairings)
})
.catch((err) => console.log(err))
}
const handleChange = (e) => {
e.preventDefault();
setWine(e.target.value);
getPairing();
};
console.log(wine)
I see that the request isn't capturing the wine type, but when I console.log the wine, it's showing up in the browser console as expected. When I console.log the response.data from the API call, I get a status code of 400 with a message stating that the wine must not be empty.
Now, if I change my code to the following—I get the same errors and console.logs as I mentioned... but only on the first try! On the second try (clicking the same exact wine), the wine shows correctly in the browser console since I'm console.loging it, but I get that same 500 error in my console, however, now I can see all of the correct data in my terminal! That leads me to believe I'm doing something wrong on the frontend. Here's the tweaked code that results in this:
const getPairing = async (wine) => {
axios
.get(`/api/wineWithFood?wine=${wine}`, {
headers: {
Accept: 'application/json',
'Access-Control-Allow-Origin': '*',
},
})
.then((response) => response)
.then((response) => {
setData(response.data.pairings);
console.log(response.data.pairings);
})
.catch((err) => console.log(err));
};
const handleChange = (e) => {
e.preventDefault();
setWine(e.target.value);
getPairing(wine);
};
I'm happy to check out any other resources to help me out if that's a better answer to this question.
I finally figured this out and wanted to share the answer—which was staring me in the face.
I left my API call in pages/api/wineWithFood.js the same. I was right. The error was on the frontend. I got rid of the getPairing() function and put everything in the handleChange function. When I console logged my response on the frontend, I realized that the info I needed was res.data.data.pairings. I also changed the axios call by using e.target.value as the search query. I removed wine and setWine since it wasn't necessary. Here's the final code:
const handleChange = (e) => {
e.preventDefault();
axios
.get(`/api/wineWithFood?wine=${e.target.value}`, {
headers: {
Accept: 'application/json',
'Access-Control-Allow-Origin': '*',
},
})
.then((res) => {
setData(res.data.data.pairings);
});
};
I hope this can help someone out—also I'm open to feedback if there's a better way.

Vuejs axios get request always fetch new values [duplicate]

I am trying to query a quote API for a freeCodeCamp project I'm updating to React.js. I am now trying to use Fetch or Axios to query the API but it's caching the response in the browser. I know in $ajax there is a { cache: false } that would force the browser to do a new request.
Is there some way I will be able to do the same with Fetch or Axios?
The cache-control setting seems to be already set to max-age: 0 by Axios.
This is my code I have that is querying the API.
generateQuote = () => {
axios.get('https://quotesondesign.com/wp-json/posts?filter[orderby]=rand&filter[posts_per_page]=1')
.then(response => {
const { title, content, link } = response.data[0];
console.log(title, content, link)
this.setState(() => ({ title, content, link }));
})
.catch(err => {
console.log(`${err} whilst contacting the quote API.`)
})
}
Okay so I found a solution. I had to set a timestamp on the API url to get it to make a new call. There doesn't seem to be a way to force axios or fetch to disable cache.
This is how my code now looks
axios.get(`https://quotesondesign.com/wp-json/posts?filter[orderby]=rand&filter[posts_per_page]=1&timestamp=${new Date().getTime()}`)
.then(response => {
const { title, content, link } = response.data[0];
console.log(title, content, link)
this.setState(() => ({ title, content, link }));
})
.catch(err => {
console.log(`${err} whilst contacting the quote API.`)
})
I added these headers to all axios requests and it's working well.
axiosInstance.defaults.headers = {
'Cache-Control': 'no-cache',
'Pragma': 'no-cache',
'Expires': '0',
};
If you do not want to disable caching for all axios requests, you can disable caching for only one request by using the following parameters in the axios call:
axios.get(
'https://YOUR-URL.com',
{
// query URL without using browser cache
headers: {
'Cache-Control': 'no-cache',
'Pragma': 'no-cache',
'Expires': '0',
},
}
)
It seems, adding timestamp is the only always working way.
If you're using Vue, for example:
const api = axios.create({
baseURL: 'https://example.com/api',
params: {
t: new Date().getTime()
}
})
Vue.prototype.$api = api
So you can use it with:
this.$api.get('items')
And it will always add different timestamp to the url, depending on current request time.
I think you just need to make the url different each time you make the axios call. Timestamp is just one way to do so. Also consider disabling or filtering service workers caching method if you are developing a PWA.
Create an instance of axios and then add timestamp to every request.
const axiosInstance = axios.create({})
axiosInstance.interceptors.request.use(
function (config) {
// Do something before request is sent
config.params = { ...config.params, timestamp: Date.now() };
return config;
},
function (error) {
// Do something with request error
return Promise.reject(error);
}
);

React Native fetching request from API freezes UI

I'm able to fetch messages from the API and render them in the component successfully. However, as the number of messages increases, fetching from the API causes the app to freeze and clicking any event (such as selecting a different tab or button) will be only triggered when the request is done.
I've read about using next-frame to solve this issue but I'm finding difficulties in how to add it to my code. I'd like to know how to implement next-frame inside it.
This is the section of code that fetches messages from the backend:
componentWillMount()
{
/**load user's messages */
loadmessages() {
fetch(server + 'view_user_messages.php', {
method: 'POST',
headers: {
'Accept': 'text/plain',
'Content-Type': 'text/plain',
},
body: JSON.stringify({
user_idDB: modulevariables.globaluserid
})
}).then((response) => response.text())
.then((responseJson) => {
var jsonconvertedrows = JSON.parse(responseJson)
this.setState({ messagestable: jsonconvertedrows })
}).catch((error) => {
console.log(error);
})
}
}

globalize axios as API wrapper in vue project

I have almost 13 Axios requests in my Vue application. which are almost the same
axios({
method: 'post',
url: `${this.$root.api_url}/v2/cameras/${this.selected.exid}/nvr/snapshots/extract`,
data: {
start_date: moment(this.fromDateTime).format(),
end_date: moment(this.toDateTime).format(),
schedule: this.schedule,
interval: this.interval,
create_mp4: this.create_mp4,
inject_to_cr: this.inject_to_cr,
jpegs_to_dropbox: this.jpegs_to_dropbox,
requester: this.$root.user.email,
api_key: this.selected.api_key,
api_id: this.selected.api_id
}
}).then(response => {
if (response.status == 201) {
this.showSuccessMsg({
title: "Success",
message: "Snapshot Extractor has been added (Local)!"
});
this.$events.fire('se-added', {})
this.clearForm()
} else {
this.showErrorMsg({
title: "Error",
message: "Something went wrong!"
})
}
})
I pass the method, URL and data.. and do a few things in response and in case of error.
How can I reduce that so much code? I have this idea to make an API file for this where, the method will accept, API.get(method, URL, data) and I will have {message, statusCode} in return. and then on the basis of that, I can do other stu7ff.
I tried to follow some documentation online but it didn't work. Is there any suitable way to reduce this code.
Is it even possible to give success and error message as well in API.get or post or delete that it would be very minimal when you send the API request?
EDIT: so i guess you need something like a class here:
class API {
static get(url, callback) {
axios({
method: "get",
url: url,
data: data
}).then(response => {
callback(response);
});
}
static post(url, data, callback) {
axios({
method: "post",
url: url,
data: data
}).then(response => {
callback(response);
});
}
}
API.post("url", data, response => {
console.log(response);
});
API.get("url", response => {
console.log(response);
});
I use yamlful
You make a .yml file which includes
events:
- method: get
get: /events/:id
then API calls become
const response = await this.$api.events.get(2)
Furthermore, I inject methods into my context
// api.js
async function populateEvents (app, id) {
const response = await app.$api.events.get(id)
return response
}
export default ({ app, store }, inject) => {
inject('populateEvents', id => populateEvents(app, id))
}
// any_file.vue
this.populateEvents(12)
and in api.js you can generalize your api calls, so if any 2 api calls do the same stuff, you can refactor that repeated code into a separate method

handle network request failed in react native

I'm facing an issue while using react native fetch api. many times request got failure . I have a high speed connection. but many times it got failed.
that issue is happening In android,ios both.
const shoppingApi = 'myserverlink';
async function Sendshoppinapi(data) {
try {
let response = await fetch(shoppingApi, {
method: 'POST',
headers: {
'Accept': 'application/json',
'content-type':'multipart/form-data'
},
body: data
});
let responseJson = await response.json();
return responseJson;
}
catch (error) {
Alert.alert(error.toString())
}
}
export {Sendshoppinapi};
data that I sending server as post request
add_to_wishlist = (item,index) => {
{
let data = new FormData();
data.append('methodName', 'add_to_wishlist');
data.append('user_id', global.userid)
data.append('item_id', this.props.navigation.state.params.itemid.toString())
Sendshoppinapi(data).then((responseJson)=>{
console.warn(responseJson);
if(responseJson.responseCode == '200'){
this.setState({fav:false})
Alert.alert('SHOPPING','Item added to wishlist successfully.',[{text: 'OK',},],{ cancelable: false })
}
else{
this.setState({fav:false})
Alert.alert('SHOPPING','Item already .',[{text: 'OK',},],{ cancelable: false })
}
})}
}
Error that when request got failed
I've quoted an answer I used for another post - however I have added await.
You can check the status of the call, to determine perhaps why the network call failed. Try using fetch's ok to check whether the response was valid, for example:
.then(function(response) {
if (!response.ok) {
//throw error
} else {
//valid response
}
})
Using await:
let response = await fetch(url)
if (response.ok) return await response.json()
You can also access the response's status like:
response.status;
or also, statusText such as:
response.statusText;
checkout the below:
https://developer.mozilla.org/en-US/docs/Web/API/Response/statusText
https://developer.mozilla.org/en-US/docs/Web/API/Response/status
https://www.tjvantoll.com/2015/09/13/fetch-and-errors/
Use then() function with promises. (Requested code snippet)
fetch(shoppingApi, {
method: 'POST',
headers: {
'Accept': 'application/json',
'content-type':'multipart/form-data'
},
body: data
})
.then((resp) => {
return resp.json()
})
.then((resp) => {
//resp contains your json data
});
You also can make your function returns a Promise, and use it with then():
function sendShoppingApi(data) {
return new Promise((resolve, reject) => {
fetch(shoppingApi, {
method: 'POST',
headers: {
'Accept': 'application/json',
'content-type':'multipart/form-data'
},
body: data
})
.then((resp) => {
return resp.json();
})
.then((resp) => {
resolve(resp);
/*
you should also check if data is valid, if something went wrong
you can reject the promise:
if(!dataOK)
reject("error message");
*/
});
});
}
So now you can do something like this:
sendShoppingApi(data)
.then((resp) => {
//do stuff with your data
})
.catch((err) => {
//handle error
});
UPDATE
could be a duplicate of this: React Native fetch() Network Request Failed
For the case when you are running the app on the android device, the API is on a computer and both of them are on the same network I have added some possible things to check. I haven't detailed specific solutions since there are many answers on each topic.
Do a quick check with ngrok https://ngrok.com/ on the free plan to see if that works. If yes:
Make sure the API is accessible by trying to access it on the device browser (most important is to check if you allow the port at inbound rules, firewall).
If you are using HTTPS, you might get an error if your react native env is not properly configured to accept not trusted certificates, assuming you are using a non trusted one. Do a check without HTTPS, only with HTTP, to see if it's the case. https://github.com/facebook/react-native/issues/20488