error: 405 Method Not Allowed Using Node.js - javascript

I'm building a Weather Journal application using Node, and I keep getting this error when the POST route code is getting executed. My GET function is executed well and I retrieve the data needed then this error stops the rest of the process(saving data/updating the UI/etc)..
here is the piece of code causing the problem:
async function postData(url="",data={}){
console.log(data);
const res= await fetch (url, { //this method not allowed idk why.
method: 'POST',
headers: {
'content-type':'application/JSON'
},
credentials: 'same-origin',
body: JSON.stringify(data)
});
try{
const finalData= await res.json();
console.log(finalData);
return finalData;
} catch(error) {
console.log("error", error);
}
}
Here is the server-side code after setting up express/cors/body-parser
app.listen(port, () => {
console.log(`Now listening on port ${port}`);
});
app.get('/all', function (req,res) {
res.send(projectData)
});
app.post('/add', function(req,res){
console.log(req.body);
newEntry={
date: req.body.date,
temp: req.body.temp,
content: req.body.content
}
projectData.push(newEntry);
});
I tried to use different pieces of code I found online on the same topic but it all ended up giving me the same error, tried googling as well but didn't really help. I'm also a beginner with node, app building, or working with servers so I'm really not sure if what I stated here is gonna make it clear for y'all to help.

Related

Express app, multiple POST requests from the client side crashing page

I have a to-do list app that updates a string in a mongodb database with every change in state of the to-do list - that string is parsed on reload to render the state. It works great, except when I trigger 5 or 6 state changes quickly in sequence, it hangs the page. As example, if I delete 5 tasks over the course of a couple seconds. I assume the problem is handling all those post requests, but maybe it's on the updating mongodb side? Is there a way to handle a lot of post request like that in a some sort of queue?
Client side:
function sendData(obj) {
fetch('/jsondata', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(obj),
}).catch(function (error) {
console.log(error);
});
console.log('db updated');
}
Here's the mongo side that runs when the POST request is requested from client...if it helps:
app.post('/jsondata', function (req, res) {
updateUserCache(currentUserEmail, JSON.stringify(req.body));
});
async function updateUserCache(email, newState) {
const foundUser = await user.findOne({
email: email,
});
foundUser.cachedState = newState;
const newDate = await Date.now();
foundUser.date = newDate;
await foundUser.save();
console.log('user cache has been updated');
}
It's hanging because you're never sending back a response from your backend code, and at some point the browser will stop making new connections to it.
So make sure you end the requests properly:
app.post('/jsondata', async function (req, res) {
await updateUserCache(currentUserEmail, JSON.stringify(req.body));
res.end();
});

nuxt app deployed to Netlify: fetch to api working locally, but not on deployed site: getting a 404

I have a Nuxt.js app that I'm trying to deploy to Netlify - and everything works on my local machine, but the fetch request to the api returns a 404 when it's deployed to Netlify. I don't know how to make that server route available to my client when it's deployed.
the fetch request in my api-client.js file looks like this:
async fetchInfo(state) {
let response = await fetch(`/api/info/${state}`);
let data = await response.json();
return data;
}
and the api looks like this (in api/index.js file):
const rp = require('request-promise');
const apiKey = process.env.POLICY_API_KEY;
export default function (req, res, next) {
if (req.url.includes("/info")) {
let stateAbbr = req.originalUrl.slice(-2);
rp({
uri: `https://third-party-api-here.com/states/${stateAbbr}/`,
method: 'GET',
headers: {
'token': apiKey,
},
json: true
}).then(function success(response) {
if (response) {
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify(response));
return;
}
}).catch(function error(response) {
console.log('error', response.error);
});
return;
}
next();
}
I think this might have something to do with CORS? I'm getting this error in the browser when I try to hit that route in the deployed app:
GET https://my-app-name.netlify.app/api/info/MN 404
SyntaxError: Unexpected token < in JSON at position 0
As mentioned in the comment above, you need to have a Node.js of some sort.
Hence, hosting on Heroku fixed OP's issue (Netlify is only for static files).

App failing to work after deployment via Heroku

I'm trying to deploy my app to Heroku in which I believe is working. Whilst testing my app via localhost it works fine, everything is posting. However after deployment and replacing all my URLs to Heroku, number of things are not working:
The GIPHY API no longer works
Nothing would post (comments and likes work but not the posting)
I have tried debugging however nothing has worked. Where am I going wrong? Please see below for details
app: https://mitnickproject1-journal-app.netlify.app/
heroku: https://journal-post-pl.herokuapp.com/print
Front-end code
const formEl = document.querySelector('form');
formEl.addEventListener('submit', postFormData)
let count=0;
async function postFormData(e) {
const current= new Date().toLocaleString()
const formData= new FormData(formEl) // console.log this to check what format this is in
const formDataSerialised=Object.fromEntries(formData) //console.log this to see what this does
const jsonObject = {...formDataSerialised, "dateTime": current, "comment": [], "EmojiCount": [0,0,0], "gifLink":gifLink, 'id': count}
console.log(JSON.stringify(jsonObject, null, 2))
try{
const options = { method: 'POST',
body: JSON.stringify(jsonObject),
headers: {
'Content-Type': 'application/json'
}
}
await fetch("https://journal-post-pl.herokuapp.com/test", options);
// const response = await fetch("https://journal-post-pl.herokuapp.com/test", {
// })
// const json = await response.json();
}catch(err){
console.error(err);
alert('There was an error')
}
}
Back End Code
app.post('/test', (req, res) => {
formData.push(req.body)
console.log(formData)
writeToJson();
res.json({success: true})
})
Any help would be appreciated
I checked out your code and tested it out while looking at the console.
Your GIPHY urls are using http instead of https. http is fine for development, but live site needs to use https. Just switch all your http urls to https and that will work.
Your server isn't set up to accept any requests from an outside source (AKA CORS). To fix this, just add app.use(cors()) to your server file.
Don't forget to put const cors = require('cors') at the top.

How do I connect service to a Cloud Foundry app?

I'm new to IBM cloud and I'm trying to build an application where I can write a text, press a button and that text is analysed by the service tone analyser returning a JSON so I can show it.
I have created an instance of said service and I have connected it to my application (a toolchain) using the 'connections' tab on the service.
I also have this code on the app.js file on my app:
const ToneAnalyzerV3 = require('ibm-watson/tone-analyzer/v3');
const { IamAuthenticator } = require('ibm-watson/auth');
const toneAnalyzer = new ToneAnalyzerV3({
version: '2019-10-10',
authenticator: new IamAuthenticator({
apikey: [API key found in service credentials],
}),
url: [API url found in service credentials],
});
app.get('/', function(req, res) {
res.render('index');
});
app.post('/api/tone', async function(req, res, next) {
try {
const { result } = await toneAnalyzer.tone(req.body);
res.json(result);
} catch (error) {
next(error);
}
});
The problem is that when I make the following call on my javascript:
$.post( "/api/tone", {text: textInput}, function(data){
console.log(data);
});
I get the error: 500 (Internal Server Error).
Does anybody know what I am doing wrong?
The issue is that you are sending req.body to be analysed for tone. If you take a look at the API Docs - https://cloud.ibm.com/apidocs/tone-analyzer?code=node#tone - you will see that you only need to send
const toneParams = {
toneInput: { 'text': text },
contentType: 'application/json',
};
I doubt very much that req.body has a toneInput field, and if it does have contentType it may not be set to one of the allowable values.

Send PDF from Server to Client

I'm trying to get access to a pdf from a Google Drive. Whether this access is downloading or viewing, it doesn't really matter, it just needs to be available.
I am using Javascript and NodeJS, with express and google drive api.
I have the following function below which downloads a pdf. But silly me thought this was correct because it worked locally. Then when I deployed it I realised the target filepath no longer makes sense.
function downloadDoc (sourceID, targetName, callback) {
const dest = fs.createWriteStream(`${os.homedir()}/downloads/`+targetName);
drive.files.get(
{sourceID, alt: 'media'},
{responseType: 'stream'},
(err, res) => {
if (err) {
console.error(err);
}
res.data.on('end', () => {
console.log('Done downloading file.');
callback();
})
.on('error', err => {
console.error('Error downloading file.');
throw err;
})
.pipe(dest);
});
}
So what I need to do, is take the data (or response?) from this function and send it over to client side. I assume this is simple to do but, being a simple man, I find myself stuck. I have written this, with the intention that a user can click a link on client side, requesting this URL and calling the function to download the pdf.
app.get('/download_pdf', (req, res) => {
downloadDoc(documentID, 'docName.pdf', ()=>{
console.log("downloaded pdf");
});
res.end();
});
I'm thinking I need to change the argument provided to pipe() since obviously I can't use the filepath.
Similar questions I've checked:
Display Pdf in browser using express js
How to send a pdf file from Node/Express app to the browser
Send pdf via express to js client and download
While these questions are very related to this, I think my issue is due to a lack of understanding of callbacks or requests/responses. I want to learn this properly - not just ask for answers - but as it is, I'm becoming very pressed for time and need a solution soon.
You should be able to simply pipe the returned readable stream to the express res object (which is a writeable stream):
app.get('/download_pdf', (req, res) => {
drive.files.get({
fileId: "your-file-id-here",
alt: 'media'
})
.on('end', function () {
console.log('Done');
})
.on('error', function (err) {
console.log('Error during download', err);
})
.pipe(res);
});
Edit:
as mentioned here, drive.files.get does return a promise. So you need to change it to:
app.get('/download_pdf', (req, res) => {
drive.files.get({
fileId,
alt: 'media'
}, {
responseType: 'stream'
}).then(response => {
response.data
.on('end', function () {
console.log('Done');
})
.on('error', function (err) {
console.log('Error during download', err);
})
.pipe(res);
});
});
So I figured out a way. I'm not sure if this is bad practice but it seems to work. I distinguished between the two response objects by referring to one as response and one as res.
app.get('/download_pdf', (req, res) => {
const docId = req.query.id;
drive.files.get({
fileId: docId,
alt: 'media'
}, {
responseType: 'stream'
}).then(response => {
response.data
.on('end', function () {
console.log('Done');
})
.on('error', function (err) {
console.log('Error during download', err);
})
.pipe(res);
});
});
Posting this in the event that somebody else has a similar issue.

Categories

Resources