How to change fetch API link for deployment? - node.js

This is a method to fetch data from an API. I have used the MERN stack. I hosted this application on Heroku. The problem is that I can't understand how to change the link to fetch the API because on Heroku the app is running at a different port every time.
const SendData = async (e) => {
e.preventDefault();
await fetch('http://localhost:4000/Login',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
Email,
Password
})
})
.then(HandleErrs)
.then((res) => {
return res
}).then((res)=>{
const {UserName}=res;
// console.log(UserName);
setCredentials({
UserName,
Email,
Password
})
})
.catch((err) => {
getErr(ERR);
console.log(err)
})
}

Probably this will not give a direct answer to your question, but its a good practice,
What we normally do is create a separate file for api details
for ex:
api.js
//REACT_APP_SERVER_URL is a env variable in .env file
const rootUri = process.env.REACT_APP_SERVER_URL
? process.env.REACT_APP_SERVER_URL
: 'http://localhost:3001';
const apiVersion = 'v1';
const apiBasePath = `${rootUri}/api/${apiVersion}`; //this is the base path
export const userApis = {
all: {
url: `${apiBasePath}/users`,
method: 'GET',
},
update: {
url: `${apiBasePath}/user`,
method: 'POST',
},
};
this is how we use it
const fetchAllUser = () => {
const api = userApis.all;
fetch(api.url, {
method: api.url.method,
body: JSON.stringify(request)
}...

Related

How to hide my API Key in a POST request?

I want to hide my API key when I am making a post request from my browser. I need to input a number plate and send the request to the API and the API responds me with details about it. I have managed to get this working with a GET request to another API by using nodeJS but I can't manage to make it work with a post request. Keep in mind the request needs information from my input field in the browser which is the registration number of the vehicle to send me information back about it.
Here is my function in my browser JS file.
const searchBtn = document.getElementById("search-btn")
function startFetch() {
let plate = document.getElementById("plate").value
let reg = {registrationNumber: `${plate}`}
fetch(`https://driver-vehicle-licensing.api.gov.uk/vehicle-enquiry/v1/vehicles`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': `my key is here`,
},
body: JSON.stringify(reg),
})
.then(response => response.json())
.then(response => {
console.log(response);
})
.catch(err => {
console.log(err);
});
};
searchBtn.addEventListener("click", startFetch);
Any help and method would be appreciated. Thanks in advance.
For anyone in the same boat. I have managed to achieve what I want.
Client side JS file:
function startFetch() {
let plate = document.getElementById("plate").value
let reg = {registrationNumber: plate}
fetch(`http://localhost:3000/v`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(reg),
})
.then(response => response.json())
.then(response => {
console.log(response);
})
.catch(err => {
console.log(err);
});
};
And the backend using Express, NodeJS, body-parser and axios
require("dotenv").config()
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const axios = require('axios');
app.use(bodyParser.json());
app.use(express.static("src"))
//Env vars
const API_URL = process.env.API_URL
const API_KEY = process.env.API_KEY
app.post('/v', (req, res) => {
const body = req.body;
// Make a request to the backend API
axios.post(API_URL, body,
{
headers: {
"Content-Type": "application/json",
'x-api-key': API_KEY
}
}
)
.then((response) => {
// Return the response from the backend API to the client
res.send(response.data);
})
.catch((error) => {
// Handle any errors
res.status(500).send(error);
});
});
app.listen(3000, () => {
console.log('API proxy server is listening on port 3000');
});
You are already sending the body.
A very minor modification to you code:
function startFetch() {
let plate = "abc123";
let reg = { registrationNumber: `${plate}` };
fetch(`https://driver-vehicle-licensing.api.gov.uk/vehicle-enquiry/v1/vehicles`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": `my key is here`,
},
body: JSON.stringify(reg),
}
);
}
startFetch();
You can see your api-key in the header (though you should never send secret via http):
Then in the body (in chrome they call it payload):

Axios POST request to Twillio returns with an Authentication Error?

in Node.js, I am trying to send a POST request with Axios to Twilio and send an SMS message to my phone. But I am getting an 'error: Authentication Error - No credentials provided ? Here is the code:
const body = {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
Body: 'hi from vsc',
To: toNumber,
From: fromNumber,
};
const headers = {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
Authorization: `Basic ${accountSID}:${authToken}`,
};
exports.axios = () => axios.post(`https://api.twilio.com/2010-04-01/Accounts/${accountSID}/Messages.json`, body, headers).then((res) => {
console.log(res, 'res');
}).catch((err) => {
console.log(err);
});
I also tried to use the same parameters with POSTMAN and the POST request is successful. I also tried to encode my authorization username and password to Base 64, but with no success.
I wrote to Twilio customer help but haven`t received any replies yet.
Axios makes an auth option available that takes an object with username and password options. You can use this with the username set to your account SID and password set to your auth token.
The headers object should be sent as the headers parameter of a config object in the third parameter to axios.post. Like so:
const params = new URLSearchParams();
params.append('Body','Hello from vcs');
params.append('To',toNumber);
params.append('From',fromNumber);
const headers = {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
};
exports.axios = () => axios.post(
`https://api.twilio.com/2010-04-01/Accounts/${accountSID}/Messages.json`,
params,
{
headers,
auth: {
username: accountSID,
password: authToken
}
}
}).then((res) => {
console.log(res, 'res');
}).catch((err) => {
console.log(err);
});
Headers is actually a field of config, try something like this:
const config = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
Authorization: `Basic ${accountSID}:${authToken}`,
}
}
axios.post(URL, data, config).then(...)
Or this (general example calling a Twilio endpoint)
const axios = require('axios');
const roomSID = 'RM1...';
const participantSID = 'PA8...';
const ACCOUNT_SID = process.env.ACCOUNT_SID;
const AUTH_TOKEN = process.env.AUTH_TOKEN;
const URL = "https://insights.twilio.com/v1/Video/Rooms/"+roomSID+"/Participants/"+participantSID;
axios({
method: 'get',
url: URL,
auth: {
username: ACCOUNT_SID,
password: AUTH_TOKEN
}
})
.then((response) => {
console.log(response.data);
})
.catch((error) => {
console.log(error);
});
Working code:
const params = new URLSearchParams();
params.append('Body','Hello from vcs');
params.append('To',toNumber);
params.append('From',fromNumber);
exports.axios = () => axios.post(
`https://api.twilio.com/2010-04-01/Accounts/${accountSID}/Messages.json`,
params,
{
auth: {
username: accountSID,
password: authToken,
},
},
).then((res) => {
console.log(res, 'res');
}).catch((err) => {
console.log(err);
});
The previous solutions did not work for me. I encountered either the Can't find variable: btoa error or A 'To' phone number is required..
Using qs worked for me:
import qs from 'qs';
import axios from 'axios';
const TWILIO_ACCOUNT_SID = ""
const TWILIO_AUTH_TOKEN = ""
const FROM = ""
const TO = ""
const sendText = async (message: string) => {
try {
const result = await axios.post(
`https://api.twilio.com/2010-04-01/Accounts/${TWILIO_ACCOUNT_SID}/Messages.json`,
qs.stringify({
Body: message,
To: TO,
From: FROM,
}),
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
auth: {
username: TWILIO_ACCOUNT_SID,
password: TWILIO_AUTH_TOKEN,
},
},
);
console.log({result});
} catch (e) {
console.log({e});
console.log({e: e.response?.data});
}
};

can't receive file with multer (node.js-nuxt3)

I use nuxt3/node.js with multer ,
i can't store or receive file in my server and i can't see req.file in root, its empty all time.
server Code:
const upload = multer({ dest: './uploads/' })
router.post('/sendNewQuestionCSV', upload.single('csv'),adminControler.sendNewQuestionCSV.bind(adminControler))
and my FrontEnd Code with nuxt3:
async function fileSelected(e) {
let formData = new FormData();
formData.append("csv", e.target.files[0]);
const res = await $postFetch("/admin/sendNewQuestionCSV", formData, {
"Content-Type": "multipart/form-data",
});
}
note:$postFetch is an method i made my self use fetch and third argument is "headers". its a nuxt3 Plugin
this Plugin code:
export default defineNuxtPlugin(async () => {
return {
provide: {
postFetch: async (url, body,headers={}) => {
let token = useCookie('token');
return await $fetch(url, {
method: 'post',
body: { token: token.value, ...body },
baseURL: useRuntimeConfig().API_BASE,
...headers
}).catch((error) => error.data)
}
}
}
})
try using .append to add the token:
postFetch: async (url, body,headers={}) => {
let token = useCookie('token');
body.append('token', token.value);
return await $fetch(url, {
method: 'post',
body: body,
baseURL: useRuntimeConfig().API_BASE
}).catch((error) => error.data)
}
EDIT
also try removing headers

React: API url works in GET request but it gets changed in POST request

I am trying to set the api urls for my react app. The GET endpoints work perfectly but when I make a post request the URL becomes the localhost URL without any reason.
I am using a Constants.js file where I check if the node environment is in development or production. This is how they look in production.
const dev = {
url: "http://127.0.0.1:8000/",
};
const prod = {
url: "https://myapp.herokuapp.com/",
};
console.log(process.env.NODE_ENV);
export const config = process.env.NODE_ENV === "development" ? dev : prod;
Currently I have them inverted so that I can make requests to the server on heroku.
const prod = {
url: "http://127.0.0.1:8000/",
};
const dev = {
url: "https://myapp.herokuapp.com/",
};
console.log(process.env.NODE_ENV);
export const config = process.env.NODE_ENV === "development" ? dev : prod;
Here I am importing the config and making a GET request with the variable works perfectly fine.
export const loadUser = () => (dispatch, getState) => {
dispatch({ type: USER_LOADING });
axios
.get(`${config.url}accounts/api/auth/user`, tokenConfig(getState))
.then((res) => {
dispatch({
type: USER_LOADED,
payload: res.data,
});
})
.catch((err) => {
dispatch(returnErrors(err.response.data, err.response.status));
dispatch({
type: AUTH_ERROR,
});
});
};
Here is where it gets weird. When I make the POST request the URL gets changed to the localhost.
export const login = (username, password) => (dispatch) => {
const config = {
headers: {
"Content-Type": "application/json",
},
};
const body = JSON.stringify({
username,
password,
});
axios
.post(`${config.url}accounts/api/auth/login`, body, config)
.then((res) => {
dispatch({
type: LOGIN_SUCCESS,
payload: res.data,
});
})
.catch((err) => {
dispatch(returnErrors(err.response.data, err.response.status));
dispatch({
type: LOGIN_FAILED,
});
});
};
This is the error I get in the console
VM159:1 POST http://localhost:3000/undefinedaccounts/api/auth/login 404 (Not Found)
As you can see the URL gets changed to the localhost and an undefined is passed to the URL which I do not know from where it comes.
If someone has any idea of what is happening here I would really appreciate some help, thanks.
The easiest way to fix this would be by setting baseURL:
Either as a default config:
axios.defaults.baseURL = 'https://api.example.com';
Or, as the baseURL of your axios custom instance:
const instance = axios.create({
baseURL: 'https://api.example.com'
});
Issue in your code:
When you wrote:
axios.post(`${config.url}accounts/api/auth/login`, body, config)...
where config is:
const config = {
headers: {
"Content-Type": "application/json",
},
};
and it has "headers" only, hence "url" is simply undefined. To fix it, you should add "url" property as well in config object.

How to show the success response from node server on react-redux framework

I am making a demo react-redux app for the basic understanding of redux and its server is made on nodeJS. I have made a simple form which gets submitted and the server response is res.send('FORM SAVED'). In front-end, I make the post request but is not able to see the response that returns, be it the success response.
My server controller that responds when form details are saved.
export const postData = (req, res) => {
let p = new PostData();
p.name = req.body.name;
p.emp_id = req.body.emp_id;
p.age = req.body.age;
p.dept = req.body.dept;
p.phone = req.body.phone;
p.gender = req.body.gender;
p.save(((err) => {
if (err){res.send(`Error in uploading: ${err}`);}
else {res.send('Form saved');}
}));
}
This is my action:-
export const createPost = postData => dispatch => {
fetch(`${Config.address}/post`, {
method: 'POST',
headers:{
'Content-Type': 'application/json'
},
body: JSON.stringify(postData)
})
.then((post) => {
console.log('post:', post);
dispatch({
type: NEW_POST,
payload: post
})
})
}
This is how I call this in component after clicking submit:-
onSubmit = (e) => {
e.preventDefault();
let postData = {
name: this.state.name,
emp_id: this.state.emp_id,
dept: this.state.dept,
gender: this.state.gender,
age: this.state.age,
phone: this.state.phone
}
this.props.createPost(postData);
}
I want to get the response string ('Form saved') but I don't know how to read that. Can anyone help? Thanks in advance
fetch returns a raw response object. To get an expected data you should call a .json() method on raw response object which is returned by fetch, like below:
export const createPost = postData => dispatch => {
fetch(`${Config.address}/post`, {
method: 'POST',
headers:{
'Content-Type': 'application/json'
},
body: JSON.stringify(postData)
})
.then(response => response.json()) // add this line
.then((post) => {
console.log('post:', post); // you should get an object with `Form saved` or something similar to it
dispatch({
type: NEW_POST,
payload: postData // replace it to the input parameter
})
})
}
Using async/await it becomes more readable:
export const createPost = (postData) => async (dispatch) => {
// send postData to server
const rawResponse = await fetch(`${Config.address}/post`, {
method: 'POST',
headers:{
'Content-Type': 'application/json'
},
body: JSON.stringify(postData)
});
// we are done with server but we need one more step
// turn a raw response to readable JS object
const message = await rawResponse.json()
// message from server response
console.log('Message ', message);
// store same object as we sent to server in redux store
dispatch({ type: NEW_POST, payload: postData });
}
Hope it helps

Resources