Expressjs API variables undefined - node.js

i'm trying to create my first API using nodejs / express js for backend and React for frontend. I'm able to call the API via postman but not via localhost on frontend as the path returns "undefined" and my "mediaType" and "id" are undefined.
The frontend should call the API
BACKEND
const express = require("express");
const app = express();
const PORT = 8080;
const axios = require("axios");
app.use(express.json());
app.get("/test", (req, res) => {
// const { mediaType, id } = req.params;
const { mediaType, id } = req.body;
const options = {
methond: "GET",
url: `https://api.themoviedb.org/3/${mediaType}/${id}?api_key=${APIKEY}&language=en-US`,
// headers: {
// }
};
axios.request(options).then((response) => {
res.send(response.data);
}).catch((error) => {
console.log(error)
})
});
FRONTEND
const fetchData = async () => {
const { data } = await axios.get(
`http://localhost:8080/test`, { params: { mediaType: mediaType, id: id } }
);
setContent(data);
};
PART OF HEADER
_header: 'GET /3/undefined/undefined?api_key=XXX&language=en-US HTTP/1.1\r\n' +
'Accept: application/json, text/plain, */*\r\n' +
'User-Agent: axios/0.27.2\r\n' +
'Host: api.themoviedb.org\r\n' +
'Connection: close\r\n' +
'\r\n',

Alright, for anyone interested...
i updated the FE req
const fetchData = async () => {
const { data } = await axios.get(
`http://localhost:8080/test2?mediaType=${mediaType}&id=${id}`
);
setContent(data);
};
And changed the BE req also, to use query parameters
app.get("/test2", (req, res) => {
// const { mediaType, id } = req.params;
mediaType = req.query.mediaType;
id = req.query.id;
const options = {
methond: "GET",
url: `https://api.themoviedb.org/3/${mediaType}/${id}?api_key=${apiKey}&language=en-US`,
// headers: {
//
}
};
axios
.request(options)
.then((response) => {
res.send(response.data);
})
.catch((error) => {
console.log(error);
});
});
Also needed to update CORS (no idea how it works????) as it blocked my localhost testing
const cors = require("cors");
app.use(
cors({
origin: "http://localhost:3000",
credentials: true, //access-control-allow-credentials:true
optionSuccessStatus: 200,
})
);
Now it seems that everything works!

You accept body parameters in your API endpoint
so with axios you should use data parameter with your body data included and send it to your backend:
const fetchData = async () => {
const { data } = await axios.get(
`http://localhost:8080/test`, { data: { mediaType: mediaType, id: id } } <--- check data key here
);
setContent(data);
};
by the way, it's not a good idea to send body HTTP request with GET http verb

Related

why CSRF token always say invalid CSRF while I send the token through request to the backend?

i import these two packages (csrf, cookieparser) and using inside the appjs for express only its working and also i tested in postman it's working fine here is my code express js:
const csrf = require('csurf')
const cookieParser = require('cookie-parser')
const csrfProtection = csrf({
cookie: {
httpOnly: true,
maxAge: 3600
}
});
app.use(cookieParser())
app.use(csrfProtection);
app.get('/auth/csrf-token', (req, res) => {
res.json({ csrfToken: req.csrfToken() });
});
and also the frontend i using react js and inside the useEffect i fetch the csrf from backend after that i saved in the headers of the axios, but when i send request to the backend, response say invalid csrf :/
useEffect(() => {
const getCsrfToken = async () => {
const { data } = await API.get('/auth/csrf-token');
API.defaults.headers.post['X-CSRF-Token'] = data.csrfToken;
};
getCsrfToken();
}, []);
const handelLogin = (e) => {
e.preventDefault();
API.post('/auth/login', {
headers: {
'Content-Type': 'application/json'
},
data: { email, password },
}).then(({ data }) => {
if (data.token) {
localStorage.setItem('token', data.token);
window.location.href = '/admin'
}
}).catch((e) => {
console.log(e)
})
}
the response from server:
ForbiddenError: invalid csrf token;
As mentioned in https://expressjs.com/en/resources/middleware/csurf.html#using-ajax
Try changing the header property to this,
API.defaults.headers.post['CSRF-Token'] = data.csrfToken;
I solve the problem by adding withcredentials to the axios
all codes after changing
AXIOS.get('get/csrf-token', {
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
withCredentials: true
}).then(({ data }) => {
AXIOS.defaults.headers.common['x-csrf-token'] = data.csrfToken
AXIOS.defaults.withCredentials = true
})

How do I debug server-side errors on MERN?

I have this front-end code:
export const CreatePage = () => {
const auth = useContext(AuthContext)
const {request} = useHttp()
const [content, setContent] = useState('')
const [title, setTitle] = useState('')
const [lead, setLead] = useState('')
useEffect(() => {
window.M.updateTextFields()
},[])
const postHandler = async () => {
try {
const data = await request('/api/post/generate', 'POST', {title: title, lead: lead, content: content}, {
Authorization: `Bearer ${auth.token}`
})
console.log(data)
} catch (e) {}
}
And this back-end code:
router.post('/generate', auth, async (req, res) => {
try {
const baseURL = config.get('baseURL')
const {title, lead, content} = req.body
// if (!title || !lead || !content) {
// return res.status(422).json({error: 'Please, input ALL fields'})
// }
const Post = new Post({
title, lead, content, owner: req.body.user.userId // req.user.userId
})
await Post.save()
res.status(201).json({Post})
} catch (e) {
res.status(500).json({message: 'Something went wrong'})
}})
I've tried a lot of things, but I still get this error. I know this is a server-side error, but that's all I have been able to figure out.
P.S. If there are any questions about the code, I will add it later.
UPD: By the way, could it be a problem's reason? Console log:
[1] Proxy error: Could not proxy request /api/post/generate from localhost:3000 to http://localhost:5000.
Probably, it's because of cors, you just can't send request from different url's. Try to install cors and configure it:
const cors = require("cors");
app.use("/", require('./src/routes'));
app.use(cors({
origin: '*'
}))

Request form URL encoded within a request

I'm trying to make a request form_url_encoded when requesting a request, but it's giving me an error on the console that is already on port 3000, it's giving some error but not finding it, because if I leave the default as in the doc, it runs normal and opens at the door. I get:
Error: connect ECONNREFUSED
const express = require("express");
const router = express.Router();
const axios = require("axios");
const qs = require("qs");
const requestBody = {
refresh_token:
"1000.51355b1f8f5a8176026525670b5bbf3e.93c56a6bd3cb4589bd65b334810848cf",
client_id: "1000.KS2QNMSAQIMS74YBGZROSXD8QD3GWO",
client_secret: "06abfcc05409c430fb15252d47e8d9fe03a3582cbc",
rant_type: "refresh_token",
};
const config = {
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
};
const config2 = {
headers: {
"Content-Type": "application/json",
},
};
axios
.post(
"/crm7/sell_order",
{ test: "test" },
config2
)
.then((res) => {
console.log(res);
return axios.post("https://accounts.blue.com/oauth/v2/token", qs.stringify(requestBody), config);
})
.then((res) => {
console.log(res)
})
.catch((err) => {
console.log(err)
});
module.exports = router;

nuxtjs apollo-client does not set authorization header

I am trying to create a login functionality using nuxtjs with the nuxtjs apollo-module and nodejs in the backend using apollo-server. I would like to pass the token from the frontend (nuxtjs/apollo-client) to the backend (nodejs/apollo-server).
Signin Function (frontend)
async signin () {
const email = this.email
const password = this.password
try {
const res = await this.$apollo.mutate({
mutation: signIn,
variables: {
email,
password
}
}).then(({ data }) => data && data.signIn)
const token = res.token
await this.$apolloHelpers.onLogin(token)
this.$router.push('/feed')
} catch (err) {
// Error message
}
}
nuxtjs.config (frontend)
apollo: {
clientConfigs: {
default: {
httpEndpoint: 'http://localhost:8000/graphql',
wsEndpoint: 'ws://localhost:8000/graphql',
authenticationType: 'Bearer',
httpLinkOptions: {
credentials: 'include'
},
}
}
Cookie in Browser DevTools
Index File (backend)
const app = express()
const corsConfig = {
origin: 'http://127.0.0.1:3000',
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
credentials: true
}
app.use(cors(corsConfig))
app.use(morgan('dev'))
const getMe = async req => {
const token = req.headers.authorization // <========
console.log(token) // returns 'Bearer undefined'
if (token) {
try {
return await jwt.verify(token, process.env.SECRET)
} catch (e) {
// Error message
}
}
}
const server = new ApolloServer({
introspection: true,
playground: true,
typeDefs: schema,
resolvers,
context: async ({ req }) => {
if (req) {
const me = await getMe(req)
return {
models,
me,
secret: process.env.SECRET,
loaders: {
user: new DataLoader(keys =>
loaders.user.batchUsers(keys, models),
),
},
}
}
},
})
server.applyMiddleware({
app,
path: '/graphql',
cors: false
})
const httpServer = http.createServer(app)
server.installSubscriptionHandlers(httpServer)
const port = process.env.PORT || 8000
sequelize.sync({ force: true }).then(async () => {
createUsers(new Date())
httpServer.listen({ port }, () => {
console.log(`Apollo Server on http://localhost:${port}/graphql`)
})
})
The token is saved in a cookie called 'apollo-token'. However the Authoriation header in the format 'Bearer token' is not set. According to the apollo-client documentation this should be set automatically (https://github.com/nuxt-community/apollo-module#authenticationtype-string-optional-default-bearer).
What am I missing? I would be very thankful for any kind of help!

How can I get Axios to send a request with FormData?

I'm unable to get the server that I'm calling to recognize the FormData that I'm providing when I use axios. It keeps telling me that I'm not providing the right FormData even though it works in Postman and Node native http (see below):
import { Router } from "express";
import axios from "axios";
import * as FormData from "form-data";
const router = Router();
const cookieHeader = {
Cookie: "XXX",
};
router.get("/", async (_req, res) => {
try {
const formData = new FormData();
formData.append("key1", JSON.stringify(["value1"]));
formData.append("key2", "value2");
formData.append("key3", "value3");
const response = await axios.post("https://xxx", formData, { headers: { "Content-Type": "multipart/form-data; boundary=--------------------------811161660471543283806813" } });
res.send(response.data);
} catch (error) {
console.log(error);
}
});
module.exports = router;
I am able to get it working in Postman and used that to export using Node's native http, which also works:
import { Router } from "express";
import { https } from "follow-redirects";
const router = Router();
router.get("/", () => {
const options = {
method: "POST",
hostname: "xxx",
path: "/xx/xxx",
headers: {
"Content-Type": "multipart/form-data; boundary=--------------------------811161660471543283806813",
Cookie: "xxx",
},
maxRedirects: 20,
};
const req = https.request(options, (res: any) => {
const chunks: any[] = [];
res.on("data", (chunk: any) => {
chunks.push(chunk);
});
res.on("end", () => {
const body = Buffer.concat(chunks);
console.log(body.toString());
});
res.on("error", (error: any) => {
console.error(error);
});
});
const postData = `------WebKitFormBoundary7MA4YWxkTrZu0gW\nContent-Disposition: form-data; name=\"key1\"\n\n[\"value1\"]\n------WebKitFormBoundary7MA4YWxkTrZu0gW\nContent-Disposition: form-data; name=\"key2\"\n\nvalue2\n------WebKitFormBoundary7MA4YWxkTrZu0gW\nContent-Disposition: form-data; name=\"key3\"\n\nvalue3\n------WebKitFormBoundary7MA4YWxkTrZu0gW--`;
req.setHeader("content-type", "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW");
req.write(postData);
req.end();
});
module.exports = router;
I figured it out after reading through https://github.com/axios/axios/issues/318. It wasn't until near the end that Googrosh posted that he used .getHeaders(). Lo and behold, I added that to my headers too and it worked.
So updating my code, here's what it looks like:
const response = await axios.post("https://xxx", formData, { headers: formData.getHeaders() });
onst formUrlEncoded = x =>
Object.keys(x).reduce((p, c) => p + `&${c}=${encodeURIComponent(x[c])}`, '')
var axios = require("axios");
axios({
url: 'https://login.xyz.com/oauth/v2/token',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
data: formUrlEncoded({
client_id: '***',
client_secret: '***',
grant_type: 'authorization_code',
})
})
.then(function(response) {
console.log(response.data)
})
.catch(function(error) {
console.log(error)
})

Resources