article

Monday, April 24, 2023

ReactJS Python Flask Registration with Form Validation | SQLAlchemy | Formik

ReactJS Python Flask Registration with Form Validation | SQLAlchemy | Formik

Python Flask 

https://flask.palletsprojects.com/en/2.2.x/installation/
 
Create an environment
C:\flask_dev>py -3 -m venv venv

Activate the environment
C:\flask_dev>venv\Scripts\activate

Install Flask
venv C:\flask_dev>pip install Flask
C:\flask_dev\flaskreact\app.py

Install requirements

Flask-SQLAlchemy
Flask-SQLAlchemy is an extension for Flask that adds support for SQLAlchemy to your application.
https://flask-sqlalchemy.palletsprojects.com/en/3.0.x/

(venv) PS C:\flask_dev\flaskreact>pip install -U Flask-SQLAlchemy

Flask-Bcrypt
Flask-Bcrypt is a Flask extension that provides bcrypt hashing utilities for your application.
https://pypi.org/project/Flask-Bcrypt/

(venv) PS C:\flask_dev\flaskreact>pip install Flask-Bcrypt

Flask-Cors
A Flask extension for handling Cross Origin Resource Sharing (CORS), making cross-origin AJAX possible.
https://pypi.org/project/Flask-Cors/

(venv) PS C:\flask_dev\flaskreact>pip install -U flask-cors

C:\flask_dev\flaskreact\app.py
#C:\flask_dev\flaskreact\app.py
from flask import Flask, request, jsonify
from flask_bcrypt import Bcrypt #pip install Flask-Bcrypt = https://pypi.org/project/Flask-Bcrypt/
from flask_cors import CORS, cross_origin #ModuleNotFoundError: No module named 'flask_cors' = pip install Flask-Cors
from models import db, User
 
app = Flask(__name__)
 
app.config['SECRET_KEY'] = 'cairocoders-ednalan'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///flaskdb.db'

# Databse configuration mysql                             Username:password@hostname/databasename
#app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///flaskdb.db'

SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_ECHO = True
  
bcrypt = Bcrypt(app) 
CORS(app, supports_credentials=True)

db.init_app(app)
  
with app.app_context():
    db.create_all()
 
@app.route("/")
def hello_world():
    return "Hello, World!"
 
@app.route("/signup", methods=["POST"])
def signup():
    fullname = request.json["fullname"]
    username = request.json["username"]
    email = request.json["email"]
    password = request.json["password"]
 
    user_exists = User.query.filter_by(email=email).first() is not None
 
    if user_exists:
        return jsonify({"error": "Email already exists"}), 409
     
    hashed_password = bcrypt.generate_password_hash(password)
    new_user = User(fullname=fullname, username=username, email=email, password=hashed_password)
    db.session.add(new_user)
    db.session.commit()
 
    return jsonify({
        "id": new_user.id,
        "email": new_user.email
    })
 
if __name__ == "__main__":
    app.run(debug=True)
C:\flask_dev\flaskreact\models.py
#C:\flask_dev\flaskreact\models.py
from flask_sqlalchemy import SQLAlchemy
from uuid import uuid4
 
db = SQLAlchemy()
 
def get_uuid():
    return uuid4().hex
 
class User(db.Model):
    __tablename__ = "users"
    id = db.Column(db.String(11), primary_key=True, unique=True, default=get_uuid)
    fullname = db.Column(db.String(150), unique=True)
    username = db.Column(db.String(150), unique=True)
    email = db.Column(db.String(150), unique=True)
    password = db.Column(db.Text, nullable=False)
Postman
Postman is an API platform for building and using APIs. Postman simplifies each step of the API lifecycle and streamlines collaboration so you can create better APIs—faster.
https://www.postman.com/

run (venv) C:\flask_dev\flaskreact>flask run
http://127.0.0.1:5000/signup

React JS
https://create-react-app.dev/

Create Project
C:\react-js>npx create-react-app myreactdev

Install Formik
npm install formik yup
C:\reactdev\myreactdev>npm install formik yup

https://github.com/axios/axios

Installing the Axios Client
$ npm install axios

C:\reactdev\myreactdev>npm install axios

Run
C:\react-js\myreactdev> npm start
C:\react-js\myreactdev\src\App.js

//C:\react-js\myreactdev\src\App.js
import React from 'react';
import "./App.css";
import { Formik, Field, Form, ErrorMessage } from 'formik';
import * as Yup from 'yup';
import axios from 'axios';
 
class App extends React.Component {
    constructor(props) {
        super(props);
        this.handleSubmit = this.handleSubmit.bind(this);
    }
 
    handleSubmit(data) {
        axios.post('http://127.0.0.1:5000/signup', {
            fullname: data.fullname,
            username: data.username,
            email: data.email,
            password: data.password
        })
        .then(function (response) {
            //handle success
            console.log(response)
            alert('New User Successfully Added.');  
            window.location.href = '/';
        })
        .catch(function (response) {
            //handle error
            console.log(response)
            if (response.status === 400) {
                alert("Invalid credentials");
            }
        });
    }
 
    validationSchema() {
        return Yup.object().shape({
          fullname: Yup.string().required('Fullname is required'),
          username: Yup.string()
            .required('Username is required')
            .min(6, 'Username must be at least 6 characters')
            .max(20, 'Username must not exceed 20 characters'),
          email: Yup.string()
            .required('Email is required')
            .email('Email is invalid'),
          password: Yup.string()
            .required('Password is required')
            .min(6, 'Password must be at least 6 characters')
            .max(40, 'Password must not exceed 40 characters'),
          confirmPassword: Yup.string()
            .required('Confirm Password is required')
            .oneOf([Yup.ref('password'), null], 'Confirm Password does not match'),
          acceptTerms: Yup.bool().oneOf([true], 'Accept Terms is required'),
        });
    }
 
    render() {
        const initialValues = {
            fullname: '',
            username: '',
            email: '',
            password: '',
            confirmPassword: '',
            acceptTerms: false,
        };
 
        return (
            <div className="container" style={{padding: 20}}>
            <div className="register-form"><h1>ReactJS Python Flask Registration with Form Validation | SQLAlchemy | Formik</h1>
              <Formik
                initialValues={initialValues}
                validationSchema={this.validationSchema}
                onSubmit={this.handleSubmit}>
 
                {({ resetForm }) => (
                  <Form>
                    <div className="form-group">
                      <label>Full Name</label>
                      <Field name="fullname" type="text" className="form-control"/>
                      <ErrorMessage name="fullname" component="div" className="text-danger"/>
                    </div>
       
                    <div className="form-group">
                      <label htmlFor="username"> Username </label>
                      <Field name="username" type="text" className="form-control" />
                      <ErrorMessage name="username" component="div" className="text-danger"/>
                    </div>
       
                    <div className="form-group">
                      <label htmlFor="email"> Email </label>
                      <Field name="email" type="email" className="form-control" />
                      <ErrorMessage name="email" component="div" className="text-danger"/>
                    </div>
       
                    <div className="form-group">
                      <label htmlFor="password"> Password </label>
                      <Field name="password" type="password" className="form-control"/>
                      <ErrorMessage name="password" component="div" className="text-danger"/>
                    </div>
       
                    <div className="form-group">
                      <label htmlFor="confirmPassword"> Confirm Password </label>
                      <Field name="confirmPassword" type="password" className="form-control"/>
                      <ErrorMessage name="confirmPassword" component="div" className="text-danger"/>
                    </div>
       
                    <div className="form-group form-check"><br/>
                      <Field name="acceptTerms" type="checkbox" className="form-check-input"/>
                      <label htmlFor="acceptTerms" className="form-check-label">
                        I have read and agree to the Terms
                      </label>
                      <ErrorMessage name="acceptTerms" component="div" className="text-danger"/>
                    </div>
       
                    <div className="form-group">
                      <button type="submit" className="btn btn-primary">
                        Register
                      </button>
                      <button type="button" onClick={resetForm} className="btn btn-warning">
                        Reset
                      </button>
                    </div>
                  </Form>
                )}
              </Formik>
            </div>
            </div>
        );
    }
}      
export default App;
react-js\myreactdev\public\index.html
//react-js\myreactdev\public\index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>React App</title>
    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"/>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>
Run C:\react-j\myreactdev>npm start
http://localhost:3000/

Related Post