Skip to main content

Server-Side Form Validation with Formik, React, and Spring Boot


 

The final output of the form:






The form is built using React, and Formik is used to manage the form state and handle form submissions. React-Toastify is used to display validation messages to the user.


import React, { useState } from 'react';
import { Formik, Form, Field, ErrorMessage } from 'formik';
import axios from 'axios';
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';

const RegisterForm = () => {
const [serverErrors, setServerErrors] = useState({});

const initialValues = {
email: '',
password: '',
confirmPassword: '',
};

const onSubmit = async (values, { setSubmitting }) => {
try {
const response = await axios.post('http://localhost:8080/api/users/register ', values);
console.log('Server response:', response);
setServerErrors({});
toast.success('Registration successful');
} catch (error) {
console.error('Server error:', error.response);
if (error.response.data && error.response.data.length > 0) {
const errors = {};
error.response.data.forEach((errorItem) => {
const fieldName = errorItem.field;
const errorMessage = errorItem.defaultMessage;
errors[fieldName] = errorMessage;
});
setServerErrors(errors);
toast.error('Please fix the errors and try again');
} else {
setServerErrors({ _error: 'Something went wrong. Please try again later.' });
toast.error('Something went wrong. Please try again later.');
}
}
setSubmitting(false);
};
return (
<div className="container">
<div className="row justify-content-center">
<div className="col-md-6">
<Formik initialValues={initialValues} onSubmit={onSubmit}>
{({ isSubmitting }) => (
<Form className="mx-auto mt-5" style={{ maxWidth: '400px' }}>
<div className="form-group">
<label htmlFor="email">Email</label>
<Field type="email" name="email" className="form-control" />
<ErrorMessage name="email" component="div" className="text-danger" />
{serverErrors.email && (
<div className="text-danger">{serverErrors.email}</div>
)}
</div>
<div className="form-group">
<label htmlFor="password">Password</label>
<Field type="password" name="password" className="form-control" />
<ErrorMessage name="password" component="div" className="text-danger" />
{serverErrors.password && (
<div className="text-danger">{serverErrors.password}</div>
)}
</div>
<div className="form-group">
<label htmlFor="confirmPassword">Re-enter Password</label>
<Field type="password" name="confirmPassword" className="form-control" />
<ErrorMessage
name="confirmPassword"
component="div"
className="text-danger"
/>
{serverErrors.confirmPassword && (
<div className="text-danger">{serverErrors.confirmPassword}</div>
)}
</div>
<button type="submit" className="btn btn-primary" disabled={isSubmitting}>
Register
</button>
{serverErrors._error && (
<div className="text-danger">{serverErrors._error}</div>
)}
</Form>
)}
</Formik>
<ToastContainer />
</div>
</div>
</div>
);
};

export default RegisterForm;




The spring boot controller is :

package com.basics.in.java.blogspot.formikServer.controller;

import com.basics.in.java.blogspot.formikServer.dto.UserDto;
import com.basics.in.java.blogspot.formikServer.entity.User;
import com.basics.in.java.blogspot.formikServer.service.UserService;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

@CrossOrigin(origins = "http://localhost:3000")
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;

@PostMapping("/register")
public ResponseEntity<?> registerUser(@Valid @RequestBody UserDto userDto, BindingResult result) {
if (result.hasErrors()) {
return ResponseEntity.badRequest().body(result.getAllErrors());
}

if (!userDto.getPassword().equals(userDto.getConfirmPassword())) {
result.rejectValue("confirmPassword", "Passwords do not match","Passwords do not match");
return ResponseEntity.badRequest().body(result.getAllErrors());
}

User user = new User();
user.setEmail(userDto.getEmail());
user.setPassword(userDto.getPassword());

userService.save(user);

return ResponseEntity.ok("User registered successfully");
}
}



the full code is available here: 



to run this:
clone the repo

install docker desktop 

and run : docker-compose up






Comments

Popular posts from this blog

a simple example for jdbc PreparedStatement

a simple example for PreparedStatement package basics.in.java.blogspot.in; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class Main { private static final String USERNAME="root"; private static final String PASSWORD=""; private static final String CONN_STRING="jdbc:mysql://localhost/basicsinjavablogspot"; public static void main(String[] args) throws ClassNotFoundException, SQLException { Class.forName("com.mysql.jdbc.Driver"); Connection conn=null; Statement stmt=null; ResultSet rs=null; try { conn= DriverManager.getConnection(CONN_STRING, USERNAME, PASSWORD); System.out.println("database connection successful"); //stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY); String sql="select * fr...

Server-Side Pagination with React-Table and Spring Boot JPA with H2 Database

Pagination is a common technique used to split large amounts of data into smaller, more manageable chunks. With server-side pagination, data is retrieved from the server in smaller batches, reducing the amount of data transferred over the network and improving application performance. React-Table provides a wide range of built-in features such as sorting, filtering, pagination, row selection, and column resizing. These features can be easily configured and customized to fit specific requirements. For example, you can customize the sorting behavior to handle multiple sorting criteria, or you can add custom filters to the table to handle complex data filtering scenarios. Additionally, React-Table provides a flexible API that allows developers to extend its functionality with custom hooks, plugins, and components. This means that you can easily add custom functionality to the table, such as exporting data to CSV or integrating with external data sources. In terms of styl...