I'm working on a personal project that will allow users to find new books based on their preferences for the genre. The database I'm using is MongoDB. However, while I'm able to get all the data on the backend using Postman, I can't get it properly displayed on the frontend. At the moment, I'm just trying to get the data sent to the front end and at least console.log'd but it isn't making it that far.
Here is the code in the routes file.
router.get('/books/:genre', bookBuilder.get_some_books)
Here's the code on the backend that the routes file is pointing to and is working:
exports.get_some_books = async function (req, res) {
let { genre } = req.params;
try {
let books = await Book.find({"genre": genre});
if (books) {
res.json(books)
} else {
res.status(404).send({error: 'Not Found'});
}
} catch (err) {
res.status(500).send({error: err.message});
}
}
Here's my code on the frontend that is not working.
async getEverything() {
try {
let pbBooks = await axios.get(`/books/`, {
method: 'GET',
headers: {'Content-Type': 'application/json'},
params: {
genre: 'PB'
}
})
if (pbBooks) {
console.log(pbBooks)
} else {
this.$router.push('/Error');
}
} catch (err) {
console.log(`Network error: ${err.message}`)
}
}
My code stack is Vue.js, Express.js, Node.js and Axios. On the frontend, I've tried making the inner code of axios.get() into '/books/PB' and then tried getEverything(genre) along with /books/${genre} but neither seems to be working.
The error I am getting is a 404 Request Failed error that is from the catch block in the getEverything() function. I'm not sure why the frontend is unable to get the data when the backend works just fine. Is there anything I'm doing wrong?
404 is the HTTP status code for Not found, which implies there is no route setup on localhost for /books. Actually, /books would route to your app, not the backend (unless you have a proxy setup on your app server that redirects to the backend).
If a proxy were involved, it's likely misconfigured. Otherwise, the target URL in the Axios request should be <backend_url>/books (e.g., http://localhost:9999/books with the back running locally on port 9999, and the app on some other port).
Change
let pbBooks = await axios.get(`/books/`, {
...
to
let genre = "PB"
let pbBooks = await axios.get(`/books/${genre}`, {
method: 'GET',
headers: {'Content-Type': 'application/json'}
})
reason is the params part of the config object is converted to query strings (/books?genre=PB) instead of /books/PB, which is what the backend is expecting
More: https://masteringjs.io/tutorials/axios/get-query-params
Related
I am trying to build an e-commerce site with Next.JS and Strapi. Whenever I try to request data from Strapi to Next.JS, I always get error:-
FetchError: request to http://localhost:1337/api/products?populate=* failed, reason: connect ECONNREFUSED 127.0.0.1:1337
?populate=* in the link is to receive all data and I also tried without it.
This is how I am requesting data:-
export async function getServerSideProps() {
let data = await fetch('http://localhost:1337/api/products?populate=*', {
method: 'GET',
headers: {
'Authorization': 'Bearer api-token',
},
});
let products = await data.json();
return {
props: { products },
};
}
I have read many similar questions but can't find anything. I have checked everything many times but still not working. However, when I make the request with the same API token using thunder client, it gives me a status: 200, and I also receive data in JSON format without any error.
It's been hours and everything looks good but still not working.
First and foremost, when fetching from your nextjs api, you don't call the full url, (i.e., 'localhost'), you just start the call with /api/more/params
export async function getServerSideProps() {
// next api routes use a proxy under the hood,
// so you just need to call `/api/` then the rest of the params :)
let data = await fetch('/api/products?populate=*', {
method: 'GET',
headers: {
'Authorization': 'Bearer api-token',
},
});
let products = await data.json();
return {
props: { products },
};
}
I also think it’s first going to be worth reading (and will likely answer your question) the documentation on getServerSideProps
It can be tempting to reach for an API Route when you want to fetch data from the server, then call that API route from getServerSideProps. This is an unnecessary and inefficient approach, as it will cause an extra request to be made due to both getServerSideProps and API Routes running on the server.
While this may not entirely solve the problem, given then lack of further details, both these recommendations should certainly be a good start and get us goin on solving this!
Changing "localhost" to "127.0.0.1" fixed it for me
reference:
strapi FetchError: request to http://localhost:1337/api/events failed, reason: connect ECONNREFUSED ::1:1337
I have the following Node.JS (ran with Express) code :
let app = express();
app.use(cors());
app.get('/callback', function (req, res) {
// your application requests refresh and access tokens
// after checking the state parameter
var code = req.query.code || null;
var authOptions = {
url: 'https://accounts.spotify.com/api/token',
form: {
code: code,
redirect_uri: redirectUri,
grant_type: 'authorization_code'
},
headers: {
'Authorization': 'Basic ' + (new Buffer(clientId + ':' + clientSecret).toString('base64'))
},
json: true
};
request.post(authOptions, function (error, response, body) {
if (!error && response.statusCode === 200) {
var access_token = body.access_token,
refresh_token = body.refresh_token;
fs.writeFile('test.txt', 'HELLO', function (err) {
if (err) return console.log(err);
console.log('Hello World > helloworld.txt');
});
}
}
)
});
console.log('Listening on 8888');
app.listen(8888);
The route is used as a callback for a request to the Spotify Web API, thus I can get an access token.
Spotify then redirects to the callback function above, you can see it in the URI by looking at "redirect_uri".
If you need more information about the Spotify Authorization Flow, see here.
Here's the URI I'm using to authenticate my app to Spotify.
https://accounts.spotify.com/authorize?client_id=CLIENT_ID&response_type=code&redirect_uri=http://localhost:8888/callback&scope=user-read-private%20user-read-email%20playlist-modify-public&state=PexBrjEzISHepTp7&show_dialog=false
CLIENT_ID is replaced by my real CLIENT_ID in the request I make
My problem is located to the file writing part :
fs.writeFile('test.txt', 'HELLO', function (err) {
if (err) return console.log(err);
console.log('Hello World > helloworld.txt');
});
When the callback route is called by Spotify, I have the string "HELLO" wrote in my text file, so the file writing is functional.
But even if it has finished writing the string, the Chrome page is still running and "pending" on the server. It runs for a few minutes and then crash by saying that the page didn't sent any data. Why ?
I've looked at this page talking about the methods of writing to text files, using writeFile and writeFileAsync, but using both of them didn't solved my problem.
EDIT: I don't really want to stop the Express process! I just want to be able to process another request :)
Any idea ? Thanks in advance :)
You aren't returning anything from your route, try adding res.send({})
In your get route you are not sending response, you must send response irrespective of writing a file was successful or not.
Add below code post writing to file (as well as in if error case)
res.send({YOUR_CHOICE_RESPONSE_DATA})
I am running a React app with an Express server back-end on port:5000. I am making a request to one of my endpoint using the state of the element to get some data and then render it to the page. I initially setup the proxy in the package.json file of the React app as "proxy": "http://localhost:5000" (documentation. Now it was giving me a proxy error saying cannot proxy to localhost:5000. So I used CORS in my express server as a universal middleware for all of the routes using app.use(cors()).That removed the proxy error but the request is still not working (the code is not even reaching the endpoint because nothing is being logged to the console) and I am pretty sure it's because of the same error. Here are the code snippets
router.get("/", async (req, res) => {
var elements = [];
elements = await Element.find();
res.json(elements);
});
const getElements = async () => {
try {
console.log('getElements call')
const data = await axios.get("/api/elements");
console.log(data);
dispatch({ type: GET_ELEMENTS, payload: data });
} catch (e) {
console.error(e);
}
};
const { getElements, elements, loading } = elementContext;
useEffect(() => {
getElements();
}, [])
Expected behaviour: I want the endpoint to send an array name elements to the call which can then be set to the elements state using the reducer and then can be accessed by destructing in the end. I hope I have given adequate information. Any help will be appreciated. Thank you.
I'm sending JWT tokens accross requests for authorization, however I can't seem to get the token decode each time. It works with one method but not the other. The first snippet gives a "decoded" token result from the server side, however the second one doesn't.
public async getAllUsers(req: Request, res: Response) {
try {
const payload = req["decoded"]; // gives the token decoded
if (payload) {
let users: ILoginResult = await UserData.getAllUsers(payload);
res.status(users.status).send(users.result);
}
} catch (e) {
res.status(500).send({ error: e.toString() });
}
}
public async getAccountDetails(req: Request, res: Response) {
try {
const user = req["decoded"]; // always undefined
let details: IDetails = await AccountData.getAccountDetails(name);
res.status(200).send(details);
} catch (e) {
let err = e.toString();
res.status(500).send({ error: err });
}
}
The request from postman are included a bearer token which is provided at login and used throughout other parts of the app. Not sure why it works in the one but not the other. Would really appreciate if someone could better explain what's going on here and/or provide tips, advice, suggestions.
edit - adding request details
get request to: http://localhost:5000/api/v1/account
with a token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWRtaW4iLCJpYXQiOjE1Nzc5OTUwMjUsImV4cCI6MTU3ODE2NzgyNSwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdCJ9.--msLba1VPs4Nv_B9YL6fk2DFHkQCgiVvDJFPt_UnDk
The decoded property was used in a tutorial I was following that seemed to be added from the server side but was poorly explained and I haven't found a good alternative/explanation. I don't think it has any middleware either. Very much open to alt methods.
Thanks to the suggestions from the comments I was able to find a missing piece in the route that creates the decoded property which is being used here. By adding the middleware to the router the request works as expected:
import express from "express";
import UserController from "../controllers/UserController";
import valid from "../utils/ValidateToken";
export default (router: express.Router) => {
router
.route("/users")
.post(UserController.addUser)
.get(valid.validateToken, UserController.getAllUsers);
router.route("/login").post(UserController.loginUser);
router.route("/account").get(valid.validateToken, UserController.getAccountDetails);
};
The valid.validateToken was missing which is the bit that generates the decoded object from the JWT being passed. Moral of the story, always double check everything. Thanks to all who commented/answered!
Hello im trying to set up push notifications for my webapp.
I'm getting my subscription like I should.
It saves it to my database correctly.
It sends my notification like it should if there only is ONE user in the db
and i want to send to more than only one user :)
Im using:
Vue.js (framework)
Axios (post)
node.js (api)
mongoDB (database)
Here's my post to API.
await axios({
method: 'post',
url: 'API',
data: {
subscription: JSON.stringify(subscription),
storeId: storeId
},
headers: {
'Content-Type': 'application/json'
}
})
It registreres my post, but then i get an throw error.
that "Can't set headers after they are sent."
I'm using CORS in my app like this:
const cors = require('cors')
const app = express();
app.use(bodyParser.json());
app.use(cors())
app.use(morgan('combined'))
The way I'm handling the post from my website is by finding my subscriptions and then map through and say foreach subscription
webpush
//subscribe routes
app.post('/pushNotification', (req, res) => {
var storeId = req.body.storeId
res.setHeader('Content-Type', 'application/json');
console.log(storeId)
if (req.body.storeId != null) {
console.log('Test1')
//get pushSubscription object
//create payload
const payload = JSON.stringify({ title: 'push test' })
Push.find({
"storeId": storeId
},
'subscription', function(error, response) {
console.log('Test2')
console.log(response)
response.map(item => {
res.status(201).json({});
console.log('Test3')
var subscription = item.subscription
console.log(subscription)
webpush.sendNotification(subscription, payload).catch(err => console.error(err));
})
})
} else {
res.send("failed")
}
})
As i can read around somewhere is it im not setting headers or something right. I have used cors like in tutorials and stuff.
So it's like it is crashing because it iterates wrong.
but i can't see how.
ERROR MESSAGE:
Thanks in advance
you are getting this error because res.status(201).json({}) has already set the headers and sent back the response to the client but webpush.sendNotification also trying to set the headers.You should use only webpush.sendNotification(subscription, payload).catch(err => console.error(err));
res.json([body]) sets the corresponding header and sends the result:
Sends a JSON response. This method sends a response (with the correct content-type) that is the parameter converted to a JSON string using JSON.stringify().
So, first of all you don't need to set header manually.
second, If the response has more than one item, since you can't send multiple result for a request, you shouldn't use res.json in a map.
Moreover, be aware of webpush.sendNotification that it may send a result too.