Search code examples
node.jsreactjsexpressreact-hooksexpress-validator

How do I show server validation errors to client? PostgreSQL, React, Node, Express


I would like to show my client why my server side Express Validator is refusing his inputs. Specifically, I want to show him what's inside this line of code:

return res.status(400).json({errors: errors.array()});

I have struggled through other posts and videos for two days with no solutions. Help please. Here is the rest of my code for the POST loop: Front End:

    const onSubmitForm = async (e) => {    
        e.preventDefault();     
        try {
            const body = { aName, aLastName, aPhone, aEmail, job1, jobDesc1, job2, jobDesc2, job3, jobDesc3, edu, eduYear, certTitle };
            const response = await fetch("http://localhost:5000/path", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify(body)
            });

            getApplicants();

        } catch (err) { 
            console.log('this line fires in catch block of client POST')
            console.error(err.message);
        }   
    };

Back End:

app.post("/path", 
    [
        check('aName')
        .trim().exists({checkFalsy: true}).withMessage('Name must be at least two letters long.').bail()
        .isLength({ min: 2 }).withMessage('Name must be at least two letters long.').bail()
        .isString().withMessage('Name must be letters with apostrophe or dash'),
        check('aEmail')
        .trim().isEmail().withMessage('Must be a valid email')
        .normalizeEmail().toLowerCase()
    ],
    async (req, res, next) => {
        const { aName, aLastName, aPhone, aEmail, job1, jobDesc1, job2, jobDesc2, job3, jobDesc3, edu, eduYear, certTitle } = req.body;
        console.log(req.body.aName);  // prints out exactly what it should
        
        const errors = validationResult(req);
        console.log(errors.array());
        if (!errors.isEmpty()) {
            return res.status(400).json({errors: errors.array()}); //This holds what I want to show!
        } else {

        try {
            const newApplicant = await pool.query(`INSERT INTO table
            ( applicantName, applicantLastName, applicantPhone, applicantEmail, jobTitle1, jobDesc1, jobTitle2, jobDesc2, jobTitle3, jobDesc3, educationTitle, educationYear, certificationTitle) 
            VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) RETURNING *`,
                [aName, aLastName, aPhone, aEmail, job1, jobDesc1, job2, jobDesc2, job3, jobDesc3, edu, eduYear, certTitle]
            );
            
            res.json(newApplicant.rows[0]);  // "means accessing the first element in the array"
            // .rows is used to specify you JUST want rows, not a ton of other things that are in the response object.
        } catch (err) {
            console.error(err.message);
        }
    }
});

I cannot get the information from the response object on to the screen to inform the client. Best I've done is to save the response.json() in a state which prints to the f12 dev console as {errors: Array(2)} but I cannot get this printed out in JSX via any tech I know. I do this with these lines inside the front end post method:

            if (!response.ok) {
                const errorHolder = await response.json();

                console.log(errorHolder); //{errors: Array(2)} 
                setErrors(errorHolder);
                console.log(errors); //does [] on first submit and then {errors: Array(2)}
            } 

//the array of error objects prints to the server console as:
[
  {
    value: 'J',
    msg: 'Name must be at least two letters long.',
    param: 'aName',
    location: 'body'
  },
  {
    value: 'JohnDoe@sit',
    msg: 'Must be a valid email',
    param: 'aEmail',
    location: 'body'
  }
]

I sincerely thank you for your time.


Solution

  • Solution to showing express-validator errors in the DOM, helped greatly by super. First, I set a useState for the error:

        const [errors, setErrors] = useState({errors: []});
    

    Then looked for a !response.ok object for the POST request and set that to the setErrors state.

            const response = await fetch("http://path", {    
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify(body)
            }).then(response => {
                if (!response.ok) {     // if there is !response.ok object...
                    return response.json();
                } 
            }).then(jsonData => {
                console.log("Error response object is:", jsonData);  
                setErrors(jsonData);  
            });
    
    

    finally, to get it to show in the rendered JSX, I set a conditional to execute a map on the response object if it exists

    {errors && errors.errors.map((err, index) => (
        <div key={index}>
            {err.msg}
        </div>
    ))}
    

    Thanks.