I am writing a recipe search engine and i am stuck at sending data between client and server as i didn't work with backend before (i am a beginner in coding).
On the client side i ask user to choose category which he wants the recipe for (e.g chicken). Then the choice is saved in variable and that is being send to the server. That's all working right.
Then on the server i want to pass the category to API Call, make the Call and send the data back to the client, how do i do that ?
Here's some code:
CLIENT-SIDE:
function getRecipes(category){
const categorySearch = category.alt;
let data = {
categoryChoice: categorySearch
}
let options = {
method: 'POST',
headers: {
"Content-type": "application/json; charset=UTF-8"
},
body: JSON.stringify(data)
}
const promise = fetch('/data', options);
promise.then(response => {
if(!response.ok){
console.error(response)
} else {
return response.json();
}
}).then(result => {
console.log(result);
})
}
SERVER-SIDE
app.post('/data', async (request, response) => {
const data = await request.body;
const gotData = data.categoryChoice;
const category = gotData;
console.log(category);
response.json(category);
return category
})
app.get('/data', async (request, response) => {
const cat = await category;
const url = `https://edamam-recipe-search.p.rapidapi.com/search?q=${cat}&from=0&to=100`
const fetch_response = await fetch(url);
const json = await fetch_response.json();
response.json(json);
})
app.get doesn't logs or gives me anything so i don't think it even works
try this:
app.get('/data', async (request, response) => {
const cat = await category;
const url = `https://edamam-recipe-search.p.rapidapi.com/search?q=${cat}&from=0&to=100`
fetch(url).then(res => res.json()).then(res => {
response.json(json);
});
})
I think that you should use only one 'post' method for that(on both frontend and backend). Assuming that your code is correct, it should be something like that:
app.post('/data', async (request, response) => {
const data = request.body;
const category = data.categoryChoice;
console.log(category);
const url = `https://edamam-recipe-search.p.rapidapi.com/search?q=${category}&from=0&to=100`
const fetch_response = await fetch(url);
const json = await fetch_response.json();
response.json(json);
})
Related
I'm totally new to APIs. I'm trying to build a simple API on cyclic.sh that will return the title of a web page given as argument. My API is located at https://shy-ruby-basket-clam-gear.cyclic.app/ and the code is available on GitHub at https://github.com/odebroqueville/starter-micro-api. The API was built from an existing template.
The main code is as follows:
const http = require('http');
// Helper function to get the title of a web page
async function getTitle(url){
try {
const request = new Request(url, {
method: 'GET',
mode: 'cors',
headers: {
'Content-Type': 'text/html'
}
});
const response = await fetch(request);
const html = await response.text();
let title = '';
const titleMatches = html.match(/<title.*?>.*?<\/title>/gmi)||[];
if (titleMatches.length > 0) {
title = titleMatches[0];
console.log(title);
}
if (title.search(/<title/gi) !== -1){
const titleText = title.substring(title.indexOf('>')+1);
const res = titleText.replace('</title>','');
console.log(res);
return res;
}
return '';
} catch (err) {
console.error(`Failed to retrieve title with error: ${err}`);
return '';
}
}
http.createServer(function (req, res) {
const url = req.url.replace('https://shy-ruby-basket-clam-gear.cyclic.app/','');
console.log(`Just got a request at ${req.url}!`)
const title = getTitle(url);
res.write(title);
res.end();
}).listen(process.env.PORT || 3000);
Unfortunately, when I visit 'https://shy-ruby-basket-clam-gear.cyclic.app/https://www.coursera.org/learn/introduction-git-github' it produces an error that I don't understand instead of return the title of the web page https://www.coursera.org/learn/introduction-git-github
Any help I can get to better understand how to make this API work would be greatly appreciated.
First, you should use NodeJs v18 or v19.
Since Fetch API introduced from 18th version.
Also, you should use async/await in your http server's callback function.
So, now your code should now look like this.
const http = require('http');
// Helper function to get the title of a web page
async function getTitle(url){
try {
const request = new Request(url, {
method: 'GET',
mode: 'cors',
headers: {
'Content-Type': 'text/html'
}
});
const response = await fetch(request);
const html = await response.text();
let title = '';
const titleMatches = html.match(/<title.*?>.*?<\/title>/gmi)||[];
if (titleMatches.length > 0) {
title = titleMatches[0];
console.log(title);
}
if (title.search(/<title/gi) !== -1){
const titleText = title.substring(title.indexOf('>')+1);
const res = titleText.replace('</title>','');
console.log(res);
return res;
}
return '';
} catch (err) {
console.error(`Failed to retrieve title with error: ${err}`);
return '';
}
}
http.createServer(async function (req, res) {
const url = req.url.replace('http://shy-ruby-basket-clam-gear.cyclic.app/','').slice(1);
console.log(`Just got a request at ${req.url}!`)
const title = await getTitle(url);
res.write(title);
res.end();
}).listen(process.env.PORT || 3000);
i have a problem.
i have an object in my client side witch have to be my params.
anyone know how to pass an object from client side to server side?
this is my node route, i need to use endPoint from user to do query params
const fetch = require("node-fetch");
async function getDataByEndPoint(req, res, endPoint) {
const url = "https://pixabay.com/api/?key=<KEY-GOES-HERE>";
const options = {
method: "GET",
// headers: {
// "X-RapidAPI-Host": "famous-quotes4.p.rapidapi.com",
// "X-RapidAPI-Key": "your-rapidapi-key",
// },
};
try {
let response = await fetch(url, options);
response = await response.json();
res.status(200).json(response);
console.log(res);
} catch (err) {
console.log(err);
res.status(500).json({ msg: `Internal Server Error.` });
}
}
module.exports = getDataByEndPoint;
this is my client side code
function App() {
const data = useSelector((state) => state.counter.data);
const endPoint = useSelector((state) => state.counter.endPoint);
const dispatch = useDispatch();
// const [data, setData] = useState([]);
const getData = async (endPoint) => {
const requestOptions = {
method: "GET",
};
try {
const res = await fetch(
`http://localhost:8000/dataByParams`,
requestOptions
);
const resJson = await res.json();
console.log(resJson);
dispatch(setData(resJson.hits));
} catch (err) {
console.log(err);
}
};
unfortunately i cant do
?params=
be because i used node fetch so its doesn't work on my localhost....
i tried to use params on https://pixabay.com/api/?key=<KEY-GOES-HERE>
and its worked but when i use it on local host it doesn't because its not the full url, its just the local host
How to do pagination and filtering at the backend in the same controller?
Filter service:-
const filterPosts = async (filterData, token) => {
const config = {
headers: {
Authorization: `Bearer ${token}`,
},
data: {
filterData,
},
};
const response = await axios.get(API_URL, config);
return response.data;
}
Route:-
router.route("/").get(protect, getPosts);
Controller:-
I cant seem to send the filterData from service to this controller, how to achieve it?
const getPosts = asyncHandler(async (req, res) => {
console.log("filter data:- ", req.body); // This Part is undefined.
//pagination
const PAGE_SIZE = 6;
const PAGE = parseInt(req.query.page || "0");
const total = await Post.countDocuments({ user: req.user.id });
const AllPosts = await Post.find({ user: req.user.id })
.limit(PAGE_SIZE)
.skip(PAGE_SIZE * PAGE)
.sort({ createdAt: -1 });
const totalPages = Math.ceil(total / PAGE_SIZE);
res.status(200).json({ totalPages, Allposts });
});
console.log("filter data:- ", req.body); // This Part is undefined.
You can send this data using config.params in Get request or use Post request if you want to use config.data.
Sometimes XHR / Fetch do not allow payload in Get request.
As per this axios doc, sending data as request body is only applicable for request methods PUT, POST, DELETE , and PATCH.
You can also refer to this issue for reference : Link
const filterPosts = async (filterData, token) => {
const config = {
headers: {
Authorization: `Bearer ${token}`,
},
params: {
filterData,
},
};
const response = await axios.get(API_URL, config);
return response.data;
}
I'm trying to figure out how to delete information submitted to the firebase database.
I am trying to delete information under the requests. Example
Here are my actions used to fetch the data:
export default {
async contactArtist(context, payload) {
const newRequest = {
userEmail: payload.email,
message: payload.message
};
const response = await fetch(`https://find-artist-d3495-default-rtdb.firebaseio.com/requests/${payload.artistId}.json`, {
method: 'POST',
body: JSON.stringify(newRequest)
});
const responseData = await response.json();
if (!response.ok) {
const error = new Error(responseData.message || 'Failed to send request.');
throw error;
}
newRequest.id = responseData.name;
newRequest.artistId = payload.artistId;
context.commit('addRequest', newRequest);
},
async fetchRequests(context) {
const artistId = context.rootGetters.userId;
const token = context.rootGetters.token;
const response = await fetch(`https://find-artist-d3495-default-rtdb.firebaseio.com/requests/${artistId}.json?auth=` + token);
const responseData = await response.json();
if (!response.ok) {
const error = new Error(responseData.message || 'Failed to fetch requests.');
throw error;
}
const requests = [];
for (const key in responseData) {
const request = {
id: key,
artistId: artistId,
userEmail: responseData[key].userEmail,
message: responseData[key].message
};
requests.push(request);
}
context.commit('setRequests', requests);
},
};
I'm trying to set up a button that will delete the selected request object.
Your code is sending a POST request, which tells Firebase to generate a unique key. From the documentation on saving data:
POST: Add to a list of data in our Firebase database. Every time we send a POST request, the Firebase client generates a unique key, like fireblog/users/<unique-id>/<data>
The delete a node, send the DELETE verb/method to that path:
const response = await fetch(`https://find-artist-d3495-default-rtdb.firebaseio.com/requests/${payload.artistId}.json`, {
method: 'DELETE'
});
How could I modify the following code to avoid nesting Promises?
The response of request-promise is needed to be inserted in Firestore.
I would also like to know how to have the jsonresponse available when the Firestore Promise is resolved to send the response.status to the caller aplication.
const functions = require('firebase-functions');
const rp = require('request-promise')
var admin = require("firebase-admin");
var serviceAccount = require("./service_key.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://melitest-5bc38.firebaseio.com"
});
let db = admin.firestore()
exports.customHttpRequest = functions.https.onRequest((request, response) => {
const url = 'https://jsonplaceholder.typicode.com/users'
var options = {
uri: url,
method: "GET",
json: true
};
rp(options).then((jsonresponse) => {
for(var i = 0 ; i < jsonresponse.length; i++){
var obj = jsonresponse[i]
var docid = obj.id
// Warning: Avoid nesting promises.eslint(promise/no-nesting)
db.collection("scrapeusertest").doc(String(docid)).set(obj).then(() =>{
console.log(`Data was upload to firestore and the response was: ${jsonresponse}`)
response.status(200).send(jsonresponse);
}).catch(error =>{
console.log(`Error uploading data Firebase: ${error}`)
});
}
return console.log("Data was send")
})
.catch((err) => {
console.log('Error:', err)
});
return null;
});
Easiest option is to use an async function:
const db = admin.firestore()
exports.customHttpRequest = functions.https.onRequest(async (request, response) => {
const url = 'https://jsonplaceholder.typicode.com/users'
const options = {
uri: url,
method: "GET",
json: true
};
const jsonresponse = await rp(options);
await Promise.all(jsonresponse.map(async obj => {
const docid = obj.id
try {
await db.collection("scrapeusertest").doc(String(docid)).set(obj);
} catch (error) {
console.log(`Error uploading data Firebase: ${error}`);
}
}));
console.log(`Data was upload to firestore and the response was: ${jsonresponse}`);
response.status(200).send(jsonresponse);
});
use promise and used the promise all as this shape
const res= await rp(options);
//should be soure the res is array
await Promise.all(res.map( async item =>{
const id=item.id;
try {
await db.collection("scrapeusertest").doc(String(id)).set(item);
} catch (error) {
//what action when handle wrror
}))})
you can use the res as what you need