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):
Related
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
})
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)
}...
I want to upload image to the database. However, when I use fetch method with 'Content-Type': 'multipart/form-data' but I cannot get the appended data in the server side. It shows that I have no data in the body.
Below is fetching part of the coding
editProfile = () => {
let bodyData = new FormData();
let photo={
uri:this.state.uri,
type:this.state.type,
fileName:this.state.fileName,
}
bodyData.append('transactionCode', 'UPDATEPROFILE');
// bodyData.append('photo', photo);
console.log(bodyData);
fetch(URL, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'multipart/form-data',
},
body: bodyData,
}).then((response) => response.json())
.then((responseJson) => {
alert(responseJson);
})
.catch((error) => {
alert(error);
});
}
This is the example of how i check the data at the server side
const custfunction = function (req, res) {
console.log(req.body);
}
When i console.log(req), it shows body:{} is empty
Alright, I just find out the problem. I need to use Multer to handle multipart/form-data in the backend. Thanks a lot.
https://www.npmjs.com/package/multer
I created a small server using NodeJS/Express and I'm using node-fetch to interact with SurveyMonkeys API. I currently have two surveys on my account which I can view through their Postman collection. But when I try to use my own endpoints, it doesn't seem to work. The GET request to view all of the surveys returns a status code of "200" but responds with:
{
"size": 0,
"timeout": 0
}
The POST request to create a survey gives me a status code of "400" but returns the same response. Here is my code so far.
const router = require("express").Router();
const fetch = require("node-fetch");
const TOKEN = process.env.SM_ACCESS_TOKEN;
const BASEURL = process.env.SM_BASEURL;
const options = method => ({
headers: {
Authorization: `Bearer ${TOKEN}`,
"Content-Type": "application/json",
method: method
}
});
/*
GET a list of surveys
*/
router.get("/", async (req, res) => {
try {
const surveys = await fetch(`${BASEURL}surveys`, options("GET"));
console.log(surveys);
if (surveys) {
return res.status(200).json(surveys);
}
} catch (err) {
console.log(err);
res.status(500).send({ message: "Server error", err });
}
});
router.post("/create-survey", (req, res) => {
const surveyData = req.body;
fetch(`${BASEURL}surveys`, {
method: "POST",
body: surveyData,
headers: {
Authorization: `bearer ${TOKEN}`,
"Content-Type": "application/json"
}
})
.then(data => {
return res.status(data.status).json(data);
})
.catch(err => console.log(err));
});
module.exports = router;
Additional information:
I am able to complete all of these actions using the POSTMAN collection provided by SurveyMonkey with my Access Token. BASEURL = "https://api.surveymonkey.com/v3/".
ServeyData = { "title": "Some Title" }
Resolved this issue by switching out of node-fetch and instead using axios. Could be the fetch vs xhr request I think.
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