Skip to the content.

CSP blog

Purpose of your groups program

The purpose of my groups program is to help club leaders and members in Del Norte High School to communicate easily through our platform. The website helps keep control and organize events, announcements, leaderships, and members. Students can also discover a club based on their interests. This will help students increase interest in joining clubs. Often, clubs don’t have a place where they can communicate. Some clubs use instagram, some use group chat, and some clubs don’t have one. But, with this website, all the clubs will be able to communicate on the same space.

Purpose of your individual feature(s)

The purpose of my individual feature is to let presidents and other leaders of a club to announce events and make events easily. For example, if there is a competition, the president simply has to type their event on the form and click create on events tab, and other members will be able to view the event.

My feature

  • when the club has been created, I can select a club to add an event
  • create an event for club
  • edit/update the event
  • delete the event

Event Data Management and CRUD Operations

My code manages event data using Python data structures and a database. Events are stored in the database, with each row represented as a dictionary, where keys correspond to column names. The Event class handles CRUD operations like creating events with create_event() or updating them using update_event(). SQLAlchemy manages database interactions, and data is formatted into dictionaries using to_dict() for consistent frontend integration.

API Request Structure and Operations (CRUD)

API requests are structured using class-based methods for GET, POST, PUT, and DELETE operations. GET retrieves events, POST creates new ones, PUT updates existing records, and DELETE removes them. These methods use SQLAlchemy for database queries, applying sequencing, selection, and iteration for logic. Responses are formatted as JSON using Flask’s jsonify() to ensure seamless communication with the frontend.

my database table code

class Event(db.Model):
    __tablename__ = 'events'

    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(255), nullable=False)
    description = db.Column(db.String(255), nullable=False)
    date = db.Column(db.Date, nullable=False)

CRUD code

    def read(self): # returns the result of calling the to_dict(), access an object's data 
        return self.to_dict()

    def create(self):
        """
        Creates a new event in the database.
        """
        try:
            db.session.add(self) #  object (self) and add it to the session
            db.session.commit() # save changes to db
        except IntegrityError as e:
            db.session.rollback() # undoes the transaction
            logging.warning(f"IntegrityError: Could not create event '{self.title}' due to {str(e)}.")
            return None
        return self

    def update(self, data):
        """
        Updates the event with new data.
        """
        for key, value in data.items():
            if hasattr(self, key):
                # Convert date string to date object if necessary
                if key == 'date' and isinstance(value, str):
                    value = datetime.strptime(value, '%Y-%m-%d').date()
                setattr(self, key, value)
        try:
            db.session.commit()
        except IntegrityError as e:
            db.session.rollback()
            logging.warning(f"IntegrityError: Could not update event '{self.title}' due to {str(e)}.")
            return None
        return self

    def delete(self):
        try:
            db.session.delete(self)
            db.session.commit()
        except IntegrityError:
            db.session.rollback()
            logging.warning(f"Could not delete event '{self.title}' due to IntegrityError.")
            return N

Big Idea 1.4 Debugging Code and Fixing Errors

  1. Debugging API Requests (Validation Checks)
    if not data:
     return {'message': 'No input data provided'}, 400
    if 'title' not in data:
     return {'message': 'Event title is required'}, 400
    if 'description' not in data:
     return {'message': 'Event description is required'}, 400
    if 'date' not in data:
     return {'message': 'Event date is required'}, 400
    

    gives me different errors and these checks prevent invalid data from being processed.

  2. Using Postman for API Testing and Debugging:
class EventAPI:
    class _CRUD(Resource):
        @token_required
        def post(self):
            data = request.get_json()
            if not data:
                return {'message': 'No input data provided'}, 400
            event = Event(title=data['title'], description=data['description'], date=data['date'])
            event.create()
            return jsonify(event.to_dict())

These endpoints can be tested and debugged using Postman by sending requests and checking responses.

Using frontend show API request and present API response. (live demo)

Image Image Image

The user submits a form to send data to the backend. The frontend send an API request to the backend. Backend returns responce with data. And frontend displays the information. And then, the user and other users will be able to see the event they created.

Using postman to show raw API request and RESTful response (error code(s) and JSON)

Image

When I put all three requirements, which is title(club name), description, and date, the data saves.

Image

The demo includes both a working request (with successful data) and an error request (demonstrating how errors are handled).

Using db_init, db_restore, db_backup to show tester data creation and data recovery.

Image

This is my static data Image

and this is my dynamic data.

Image Image

Then, I backup and delete the database. After, I initialize new database and restore, and it restores the dynamic data.

List requests. Use of list, dictionaries and database. Code descriptions of area where you work with list (rows) and dictionaries (columns) of the database.

Discuss formatting response data (JSON) from API into DOM

  1. List, Dictionaries, and Database

This is a list from my code, and

events = Event.query.all() # retrieving all events
return jsonify([event.to_dict() for event in events])  # Return a list of events as JSON

and this is dictionary format.

    def to_dict(self):
        """
        Convert the Event object into a dictionary format.
        This method is used to return the event object as JSON in API responses.
        """
        return {
            "id": self.id,
            "title": self.title,
            "description": self.description,
            "date": self.date.strftime('%Y-%m-%d')
        }

This code is to query the database to retrieve records, and those records are returned as lists of dictionaries

  1. Formatting Response Data (JSON)

The data from the database (or from a list of dictionaries) is formatted into JSON before being sent to the frontend.

return jsonify([event.to_dict() for event in events])

the response will be like


[
    {
        "title": "Tech Conference",
        "description": "A conference about tech.",
        "date": "2025-05-20"
    },
    {
        "title": "Music Festival",
        "description": "A festival featuring music.",
        "date": "2025-06-15"
    }
]
  1. API Response Data into the DOM

Once the API sends back the JSON response, it can be displayed on a webpage by converting the JSON data into HTML elements.

DOM is the structure of the frontend of a webpage.


async function fetchAndDisplayEvents() {
    const token = localStorage.getItem('authToken'); // Get the auth token
    try {
        // Send GET request to fetch events from API
        const response = await fetch(`${pythonURI}/api/event`, {
            method: 'GET',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${token}` // Send token for authentication
            }
        });
        if (response.ok) {
            const fetchedEvents = await response.json(); // Parse the response JSON
            events = fetchedEvents; // Store events in global variable
            eventListContainer.innerHTML = ''; // Clear existing events in the DOM

This is an example of API to DOM in my code.

The fetchAndDisplayEvents() function fetches event data from the backend API and display it.

API Call: The fetch() function sends a GET request to the backend to fetch all events.

Discuss API class (code block) you used to perform get, post, put, and delete methods.

We use get, post, put, and delete to handle CRUD operations, which include, create, read, update, and delete.

Get method returns all events stored in the events list as a JSON response.

Post method listens for POST requests to the /api/event endpoint. It expects JSON data (title, description, and date) to create a new event.

Put method is used for an event ID and the updated data.

Delete method is used for deleting event.

These are my post, put, get, and delete


def post(self):
            """
            Create a new event.
            """
            current_user = g.current_user # retrieve data of current user
            data = request.get_json() # change json to python dictionary

            if not data:
                return {'message': 'No input data provided'}, 400
            if 'title' not in data:
                return {'message': 'Event title is required'}, 400
            if 'description' not in data:
                return {'message': 'Event description is required'}, 400
            if 'date' not in data:
                return {'message': 'Event date is required'}, 400

            # Create a new event object
            event = Event(title=data['title'], description=data['description'], date=data['date'])
            event.create()

            return jsonify(event.to_dict())

        @token_required
        def get(self): # display and retrieve all events
            """
            Retrieve all Events.
            """
            events = Event.query.all() # retrieving all events
            if not events:
                return {'message': 'No events found'}, 404  
            return jsonify([event.to_dict() for event in events])  # Return a list of events as JSON
        @token_required
        def put(self):
            """
            Update an event.
            """
            current_user = g.current_user  # Retrieve data of current user
            data = request.get_json()  # Change JSON to Python dictionary

            if not data or 'id' not in data:
                return {'message': 'Event ID is required'}, 400

            event = Event.query.get(data['id'])  # Retrieve event by ID
            if event is None:
                return {'message': 'Event not found'}, 404

            updated_event = event.update(data)
            if updated_event:
                return jsonify(updated_event.to_dict())
            else:
                return {'message': 'An error occurred while updating the event. Please try again.'}, 500

        @token_required
        def delete(self):
            """
            Delete an event.
            """
            current_user = g.current_user
            data = request.get_json()
            event = Event.query.get(data['id'])
            if event is None:
                return {'message': 'Event not found'}, 404
            event.delete()
            return jsonify({"message": "Event deleted"})

Discuss a method/procedure in class that contains sequencing, selection, and iteration.

Sequencing: Sequencing refers to executing statements in the order they are written. It ensures that actions happen one after the other in a logical way.

Selection: Choosing between different actions based on certain conditions (like “if” or “else”). It helps the program decide what to do next based on specific rules

Iteration: Repeating actions over and over, usually with loops (like “for” or “while”). It helps the program go through lists of things, or keep checking something until a condition is met.

sequence:

def initEvents(): # initEvents` function initializes the Events table with test data.
    """
    Initializes the Events table with test data.
    """
    with app.app_context(): # creates an application context for the app.
        db.create_all() 
        events = [ # creates a list of Event objects
            Event(title='Tech Conference', description='A conference about the latest in technology.', date='2025-05-20'),
            Event(title='Music Festival', description='A festival featuring various music artists.', date='2025-06-15'),
            Event(title='Art Expo', description='An expo showcasing modern art.', date='2025-07-10'),
        ]
        for event in events: 
            try:
                event.create()
                print(f"Record created: {repr(event)}")
            except IntegrityError as e:
                db.session.rollback()
                print(f"Records exist or duplicate error: {event.title}, {str(e)}")

create tables, define event, put it into db. each step doesnt start until previous step is done, so this is sequencing.

In this part of the post method, the statements are executed sequentially. First, an Event object is created using the provided data, and then the create() method is called to save the event in the database.

Selection ex from my code:


if not data:
    return {'message': 'No input data provided'}, 400
if 'title' not in data:
    return {'message': 'Event title is required'}, 400
if 'description' not in data:
    return {'message': 'Event description is required'}, 400

Iteration ex:


for event in events:
    response = client.post('/api/event', json=event)
    if response.status_code == 200:
        results['success_count'] += 1
    else:
        results['errors'].append(response.get_json())
        results['error_count'] += 1

This loop iterates through the list of events and sends a POST request for each event. It then checks whether the request was successful

Discuss the parameters (body of request) and return type (jasonify) of the function.

  1. Body parameters: the parameters passed to the API functions are extracted from the body of the request, typically in JSON format.

this is an example.


const payload = {
    title: eventTitle,
    description: eventDescription,
    date: eventDate,
};

const response = await fetch(`${pythonURI}/api/event`, {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${token}`,
    },
    body: JSON.stringify(payload), // Send body parameters as JSON string
});

PUT method parameters:


data = request.get_json()
if 'id' not in data:
    return {'message': 'Event ID is required'}, 400

delete method:


data = request.get_json()
event = Event.query.get(data['id'])
  1. RETURN TYPE

The jsonify function converts Python dictionaries or other data structures into JSON responses

return jsonify(event.to_dict()) is used to send the event data as a JSON object.


POST: 

{
    "title": "New Event",
    "description": "A special event",
    "date": "2025-02-10"
}

GET: 

[
    {
        "title": "Event 1",
        "description": "Description of Event 1",
        "date": "2025-02-01"
    },
    {
        "title": "Event 2",
        "description": "Description of Event 2",
        "date": "2025-02-05"
    }
]

PUT: 

{
    "id": 1,
    "title": "Updated Event",
    "description": "Updated description",
    "date": "2025-02-10"
}

Delete: 

{
    "message": "Event deleted"
}

putting request into json format.

Call to Algorithm request. Show the definition of code block to make a request.

Discuss the call/request to the method with Algorithm (fetch to endpoint).

definition of code block to make a request:

  1. Defining the API Endpoint: This is the URL to which the request will be sent ${pythonURI}/api/event
  2. Setting the Method: The HTTP method (GET, POST, PUT, DELETE, etc.) defines what action will be performed.
  3. authentication
  4. body
  5. make a request
  6. handle respose.

Algorithm for Making a Request

    eventForm.addEventListener('submit', async function (e) {
        e.preventDefault(); // Prevent default form submission
        // Get values from form inputs
        const clubName = clubNameSelect.value.trim();
        const eventDescription = document.getElementById('eventDescription').value.trim();
        const eventDate = document.getElementById('eventDate').value;
        // Check if all required fields are filled
        if (clubName && eventDescription && eventDate) {
            const payload = {
                title: clubName,
                description: eventDescription,
                date: eventDate,
            };
            const token = localStorage.getItem('authToken'); // Replace 'authToken' with the key where you store your token
            try {
                const response = await fetch(`${pythonURI}/api/event`, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'Authorization': `Bearer ${token}` // Add the token to the request headers
                    },
                    body: JSON.stringify(payload)
                });
                if (response.ok) {
                    fetchAndDisplayEvents(); // Refresh the event list
                    formContainer.style.display = 'none'; // Hide the form
                } else {
                    const error = await response.json();
                    alert(`Error: ${error.message}`);
                }
            } catch (error) {
                alert('An error occurred while creating the event. Please try again.');
                console.error(error);
            }
        } else {
            alert("Please fill out all fields!");
        }
    });
  1. Event Listener for Form Submission: This listens for the submit event on the eventForm element and prevents the default form submission behavior.

  2. Retrieve Form Input Values:


const clubName = clubNameSelect.value.trim();
const eventDescription = document.getElementById('eventDescription').value.trim();
const eventDate = document.getElementById('eventDate').value;

The values from the form inputs (club name, event description, and event date) are retrieved. collecting data.

  1. Check If All Fields Are Filled:
if (clubName && eventDescription && eventDate) {
  1. Prepare the Payload (Request Body):
const payload = {
    title: clubName,
    description: eventDescription,
    date: eventDate,
};

If the fields are filled, the data is packaged into a payload object, which will be sent as the request body in JSON format.

The payload is the data that you send to the server in the body of the request. It usually contains the information that the server needs to process the request, such as the content you want to store, update, or manipulate.

  1. Get Authentication Token:
const token = localStorage.getItem('authToken');

This retrieves the authentication token stored in the browser’s local storage, which is needed for authorization to create the event.

  1. Send the POST Request
const response = await fetch(`${pythonURI}/api/event`, {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${token}`,
    },
    body: JSON.stringify(payload),
});

This sends a POST request to the backend API with the event data in the request body. The headers specify that the data is in JSON format and include the authentication token for authorization.

  1. Handle the Response:
if (response.ok) {
    fetchAndDisplayEvents(); // Refresh the event list
    formContainer.style.display = 'none'; // Hide the form
} else {
    const error = await response.json();
    alert(`Error: ${error.message}`);
}

If the response is successful (response.ok), it fetches and displays the updated list of events (fetchAndDisplayEvents()) and hides the form.

If the response is not successful, it parses and displays the error message.

  1. Error handling
    catch (error) {
     alert('An error occurred while creating the event. Please try again.');
     console.error(error);
    }
    

    If any error occurs during the request (e.g., network issues), the user is alerted and the error is logged to the console.

  2. Validation for Empty Fields:
else {
    alert("Please fill out all fields!");
}

If any field is empty, the user is prompted to fill out all the fields before submitting the form.

Discuss the return/response from the method with Algorithm (fetch) and how you handle data.

response

return jsonify(updated_event.to_dict()) # Return updated event data as JSON

When the event is successfully updated, the server returns the updated event data in the response. The event data is serialized to JSON format using jsonify().

smth like this


{
    "id": 1,
    "title": "Updated Event Title",
    "description": "Updated Event Description",
    "date": "2025-02-12"
}

How Data Is Handled in the Method

ex of PUT method

  1. receive request
data = request.get_json()  # Change JSON to Python dictionary
  1. check if I put everything
    if not data or 'id' not in data:
     return {'message': 'Event ID is required'}, 400
    
  2. check id of the event
    event = Event.query.get(data['id'])  # Retrieve event by ID
    if event is None:
     return {'message': 'Event not found'}, 404
    
  3. update
    updated_event = event.update(data)  # Update the event with the new data
    

    Show how changing data or method triggers a different response, specifically normal conditions and error conditions.

my code for post


@token_required
def post(self):
    """
    Create a new event.
    """
    current_user = g.current_user  # retrieve data of current user
    data = request.get_json()  # change json to python dictionary

    if not data:
        return {'message': 'No input data provided'}, 400
    if 'title' not in data:
        return {'message': 'Event title is required'}, 400
    if 'description' not in data:
        return {'message': 'Event description is required'}, 400
    if 'date' not in data:
        return {'message': 'Event date is required'}, 400

    # Create a new event object
    event = Event(title=data['title'], description=data['description'], date=data['date'])
    event.create()

    return jsonify(event.to_dict()), 201  # Successful event creation (Status: 201)


normal response:

{
    "id": 1,
    "title": "New Event",
    "description": "A special event",
    "date": "2025-02-10"
}

with this code

if 'title' not in data:
    return {'message': 'Event title is required'}, 400

if I didn't put title, its gonna say

{
    "message": "Event title is required"
}

if there is an error creating event, with this code


updated_event = event.create()
if not updated_event:
    return {'message': 'An error occurred while creating the event. Please try again.'}, 500


its gonna say
 {
    "message": "An error occurred while creating the event. Please try again."
}