Axios PUT call within React MUI Component to Node.js Server does not carry custom-header, while Axios GET call works fine

Viewed 118

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.

0 Answers
Related