Skip to the content.

CRUD Check Blog

Review of week for CRUD Checkpoint

Nikhil

CRUD Integration Checkpoint (01/27/2025)

Executive Summary:

  • Made a database to store user chess games and the moves played in the form of PGN files.
  • Created a REST api with POST, GET, PATCH, and DELETE requests to manipulate data.
  • Created manager page on frontend to review, delete, and update games.
  • Created function request to save games automatically after completion.

Team Purpose:

  • Chess social platform to discuss, analyze and learn chess content. Our project will be a social media website and forum where users can discuss chess topics and interact with Artificial Intelligence to learn and play chess.

Individual Features:

  • The purpose of my feature for this review is to store games the user plays against the computer, this enables future review and analysis using the analysis page. The manager page employs CRUD functions so the user can manage the data.
  • The game feature enables the user to play chess and provide data and topics of discussion for the users.

Input/Output requests:

  • The PGN API has GET, POST, PATCH, and DELETE requests. The GET request is seen in the manager when the page is loaded as all the games are populated in cards, the POST request is made on the game page immediately after the game is over. The PATCH request is used to update the database entries, a PATCH request is used instead of a PUT as a PUT typically means all fields are changed, but for my data that would be illogical do I developed a PATCH method instead. Lastly, the DELETE request can also be used from the manager page. (to be shown in the live demo)
class _BULK_CRUD(Resource):
        def get(self):
            pgns = Pgn.query.all()
            json_ready = []
            for pgn in pgns:
                pgn_data = pgn.read()
                json_ready.append(pgn_data)
            return jsonify(json_ready)
class _CRUD(Resource):
        def post(self):
            body = request.get_json()
            body_pgn = body['pgn']
            body_name = body['name']
            body_id = body['user_id']

            ### TODO: Add error handling error for various input fields

            pgn_obj = Pgn(pgn=body['pgn'], date=body['date'], name=body['name'], user_id=body['user_id'])
            pgn_obj.create()
            # if not pgn:  # failure returns error message
            #     return {'message': f'Processed {body_pgn}, either a format error or User ID {body_id} is duplicate'}, 400

            return jsonify(pgn_obj.read())

        def delete(self):
            body = request.get_json()
            pgn = Pgn.query.get(body['id'])
            if not pgn:
                return {'message': 'Pgn not found'}, 404
            pgn.delete()
            return jsonify({"message": "pgn deleted"})

        def patch(self):
            body = request.get_json()
            pgn = Pgn.query.get(body['id'])
            if pgn is None:
                return {'message': 'Pgn not found'}, 404

            if 'name' in body:
                pgn._name = body['name']

            pgn.patch()
            return jsonify(pgn.read())
  • Postman requests work as well, and if breakpoint is placed on the return line the function will cease to function, displaying proper setup.

Requests & DOM:

  • The fetch request receives data from the REST API and is manipulated in the DOM (Document Object Model). Looping through the response object, and then accessing each property of each individual “game” to then be displayed.
async function fetchGames(){
        try {
            const response = await fetch(`${pythonURI}/api/pgns`, fetchOptions);
            if (!response.ok) {
                throw new Error('Failed to fetch groups: ' + response.statusText);
            }

            const games = await response.json();
            const container = document.getElementById('cards-container');
            container.innerHTML = '';

            games.forEach(game => {
                const card = document.createElement('div');
                card.className = 'card';
                card.innerHTML = `
                    <h3>${game.name}</h3>
                    <p>${game.pgn}</p>
                    <button class="button update">Update</button>
                    <button class="button delete">Delete</button>
                    <button class="button analyze">Analyze</button>
                `;

                card.querySelector('.delete').addEventListener('click', () => deleteGame(game.id));
                card.querySelector('.update').addEventListener('click', () => updateGame(game.id));
                card.querySelector('.analyze').addEventListener('click', () => redirectToAnalyze(game.id));
                container.appendChild(card);
            });
        } catch (error) {
            console.error('Error fetching entries:', error);
        }
    }

   async function deleteGame(id) {
        try {
            const response = await fetch(`${pythonURI}/api/pgn`, {
                method: 'DELETE',
                headers: {
                    'Accept': 'application/json',
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ id: id })
            });
            if (!response.ok) {
                throw new Error('Failed to delete: ' + response.statusText);
            }

            fetchGames();
        } catch (error) {
            console.error('Error deleting entry:', error);
        }
    }

    async function updateGame(id) {
        const newName = prompt("Enter the new name for the game:");
        try {
            const response = await fetch(`${pythonURI}/api/pgn`, {
                method: 'PATCH',
                headers: {
                    'Accept': 'application/json',
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ id: id, name: newName })
            });
            if (!response.ok) {
                throw new Error('Failed to delete: ' + response.statusText);
            }

            fetchGames();
        } catch (error) {
            console.error('Error deleting entry:', error);
        }
    }

    		async function makeGame(pgn) {
			try {
				const response = await fetch(`${pythonURI}/api/pgn`, {
					method: 'POST',
					headers: {
						'Accept': 'application/json',
						'Content-Type': 'application/json'
					},
					body: JSON.stringify({ pgn: pgn, date: '01/23/2025', name: 'placeholder', user_id: 3 })
				});
				if (!response.ok) {
					throw new Error('Failed to delete: ' + response.statusText);
				}
			} catch (error) {
				console.error('Error deleting entry:', error);
			}
		}
  • The queries to database are made by Flask_SQLAlchemy which is an ORM (Object Relational Manager) that abstracts the SQL requests enabling easier interfacing with the database.
    def delete(self):
        try:
            db.session.delete(self)
            db.session.commit()
        except Exception as e:
            db.session.rollback()
            raise e
    
    def patch(self):
        inputs = Pgn.query.get(self.id)

        if inputs._pgn:
            self._pgn = inputs._pgn
        if inputs._date:
            self._date = inputs._date
        if inputs._name:
            self._name = inputs._name

        try:
            db.session.commit()
        except IntegrityError:
            db.session.rollback()
            logging.warning(f"IntegrityError: Could not update pgn entry.")
            return None
        return self
  • The classes in my API file have multiple methods that can be called, most process the request data, parse it, perform the associated database operation and return a response. The database operations that create, delete, read, etc, are defined in the model file.

Algorithmic Request:

  • My “_CRUD” class handles POST, DELETE, and PATCH Requests. Based on the fetch request parameters one of the methods is called the corresponding logic executed. The function take the request data, parse it if necessary call the database function required and return a response (status like 200, or 404, or something else.)
  • The delete method, obtains the entry id to be deleted from the fetch request, then it searches through the database to find the entry and delete it. The development of the function involved iteration, as I tested what parameters to be sent from frontend, in the end the entry id was most logical and efficient.
  • The body of the request contains the id, and the response contains a status message and status code. Should the call be successful, it will say “PGN deleted” with a 200 status code, else it returns “PGN could not be found” with a 404 error code.

Call to Algorithm Request:

  • The delete request is called when a click is made on the delete button, an event listener listens for a click action and calls the delete function accordingly which makes the fetch request. The fetch makes a DELETE call to /api/pgn and passes a body with an id to be deleted. The fetch request is a try-except block to handle errors.
  • After the response is returned, should there be no issues the function that runs the GET request will be called to update the page after the delete request, else error messages are printed.
  • The sole parameter is the entry’s id, and the jsonify response is a a string indicating success or error along with the corresponding HTTP status code.
 async function updateGame(id) {
        const newName = prompt("Enter the new name for the game:");
        try {
            const response = await fetch(`${pythonURI}/api/pgn`, {
                method: 'PATCH',
                headers: {
                    'Accept': 'application/json',
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ id: id, name: newName })
            });
            if (!response.ok) {
                throw new Error('Failed to delete: ' + response.statusText);
            }

            fetchGames();
        } catch (error) {
            console.error('Error deleting entry:', error);
        }
    }

Vasanth

CRUD Integration Checkpoint (01/27/2025)

Executive Summary:

Developed a system for users to track and manage their skills.

Team Purpose:

Our project provides a social platform for users to track and improve their skills, manage profiles, and track progress.

Individual Features:

For this review, I focused on the skills feature, where users can input, track, update, and delete their skills. This feature is essential for users to document and modify their skill sets easily, with functionality including creating new skills, updating skill details, and deleting skills they no longer wish to track. The frontend allows users to interact with this system through forms and buttons for the CRUD operations, while the backend stores and processes all data for persistence.

Input/Output requests:

The Skills API supports the basic CRUD operations:

  • GET: Retrieves a list of all skills or a specific skill by ID. This request is handled when the page loads or when a user requests a specific skill.
  • POST: Allows users to add new skills to the database. This is done through the form on the frontend, where the user submits the skill name, skill level, and user ID.
  • PUT: Enables users to update existing skills. If a user wishes to update their skill name or skill level, they can modify it using the “Update” button, which sends a PUT request to the API.
  • DELETE: Removes a specific skill from the database. The user can delete a skill by clicking the “Delete” button next to the corresponding entry.

Requests are handled by Flask_SQLAlchemy, which uses an ORM to manage the interaction with the database, allowing easy retrieval and manipulation of skill data.

Requests & DOM:

The fetch requests interact with the backend API using the POST, PUT, GET, and DELETE methods. After fetching data from the API, the frontend dynamically populates a table to display the skill data. This table allows the user to view and interact with each entry, using buttons for adding, updating, and deleting skills.

The database operations are managed by SQLAlchemy in the backend, which abstracts the SQL queries and simplifies working with the data. The logic for the CRUD functions is handled in the SkillAPI class, where each method (POST, GET, PUT, DELETE) processes the request, interacts with the database, and sends back a response to the frontend.

    const API_URL = 'http://127.0.0.1:8887/api/skill'; // Replace with your actual API endpoint

    // Fetch skills from the database and display them in the table (GET)
    async function fetchSkills() {
        try {
            // Make a GET request to fetch all skills from the API
            const response = await fetch(API_URL, { method: 'GET' });

            // Handle HTTP errors
            if (!response.ok) throw new Error('Failed to fetch skills.');

            // Parse the JSON response
            const skills = await response.json();

            // Get the skills table element and clear any existing rows
            const table = document.getElementById('skillsTable');
            table.innerHTML = ''; // Clear table before populating

            // Add each skill as a row in the table
            skills.forEach(skill => addRowToTable(skill.id, skill.skill_name, skill.skill_level));
        } catch (error) {
            console.error('Error fetching skills:', error);
        }
    }

    // Add a new skill to the database and table (POST)
    async function addSkill(event) {
        event.preventDefault(); // Prevent form submission to avoid page refresh

        // Retrieve values from input fields
        const idInput = document.getElementById('idInput').value.trim();
        const skillInput = document.getElementById('skillInput').value.trim();
        const rankInput = document.getElementById('rankInput').value.trim();

        // Validate input fields
        if (idInput && skillInput && rankInput) {
            const newSkill = {
                skill_name: skillInput, // Skill name
                skill_level: rankInput, // Skill level
                user_id: parseInt(idInput, 10), // User ID (convert string to integer)
            };

            try {
                // Make a POST request to add the new skill
                const response = await fetch(API_URL, {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify(newSkill),
                });

                // Handle HTTP errors
                if (!response.ok) throw new Error('Failed to add skill.');

                // Parse the response and update the table
                const result = await response.json();
                addRowToTable(result.id, result.skill_name, result.skill_level);

                // Clear input fields after successful submission
                document.getElementById('idInput').value = '';
                document.getElementById('skillInput').value = '';
                document.getElementById('rankInput').value = '';
            } catch (error) {
                console.error('Error adding skill:', error);
            }
        }
    }

    // Add a new row to the table (helper function)
    function addRowToTable(id, skillName, level) {
        const table = document.getElementById('skillsTable');
        const row = table.insertRow(); // Create a new row in the table

        // Insert cells for ID, Skill Name, and Level
        row.insertCell(0).textContent = id;
        row.insertCell(1).textContent = skillName;
        row.insertCell(2).textContent = level;

        // Create a cell for action buttons (Update and Delete)
        const actionCell = row.insertCell(3);
        actionCell.classList.add('action-buttons');

        // Create and configure the Update button
        const updateButton = document.createElement('button');
        updateButton.textContent = 'Update';
        updateButton.classList.add('update-button');
        updateButton.onclick = () => updateRow(row, id);

        // Create and configure the Delete button
        const deleteButton = document.createElement('button');
        deleteButton.textContent = 'Delete';
        deleteButton.classList.add('delete-button');
        deleteButton.onclick = () => deleteRow(row, id);

        // Append the buttons to the action cell
        actionCell.appendChild(updateButton);
        actionCell.appendChild(deleteButton);
    }

    // Update a skill in the database and table (PUT)
    async function updateRow(row, id) {
        // Get the current values from the row
        const skillCell = row.cells[1];
        const levelCell = row.cells[2];

        // Prompt the user for new values
        const newSkillName = prompt('Update Skill Name:', skillCell.textContent);
        const newLevel = prompt('Update Level:', levelCell.textContent);

        // If the user provides valid inputs, proceed with the update
        if (newSkillName !== null && newLevel !== null) {
            const updatedSkill = {
                id: id, // Skill ID
                skill_name: newSkillName.trim(), // New skill name
                skill_level: newLevel.trim(), // New skill level
                user_id: parseInt(id, 10), // User ID (convert string to integer)
            };

            try {
                // Make a PUT request to update the skill
                const response = await fetch(`${API_URL}`, {
                    method: 'PUT',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify(updatedSkill),
                });

                // Handle HTTP errors
                if (!response.ok) throw new Error('Failed to update skill.');

                // Update the table row with the new values
                skillCell.textContent = updatedSkill.skill_name;
                levelCell.textContent = updatedSkill.skill_level;
            } catch (error) {
                console.error('Error updating skill:', error);
            }
        }
    }

    // Delete a skill from the database and remove the row (DELETE)
    async function deleteRow(row, id) {
        // Confirm the deletion with the user
        if (confirm('Are you sure you want to delete this skill?')) {
            try {
                // Make a DELETE request to remove the skill
                const response = await fetch(`${API_URL}`, {
                    method: 'DELETE',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ id }), // Send the skill ID in the request body
                });

                // Handle HTTP errors
                if (!response.ok) throw new Error('Failed to delete skill.');

                // Remove the row from the table on success
                row.remove();
            } catch (error) {
                console.error('Error deleting skill:', error);
            }
        }
    }

    // Attach event listener to the form for adding skills
    document.getElementById('addSkillForm').addEventListener('submit', addSkill);

    // Fetch and display skills when the page loads
    window.onload = fetchSkills;

Algorithmic Request:

The _CRUD class within the API handles the main operations: POST, PUT, and DELETE requests. When the frontend triggers one of these actions (e.g., clicking the “Add Skill” button or updating a skill), the corresponding method in the class is executed. Each method takes the necessary input data, processes it, and calls the appropriate function to interact with the database.

class SkillAPI:
    class _CRUD(Resource):
        def post(self):
            """
            Create a new skill entry.
            """
            data = request.get_json()

            # Validate required fields
            if not data or 'skill_name' not in data or 'skill_level' not in data or 'user_id' not in data:
                return {'message': 'Skill Name, Level, and User ID are required.'}, 400

            # Create a new skill
            skill = Skill(
                skill_name=data.get('skill_name'),
                skill_level=data.get('skill_level'),
                user_id=data.get('user_id')
            )
            try:
                skill.create()
                return jsonify(skill.read())
            except Exception as e:
                return {'message': f'Error saving skill: {e}'}, 500

        def get(self):
            """
            Retrieve a skill by ID or all skills.
            """
            skill_id = request.args.get('id')

            # Fetch a specific skill if ID is provided
            if skill_id:
                skill = Skill.query.get(skill_id)
                if not skill:
                    return {'message': 'Skill not found'}, 404
                return jsonify(skill.read())

            # Fetch all skills
            all_skills = Skill.query.all()
            return jsonify([skill.read() for skill in all_skills])

        def put(self):
            """
            Update an existing skill entry.
            """
            data = request.get_json()

            # Validate required fields
            if not data or 'id' not in data:
                return {'message': 'ID is required for updating a skill'}, 400

            # Find the skill by ID
            skill = Skill.query.get(data['id'])
            if not skill:
                return {'message': 'Skill not found'}, 404

            # Update the skill
            try:
                if 'skill_name' in data:
                    skill._skill_name = data['skill_name']
                if 'skill_level' in data:
                    skill._skill_level = data['skill_level']
                if 'user_id' in data:
                    skill._user_id = data['user_id']
                skill.create()  # Save changes
                return jsonify(skill.read())
            except Exception as e:
                return {'message': f'Error updating skill: {e}'}, 500

        def delete(self):
            """
            Delete a skill entry.
            """
            data = request.get_json()

            # Validate required fields
            if not data or 'id' not in data:
                return {'message': 'ID is required for deleting a skill'}, 400

            # Find the skill by ID
            skill = Skill.query.get(data['id'])
            if not skill:
                return {'message': 'Skill not found'}, 404

            # Delete the skill
            try:
                skill.delete()
                return {'message': 'Skill deleted successfully'}, 200
            except Exception as e:
                return {'message': f'Error deleting skill: {e}'}, 500

For instance, in the delete method, when a user clicks the delete button, the method obtains the skill ID, searches for it in the database, and deletes the entry. This ensures that the skill is completely removed from the system. The response is returned to the frontend, confirming the action with either a success or error message.

Call to Algorithm Request:

The backend logic is triggered by frontend events such as form submissions and button clicks. For example, when the “Add Skill” button is clicked, the form data is sent as a POST request to the API. The request body contains the skill details (name, level, user ID), and the backend creates the new entry in the database.

Similarly, when a user clicks the “Update” or “Delete” button for a specific skill, the frontend sends the corresponding PUT or DELETE request to the API. The backend processes these requests and updates the database accordingly. After each operation, a GET request is automatically triggered to refresh the frontend and display the latest data.

For all actions (POST, PUT, DELETE), error handling is implemented in both frontend and backend. In case of an issue, an appropriate message is displayed to the user, and the operation is canceled if necessary.

// Update a skill in the database and table (PUT)
async function updateRow(row, id) {
    // Access the cells in the row that contain the skill name and skill level
    const skillCell = row.cells[1];
    const levelCell = row.cells[2];

    // Prompt the user to input the new skill name and skill level, prefilled with current values
    const newSkillName = prompt('Update Skill Name:', skillCell.textContent);
    const newLevel = prompt('Update Level:', levelCell.textContent);

    // Proceed if both values are provided (not null)
    if (newSkillName !== null && newLevel !== null) {
        // Create an updated skill object with the new values
        const updatedSkill = {
            id: id,  // Unique ID of the skill being updated
            skill_name: newSkillName.trim(),  // Updated skill name (trimmed of extra spaces)
            skill_level: newLevel.trim(),  // Updated skill level (trimmed of extra spaces)
            user_id: parseInt(id, 10),  // User ID associated with the skill (converted to integer)
        };

        try {
            // Send the updated skill data to the backend using a PUT request
            const response = await fetch(`${API_URL}`, {
                method: 'PUT',  // Use PUT method to update data
                headers: { 'Content-Type': 'application/json' },  // Specify that the body is JSON
                body: JSON.stringify(updatedSkill),  // Convert the updated skill object to a JSON string
            });

            // If the response is not OK (e.g., server error), throw an error
            if (!response.ok) throw new Error('Failed to update skill.');

            // If the update is successful, update the table row to reflect the changes
            skillCell.textContent = updatedSkill.skill_name;
            levelCell.textContent = updatedSkill.skill_level;
        } catch (error) {
            // Log any errors that occur during the PUT request
            console.error('Error updating skill:', error);
        }
    }
}

Fetch Request


    // Fetch skills from the database and display them in the table (GET)
    async function fetchSkills() {
        try {
            const response = await fetch(API_URL, { method: 'GET' });
            if (!response.ok) throw new Error('Failed to fetch skills.');

            const skills = await response.json();
            const table = document.getElementById('skillsTable');
            table.innerHTML = ''; // Clear table before populating

            skills.forEach(skill => addRowToTable(skill.id, skill.skill_name, skill.skill_level));
        } catch (error) {
            console.error('Error fetching skills:', error);
        }
    }

Aarush

FULL STACK BLOG - AARUSH

Executive Summary:

For this sprint, I developed a full-stack feature that stores, manages, and analyzes chess moves and their evaluations. I created a backend database to store chess moves, built a RESTful API for CRUD operations, and integrated the backend with a frontend interface. Users can interact with this feature on the analysis page, where they can view, add, update, and delete chess moves dynamically.

Team Purpose:

Our team is working on a chess-based social media platform where users can discuss chess strategies, analyze their games, and learn from others. My feature complements this vision by providing users with the tools to analyze their games, save key moves, and review them later for improvement and discussion.

Individual Feature:

My feature focuses on enabling users to store and manage their chess moves and evaluations. Users can upload PGN files to analyze moves and save these moves to a database for later use. The manager page lets users perform CRUD operations, providing full control over their stored data. This feature enhances the user experience by allowing in-depth review and customization of their chess gameplay data. Key functionalities include:

  • POST: Adds a new evaluation to the database with the move number, move, and evaluation score.
    def post(self):
      data = request.get_json()
      if not data or 'evaluation' not in data or 'move' not in data or 'move_number' not in data:
          return {'message': 'Move data is required.'}, 400
      evaluation = Evaluation(
          evaluation=data.get('evaluation'),
          move=data.get('move'),
          move_number=data.get('move_number')
      )
      try:
          evaluation.create()
          return jsonify(evaluation.read()), 201
      except Exception as e:
          return {'message': f'Error saving evaluation: {e}'}, 500
    
  • GET: Displays all saved moves in a dynamic table on the analysis page.
    def get(self):
      all_evaluations = Evaluation.query.all()
      return jsonify([evaluation.read() for evaluation in all_evaluations])
    
  • PUT: Updates the evaluation or status of a move (e.g., marking it as “played”).
    def put(self):
      data = request.get_json()
      if not data or 'id' not in data:
          return {'message': 'ID is required to update the evaluation'}, 400
      evaluation = Evaluation.query.get(data['id'])
      if not evaluation:
          return {'message': 'Evaluation not found'}, 404
      try:
          evaluation.update(data)
          return jsonify(evaluation.read())
      except Exception as e:
          return {'message': f'Error updating evaluation: {e}'}, 500
    
  • DELETE: Removes moves from the database when no longer needed.
    def delete(self):
      data = request.get_json()
      if not data or 'id' not in data:
          return {'message': 'ID is required for deletion'}, 400
      evaluation = Evaluation.query.get(data['id'])
      if not evaluation:
          return {'message': 'Evaluation not found'}, 404
      try:
          evaluation.delete()
          return {'message': 'Evaluation deleted successfully'}, 200
      except Exception as e:
          return {'message': f'Error deleting evaluation: {e}'}, 500
    

    Input/Output Requests:

    The evaluation API supports all CRUD operations:

    1. GET: The analysis page fetches all moves from the backend and displays them in a table dynamically.
    2. POST: A POST request is triggered when a game is completed, saving new moves and their evaluations to the database.
    3. PUT: Users can update the status of a move, such as marking it as “played,” which sends a PUT request to the API.
    4. DELETE: A DELETE request is made when a user removes a move using the “Remove” button. These requests have been tested thoroughly using Postman to ensure correct functionality. Error handling ensures proper HTTP status codes (e.g., 200 for success, 404 for not found) are returned for each request.

      Requests & DOM Integration:

      Fetch requests on the frontend dynamically interact with the REST API:

  • GET Requests: Populate the DOM by fetching data from the backend and rendering it in a table. Loops are used to iterate through the response data, creating rows dynamically.
  • POST Requests: Send new move data to the backend when a game concludes, and update the DOM to reflect the added move.
  • PUT Requests: Allow users to edit move details, such as changing the evaluation or marking a move as “played.”
  • DELETE Requests: Dynamically remove moves from the database and the DOM. The backend uses Flask_SQLAlchemy as an ORM to manage database queries, abstracting SQL operations for ease of development.

    Algorithmic Requests:

    My _CRUD class in the backend API handles POST, PUT, and DELETE requests:

  • The POST method takes move data from the frontend, validates it, and adds it to the database. Duplicate checks ensure data integrity.
  • The PUT method allows partial updates to entries, such as changing the evaluation or marking a move as “played.”
  • The DELETE method removes a move from the database based on its unique ID, returning an appropriate success or error message. Each method parses incoming request data, performs validation, interacts with the database, and returns a JSON response with a status code.

    Call to Algorithm Requests:

    Frontend JavaScript functions handle the integration of the REST API with the UI:

  • A POST request is triggered when the user adds a move played in the game according to provided pgn file.
  • GET requests populate the moves table on page load, displaying all saved moves.
  • PUT requests allow users to mark moves as “played” or update their evaluations. These changes are reflected immediately in the DOM.
  • DELETE requests remove moves from the database and dynamically update the table to reflect the changes. For example, the “Mark as Played” button sends a PUT request to the API. Once the request is successful, the move is added to the “Played Moves” list and removed from the available moves table.

    Summary:

    This feature provided valuable experience in building and integrating a full-stack application:

  • Backend: Developed a RESTful API with robust CRUD operations and integrated it with a database.
  • Frontend: Designed a dynamic interface that allows users to manage their chess gameplay data effectively.
  • Testing: Used Postman for testing API endpoints and ensured smooth interaction between the backend and frontend. This project helped me better understand the complexities of full-stack development, especially in managing state and ensuring seamless communication between the frontend and backend. I’m excited to refine and expand this feature in future sprints