The following is the React.js MUI component with two Axios calls within it. The useEffect() GET call works absolutely fine. However, the PUT call in the onSubmit() function is not working.
import {
Stack,
Button,
Typography,
Box,
TextField,
Switch,
} from "@mui/material";
import axios from "axios";
import { useFormik } from "formik";
import * as yup from "yup";
import React, { useEffect, useState } from "react";
import { useNavigate, useParams } from "react-router-dom";
// User Profile Schema Validation
const userProfileValidationSchema = yup.object({
firstName: yup.string().required(),
lastName: yup.string().required(),
gender: yup.string().max(1).required(),
dateOfBirth: yup.date().required(),
phoneNumber: yup
.number()
.required("Required")
.positive()
.integer()
.min(1000000000)
.max(9999999999),
email: yup
.string("Enter email ID")
.required("Email is required")
.email("Enter a valid email"),
bamsCollege: yup.string().required(),
joiningYear: yup.number().required().positive().integer().min(1900).max(2050),
createdAt: yup.date().required(),
isBlocked: yup.bool().required(),
});
// Component Function
export default function UserDetailsForm() {
// TODO: FIXME: THIS IS NOT WORKING!!!!
// Preparing params and configs for axios calls
let navigate = useNavigate();
let { student_id } = useParams();
let url = "http://localhost:3000/admin/users/" + student_id;
let editUrl = url + "/edit";
let getOptions = {
headers: {
username: "someone@example.com",
},
};
let putOptions = {
headers: {
username: "someone@example.com",
},
data: {},
};
// State Management
let [user, setUser] = useState([]);
// Fetch User Details Function for useEffect() Hook
async function fetchUserDetails() {
const response = await axios.get(editUrl, getOptions);
setUser(await response.data);
}
// Fetch details on Load
useEffect(() => {
fetchUserDetails();
}, []);
// Formik Object & SUBMIT Function
const formikUser = useFormik({
initialValues: {
firstName: user.firstName,
lastName: user.lastName,
gender: user.gender,
dateOfBirth: user.dateOfBirth,
phoneNumber: user.phoneNumber,
email: user.email,
bamsCollege: user.bamsCollege,
joiningYear: user.joiningYear,
createdAt: user.createdAt,
isBlocked: user.isBlocked,
},
enableReinitialize: true,
validationSchema: userProfileValidationSchema,
onSubmit: (values) => {
async function updateUserDetails() {
putOptions.data = values;
await axios
.put(editUrl, putOptions)
.then(function () {
navigate(url);
})
.catch(function (error) {
if (error.response.status === 404) {
alert("This Email is not registered on AurumVidya!");
} else {
alert("ERROR: " + error.message);
}
});
}
updateUserDetails();
},
});
return (
<Box
sx={{
"& .MuiTextField-root": { m: 1, width: "25ch" },
}}
>
<Typography variant="h6" sx={{ m: 1 }} gutterBottom>
Edit User Profile
</Typography>
<Typography variant="body2" color="red" sx={{ m: 1 }} gutterBottom>
DO NOT edit user details, unless absolutely necessary!
</Typography>
<form onSubmit={formikUser.handleSubmit}>
<TextField
margin="normal"
id="firstName"
name="firstName"
label="First Name"
value={formikUser.values.firstName}
disabled
InputLabelProps={{ shrink: true }}
/>
<TextField
margin="normal"
id="lastName"
name="lastName"
label="Last Name"
value={formikUser.values.lastName}
disabled
InputLabelProps={{ shrink: true }}
/>
<br />
<TextField
margin="normal"
id="gender"
name="gender"
label="Gender"
value={formikUser.values.gender}
disabled
InputLabelProps={{ shrink: true }}
/>
<TextField
margin="normal"
id="dateOfBirth"
name="dateOfBirth"
label="Date Of Birth"
value={formikUser.values.dateOfBirth}
disabled
InputLabelProps={{ shrink: true }}
/>
<br />
<TextField
required
margin="normal"
id="phoneNumber"
name="phoneNumber"
label="Phone Number"
value={formikUser.values.phoneNumber}
onChange={formikUser.handleChange}
InputLabelProps={{ shrink: true }}
error={
formikUser.touched.phoneNumber &&
Boolean(formikUser.errors.phoneNumber)
}
helperText={
formikUser.touched.phoneNumber && formikUser.errors.phoneNumber
}
/>
<TextField
required
margin="normal"
id="email"
name="email"
label="Email"
value={formikUser.values.email}
onChange={formikUser.handleChange}
InputLabelProps={{ shrink: true }}
error={formikUser.touched.email && Boolean(formikUser.errors.email)}
helperText={formikUser.touched.email && formikUser.errors.email}
/>
<br />
<TextField
margin="normal"
id="bamsCollege"
name="bamsCollege"
label="College"
value={formikUser.values.bamsCollege}
disabled
InputLabelProps={{ shrink: true }}
/>
<TextField
margin="normal"
id="joiningYear"
name="joiningYear"
label="Joining Year"
value={formikUser.values.joiningYear}
disabled
InputLabelProps={{ shrink: true }}
/>
<br />
<TextField
margin="normal"
id="createdAt"
name="createdAt"
label="Member Since"
value={formikUser.values.createdAt}
disabled
InputLabelProps={{ shrink: true }}
/>
<br />
<Typography variant="button" color="error" sx={{ m: 1 }} gutterBottom>
USER IS BLOCKED
</Typography>
<Switch
color="error"
id="isBlocked"
name="isBlocked"
label="Member Status"
checked={formikUser.values.isBlocked}
onChange={formikUser.handleChange}
/>
<br />
<br />
<Stack marginLeft={1} spacing={2} direction="row">
<Button color="secondary" variant="outlined" type="submit">
Update User
</Button>
<Button
color="secondary"
variant="contained"
href={"/users/" + user._id}
>
Cancel
</Button>
</Stack>
</form>
</Box>
);
}
The PUT request seems to the carrying the right header information (verified by a console.log() statement in the browser), however, by the time it reaches the node.js backend application, it completely modifies the headers.
Here's the server code on the node.js backend application.
const express = require('express')
const fileUpload = require('express-fileupload')
const helmet = require('helmet')
const cors = require('cors')
const router = require('./router')
const bodyParser = require('body-parser')
const log = require('../util/logger')
const { unhandledRequests, errorHandler } = require('../util/errors')
// Test Middleware
const test = require('../middleware/test')
// Configuring Express Server
function createServer() {
// Associating All Middlware
const server = express()
server.use(express.json())
server.use(helmet())
server.use(test) // ***Pre CORS request :: For PUT request this is getting executed twice!!! I don't know why.
server.use(
cors({
origin: '*',
allowedHeaders: '*',
methods: '*'
})
)
server.use(bodyParser.urlencoded({ extended: false }))
server.use(fileUpload())
server.use(log.http)
// Directing all API requests to the router
server.use('/', router)
// Unhandled Requests + Central Error Handling
server.use(unhandledRequests)
server.use(errorHandler)
// Return the server
return server
}
module.exports = createServer
I have checked the header details before the CORS as well as after the CORS middleware in the server file. Although both are slightly different (I don't know why), neither are carrying the custom header of username.
Header that is expected. (This is the header from the GET request, and shouldn't be that different from the PUT request header minus the form data payload.)
{
"host": "localhost:3000",
"connection": "keep-alive",
"sec-ch-ua": "\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"101\", \"Google Chrome\";v=\"101\"",
"accept": "application/json, text/plain, */*",
"username": "someone@example.com",
"dnt": "1",
"sec-ch-ua-mobile": "?1",
"user-agent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Mobile Safari/537.36",
"sec-ch-ua-platform": "\"Android\"",
"origin": "http://localhost:5000",
"sec-fetch-site": "same-site",
"sec-fetch-mode": "cors",
"sec-fetch-dest": "empty",
"referer": "http://localhost:5000/",
"accept-encoding": "gzip, deflate, br",
"accept-language": "en-US,en;q=0.9",
"if-none-match": "W/\"179-9vpS3vCBO7UG4qwmDsMBsZ3JOCQ\""
}
Headers that are printed before CORS (for some reason, pre CORS middleware is getting executed twice and it prints two different headers.)
Pre CORS request details: {
"host": "localhost:3000",
"connection": "keep-alive",
"accept": "*/*",
"access-control-request-method": "GET",
"access-control-request-headers": "username",
"origin": "http://localhost:5000",
"user-agent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Mobile Safari/537.36",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-site",
"sec-fetch-dest": "empty",
"referer": "http://localhost:5000/",
"accept-encoding": "gzip, deflate, br",
"accept-language": "en-US,en;q=0.9"
}
Pre CORS request details: {
"host": "localhost:3000",
"connection": "keep-alive",
"sec-ch-ua": "\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"101\", \"Google Chrome\";v=\"101\"",
"accept": "application/json, text/plain, */*",
"username": "someone@example.com",
"dnt": "1",
"sec-ch-ua-mobile": "?1",
"user-agent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Mobile Safari/537.36",
"sec-ch-ua-platform": "\"Android\"",
"origin": "http://localhost:5000",
"sec-fetch-site": "same-site",
"sec-fetch-mode": "cors",
"sec-fetch-dest": "empty",
"referer": "http://localhost:5000/",
"accept-encoding": "gzip, deflate, br",
"accept-language": "en-US,en;q=0.9",
"if-none-match": "W/\"179-9vpS3vCBO7UG4qwmDsMBsZ3JOCQ\""
}
Please note that I am completely new to React, MUI and Axios. Any inputs will be helpful.