Home Anatomy Play Full-Stack Deployment Scrum

Full Stack

Element in full-stack include JavaScript, API’s, Python, Flask, and Database. The User database and relations provide all the elements of full-stack.

API’s, Databases and Operations

CRUD is an acronym related to the basic operations done on data within a database

  • Create: POST requests

  • Creates new user with input data

  • Performs error checking

  • Sets up user object -> adds to user database

  • Read: GET requests

  • Handles user retrieval requests

  • Data -> JSON + response

  • Update: PUT/PATCH requests

  • Updates based on user input

  • Commits changes to user database

  • This is done with the PUT request

  • Delete: DELETE requests

  • Handles user delete requests

  • Deletes user from database

Http Requests

Security

  • Validates data through HTTP POST requests

  • Find user id and checks validity of entered password with that stored

  • JSON response with authentication status, ex. Login if valid, and no login in invalid

  • Not necessarily authorization - authentication allows login while authorization allows access to a certain resource

Security

Uses of HTTP requests in our code

  • Create request used for the addition of new users

  • Post-request displays are user data table

  • Put request implemented to update user information

  • Delete request removes specified users

Create User:

Frontend Code

    // uri variable and options object are obtained from config.js
    import { uri, options } from '/portfolio_2025/assets/js/api/config.js';
    const url = uri + '/api/users/authenticate';
    const body = {
            // name: document.getElementById("name").value,
            uid: "toby",
            password: "123toby"
            // dob: document.getElementById("dob").value
        };
    const authOptions = {
            ...options, // This will copy all properties from options
            method: 'POST', // Override the method property
            cache: 'no-cache', // Set the cache property
            body: JSON.stringify(body)
        };
    fetch(url, authOptions)
    function login_user(){
        // Set Authenticate endpoint
        const url = uri + '/api/users/';

        // Set the body of the request to include login data from the DOM
        const body = {
            name: document.getElementById("name").value,
            uid: document.getElementById("uid").value,
            password: document.getElementById("password").value,
            dob: document.getElementById("dob").value
        };

        // Change options according to Authentication requirements
        const authOptions = {
            ...options, // This will copy all properties from options
            method: 'POST', // Override the method property
            cache: 'no-cache', // Set the cache property
            body: JSON.stringify(body)
        };

        // Fetch JWT
        fetch(url, authOptions)
        .then(response => {
            // handle error response from Web API
            if (!response.ok) {
                const errorMsg = 'Login error: ' + response.status;
                console.log(errorMsg);
                return;
            }
            // Success!!!
            // Redirect to the database page
            window.location.href = "/portfolio_2025/data/database";
        })
        // catch fetch errors (ie ACCESS to server blocked)
        .catch(err => {
            console.error(err);
        });
    }

    // Attach login_user to the window object, allowing access to form action
    window.login_user = login_user;
  • The code above is used to create users from a form where the user creates their account
  • Fetch API is used to send POST requests to the desired url address and create a new account
  • This corresponds to the “C” in CRUD

Backend Code

@token_required
        def post(self, current_user): # Create method
            ''' Read data for json body '''
            body = request.get_json()
            
            ''' Avoid garbage in, error checking '''
            # validate name
            name = body.get('name')
            if name is None or len(name) < 2:
                return {'message': f'Name is missing, or is less than 2 characters'}, 400
            # validate uid
            uid = body.get('uid')
            if uid is None or len(uid) < 2:
                return {'message': f'User ID is missing, or is less than 2 characters'}, 400
            # look for password and dob
            password = body.get('password')
            dob = body.get('dob')

            ''' #1: Key code block, setup USER OBJECT '''
            uo = User(name=name, 
                      uid=uid)
            
            ''' Additional garbage error checking '''
            # set password if provided
            if password is not None:
                uo.set_password(password)
            # convert to date type
            if dob is not None:
                try:
                    uo.dob = datetime.strptime(dob, '%Y-%m-%d').date()
                except:
                    return {'message': f'Date of birth format error {dob}, must be mm-dd-yyyy'}, 400

# This is code from the user.py in the model
def create(self):
    try:
        # creates a person object from User(db.Model) class, passes initializers
        db.session.add(self)  # add prepares to persist person object to Users table
        db.session.commit()  # SqlAlchemy "unit of work pattern" requires a manual commit
        return self
    except IntegrityError:
        db.session.remove()
        return None
  • After the data is send to the backend, it checks if it meets the requirements, or else it returns an error message
  • The code tries to add a user to the database and if there is not an integrity error saves it by committing the change.

Authenticate

Frontend Code:

    // uri variable and options object are obtained from config.js
    import { uri, options } from '/portfolio_2025/assets/js/api/config.js';

    function login_user(){
        // Set Authenticate endpoint
        const url = uri + '/api/users/authenticate';

        // Set the body of the request to include login data from the DOM
        const body = {
            name: document.getElementById("name").value,
            uid: document.getElementById("uid").value,
            password: document.getElementById("password").value,
            dob: document.getElementById("dob").value
        };

        // Change options according to Authentication requirements
        const authOptions = {
            ...options, // This will copy all properties from options
            method: 'POST', // Override the method property
            cache: 'no-cache', // Set the cache property
            body: JSON.stringify(body)
        };

        // Fetch JWT
        fetch(url, authOptions)
        .then(response => {
            // handle error response from Web API
            if (!response.ok) {
                const errorMsg = 'Login error: ' + response.status;
                console.log(errorMsg);
                return;
            }
            // Success!!!
            // Redirect to the database page
            window.location.href = "/portfolio_2025/data/database";
        })
        // catch fetch errors (ie ACCESS to server blocked)
        .catch(err => {
            console.error(err);
        });
    }
  • The code above sets an authentication checkpoint and if there isn’t a login error, the user is redirected to the database page

    Backend Code:

    def post(self):
              try:
                  body = request.get_json()
                  if not body:
                      return {
                          "message": "Please provide user details",
                          "data": None,
                          "error": "Bad request"
                      }, 400
                  ''' Get Data '''
                  uid = body.get('uid')
                  if uid is None:
                      return {'message': f'User ID is missing'}, 400
                  password = body.get('password')
                    
                  ''' Find user '''
                  user = User.query.filter_by(_uid=uid).first()
                  if user is None or not user.is_password(password):
                      return {'message': f"Invalid user id or password"}, 400
                  if user:
                      try:
                          token = jwt.encode(
                              {"_uid": user._uid},
                              current_app.config["SECRET_KEY"],
                              algorithm="HS256"
                          )
                          resp = Response("Authentication for %s successful" % (user._uid))
                          resp.set_cookie("jwt", token,
                                  max_age=3600,
                                  secure=True,
                                  httponly=True,
                                  path='/',
                                  samesite='None'  # This is the key part for cross-site requests
    
                                  # domain="frontend.com"
                                  )
                          return resp
    
  • The code checks if the user id and password match and if they do it creates a jwt token whic hit sends to the frontend which is what allowed the redirect into the database in the frontend
  • This corresponds to the “R” in CRUD as nothing really being modified, but instead just checked
  • After reaching the database page, the user’s inside the database are being displayed with a GET request, which is also a read operation

Updating the users

Frontend

    fetch(url, authOptions)
    function login_user(){
        // Set Authenticate endpoint
        const url = uri + '/api/users/';

        // Set the body of the request to include login data from the DOM
        const body = {
            uid: document.getElementById("uid").value,
            dob: document.getElementById("dob").value,
            favfood: document.getElementById("favfood").value
        };

        // Change options according to Authentication requirements
        const authOptions = {
            ...options, // This will copy all properties from options
            method: 'PUT', // Override the method property
            cache: 'no-cache', // Set the cache property
            body: JSON.stringify(body)
        };

        // Fetch JWT
        fetch(url, authOptions)
        .then(response => {
            // handle error response from Web API
            if (!response.ok) {
                const errorMsg = 'Login error: ' + response.status;
                console.log(errorMsg);
                return;
            }
            // Success!!!
            // Redirect to the database page
            window.location.href = "/portfolio_2025/data/database";
        })
        // catch fetch errors (ie ACCESS to server blocked)
        .catch(err => {
            console.error(err);
        });
    }

    // Attach login_user to the window object, allowing access to form action
    window.login_user = login_user;
  • This is part of a function which is run when the data for edit user is submitted
  • It uses a PUT request to update a specific user

    Backend

      @token_required
      def put(self, current_user):
          body = request.get_json() # get the body of the request
          uid = body.get('uid') # get the UID (Know what to reference)
          dob = body.get('dob')
          if dob is not None:
              try:
                  fdob = datetime.strptime(dob, '%Y-%m-%d').date()
              except:
                  return {'message': f'Date of birth format error {dob}, must be mm-dd-yyyy'}, 400
          users = User.query.all()
          for user in users:
              if user.uid == uid:
                  user.update('','','',fdob)
          return f"{user.read()} Updated"
    
  • In the backend, it iterates through all of the users and if it matches one of the uids in the database then the user is updated
  • This is an example of the “U” in CRUD

Deleting users

Frontend

const authOptions = {
    ...options, // This will copy all properties from options
    cache: 'no-cache',
    method: 'DELETE',
    mode: 'cors',
    headers: {
        'Content-Type': 'application/json',
        // 'Access-Control-Allow-Origin': '*'
    },
};

// Fetch JWT
fetch(url, authOptions)
.then(response => {
    // handle error response from Web API
    if (!response.ok) {
        const errorMsg = 'Login error: ' + response.status;
        console.log(errorMsg);
        return;
    }
  • DELETE request to the backend to remove a specific user

    Backend

    def delete(self, current_user):
      body = request.get_json()
      uid = body.get('uid')
      users = User.query.all()
      for user in users:
          if user.uid == uid:
              user.delete()
      return jsonify(users.read())
    
  • This is similar to the edit user part because it also iterates through the users to check if the user being deleted is in the database. If the user is, then the user is deleted
  • Corresponds to the “D” in CRUD