Skip to the content.

Sprint 5 Reflection

A blog about full stack development

Intro Requests

Site Purpose

“Empowering growth, celebrating achievements, connecting journeys, inspiring brighter futures”

Empowering platform: Focused on helping individuals overcome challenges and celebrate personal growth.

Profile achievements: Users can highlight their progress and milestones on their profiles.

Anonymous chat feature: Allows users to connect with others who have faced similar struggles in a safe, private, and supportive environment.

Hobbies log: Users can track and share their interests, encouraging exploration of new passions and creative pursuits.

Step tracker: Promotes healthy habits by helping users monitor their physical activity and work toward fitness goals.

Bucket list feature: Enables users to set and document aspirations, providing inspiration and accountability for pursuing dreams.

Facts log: Offers a personalized space to have facts about famous people or people they look up to, uplifting users and encouraging them to make those facts a reality about themselves.

Dynamic space for connection and growth: Combining these features to create a platform for personal development and celebration.

Individual Coolfacts Feature Purpose My feature is space to view facts, which lets users add, update, delete, and view the facts they have inputed through the CRUD method as a way to express cool facts they may have about famous people. Users can then use these cool facts as motivation to make those facts true about themselves. They can see amazing facts that great people have done and can strive to become like these people, posting their facts in the coolfacts page, letting everyone know that they got inspiration from this site's facts page.

List Requests

const data = await response.json();
const coolFactsList = document.getElementById('cool-facts-list');
coolFactsList.innerHTML = "";
data.cool_facts.forEach(coolFact => {
    const listItem = document.createElement('li');
    listItem.textContent = coolFact;
    coolFactsList.appendChild(listItem);
});


const data = await response.json(); Parses the JSON response from the API into a JavaScript object (data).
const coolFactsList = document.getElementById(‘cool-facts-list’);
Gets the element where the cool facts will be displayed.
coolFactsList.innerHTML = “”;
Clears any existing list items from the list.
data.cool_facts.forEach(coolFact => { … });
Loops through the array of cool facts.
const listItem = document.createElement(‘li’);
Creates a new li element for each cool fact.
listItem.textContent = coolFact;
Sets the text of the li to the cool fact.
coolFactsList.appendChild(listItem);
Adds the new li to the ul or ol in the DOM.
Results in cool facts being displayed as a list in the browser.</p>

Use of Lists and Dictionaries, Code Descriptions

Lists

coolfacts = CoolFact.query.filter_by(category=category).all()

CoolFact refers to the CoolFact class in the model file, mapping the cool_facts table to the database.

.query


is a query object provided by SQLAlchemy, a third-party library, allowing interaction with the database through queries such as retrieving, filtering, or sorting rows.


.filter_by(category=category)


is an SQLAlchemy method that filters results. It generates an SQL WHERE clause, filtering the cool_facts table to select a cool fact based on a category. The first category refers to the database column, and the second category is the variable specifying which category the cool fact belongs to.


.all()


is an SQLAlchemy method that executes the query and returns all matching rows as a Python list. Each list item contains the values from each column, such as id, name, and category.

Dictionaries

Create:

def create(self):
    try: 
        db.session.add(self)
        db.session.commit()
        return True
    except IntegrityError: db.session.rollback()
    return False 

Adds a row(list of data) as a coolfact with identifiers for each column

Read

def read(self):
    return {"id": self.id, "name": self.name, "category": self.category}

Returns dictionary representation of coolfacts(columns as keys)

Update

def update(self):
    try:
        db.session.commit()
        return True
    except IntegrityError:
        db.session.rollback()
        return False

Updates column values for an existing row.

Delete

def delete(self):
    try:
        db.session.delete(self)
        db.session.commit()
        return True
    except IntegrityError:
        db.session.rollback()
        return False

Deletes a row from the table.




These four operations are CRUD operations, allowing for addition, retrieval, updating, and deletion of specific rows and columns(dictionaries) in the database.

from flask import Blueprint, request, jsonify, current_app, Response, g
from flask_restful import Api, Resource  # Used for REST API building
from __init__ import app  # Ensure __init__.py initializes your Flask app
from model.coolfacts import CoolFacts
from api.jwt_authorize import token_required
# Blueprint for the API
coolfacts_api = Blueprint('coolfacts_api', __name__, url_prefix='/api')
api = Api(coolfacts_api)  # Attach Flask-RESTful API to the Blueprint
class CoolFactsAPI:
    """
    Define the API CRUD endpoints for the Post model.
    There are four operations that correspond to common HTTP methods:
    - post: create a new post
    - get: read posts
    - put: update a post
    - delete: delete a post
    """
    class _CRUD(Resource):
        
        @token_required()
        def post(self):
            # Obtain the request data sent by the RESTful client API
            data = request.get_json()
            # Create a new post object using the data from the request
            post = CoolFacts(age=data['age'], coolfacts=data['coolfacts'])
            # Save the post object using the Object Relational Mapper (ORM) method defined in the model
            post.create()
            # Return response to the client in JSON format, converting Python dictionaries to JSON format
            return jsonify(post.read())
        
        @token_required()
        def put(self):
            try:
                # Obtain the request data
                data = request.get_json()
        
                # Check if 'id' is in the data
                if 'id' not in data:
                    return jsonify({"error": "ID is required"}), 400
        
                # Find the current post from the database table(s)
                post = CoolFacts.query.get(data['id'])
                if post is None:
                    return {'message': 'Coolfact not found'}, 404
                # Check if the post exists
                
                #if not post:
                #    return jsonify({"error": "CoolFact not found"}), 404
        
                # Update the post
                
                post.age = data['age']
                
                post.coolfacts = data['coolfacts']
        
                # Save the post
                post.update()
        
                # Return response
                return jsonify(post.read())
            except Exception as e:
                # Return an error message in case of failure
                return jsonify({"error": str(e)}), 500
        @token_required()
        def get(self):
            try:
                # Query all entries in the BinaryHistory table
                entries = CoolFacts.query.all()
                # Convert the entries to a list of dictionaries
                results = [entry.read() for entry in entries]
                # Return the list of results in JSON format
                return jsonify(results)
            except Exception as e:
                # Return an error message in case of failure
                return jsonify({"error": str(e)}), 500
            
        @token_required()
        def delete(self):
            # Obtain the request data
            data = request.get_json()
            # Find the current post from the database table(s)
            post = CoolFacts.query.get(data['id'])
            # Delete the post using the ORM method defined in the model
            post.delete()
            # Return response
            return jsonify({"message": "Post deleted"})
    """
    Map the _CRUD class to the API endpoints for /post.
    - The API resource class inherits from flask_restful.Resource.
    - The _CRUD class defines the HTTP methods for the API.
    """
    api.add_resource(_CRUD, '/coolfacts')
if __name__ == '__main__':
    app.run(debug=True)

Requests

1. GET: Fetches hobbies filtered by category and returns them as a JSON list.
2. POST: Adds a new fact to the database, requiring name and category in the request body.
3. PUT: Updates an existing fact in the database, identified by old_name, and modifies its name and category.
4. DELETE: Deletes a fact from the database, identified by its name and category.



This is the API code with the GET, POST, PUT, and DELETE requests to work with the hobbies list based on each category. It allows for hobbies to be retrieved, added, updated, and deleted from each separate categorical list.

GET Method

def get(self): category = request.args.get('category', 'general') # Sequencing coolfacts = CoolFacts.query.filter_by(category=category).all() # Sequencing if coolfacts: # Selection return jsonify({"category": category, "coolfacts": [coolfacts.name for coolfact in coolfacts]}) # Iteration else: return jsonify({"message": "Category not found"}), 404 # Selection

Sequencing: The first two lines of code perform sequencing because they execute in order. The first line retrieves the category parameter from the request, and the second line fetches the list of coolfacts from the database based on the retrieved category parameter.



Selection: The if statement demonstrates selection, as it chooses between different JSON messages to return. If there is a coolfact in the coolfacts list, it returns a JSON message containing the name and category of the coolfact. Otherwise, it returns a 404 not found error, indicating that no matching category was found.



Iteration: The line right below if coolfacts is an iteration statement, as it loops through coolfact.name for coolfact in coolfacts to iterate over the coolfacts list multiple times and extract the name of each coolfact in the JSON response.

Parameters and Return Type

Parameters: request.args.get('category', 'general') retrieves the query parameter category from the request url /api/coolfacts?category=.... If a parameter isn't provided, it defaults to the general category. request.get_json() is used for POST, PUT, and DELETE methods, and it retrieves the body of an HTTP request expected to be in JSON. This JSON comes from user input. Return Type: jsonify() is used in all methods in order to take a Python dictionary and return it as a JSON response that can be sent to the user.

Call to Algorithm Request

<script type="module">
    const pythonURI = 'http://127.0.0.1:8887'; // Adjust the port if necessary
    const fetchOptions = {
        headers: {
            'Content-Type': 'application/json'
        },
        credentials: 'include' // Include credentials in fetch requests
    };
    async function fetchCoolFacts() {
        try {
            const response = await fetch(`${pythonURI}/api/coolfacts`, {
                ...fetchOptions,
                method: 'GET'
            });
            if (!response.ok) {
                throw new Error('Failed to fetch cool facts: ' + response.statusText);
            }
            const data = await response.json();
            const coolFactsList = document.getElementById('coolfacts-list');
            coolFactsList.innerHTML = "";
            data.forEach(fact => {
                const listItem = document.createElement('li');
                listItem.style.display = 'flex';
                listItem.style.alignItems = 'center';
                listItem.style.justifyContent = 'space-between';
                const factText = document.createElement('span');
                factText.textContent = `${fact.age}: ${fact.coolfacts}`;
                const updateButton = document.createElement('button');
                updateButton.textContent = 'Update';
                updateButton.style.marginLeft = '10px';
                updateButton.style.padding = '2px 5px';
                updateButton.onclick = () => promptUpdateCoolFact(fact.id, fact.age, fact.coolfacts);
                const deleteButton = document.createElement('button');
                deleteButton.textContent = 'Delete';
                deleteButton.style.marginLeft = '10px';
                deleteButton.style.padding = '2px 5px';
                deleteButton.onclick = () => deleteCoolFact(fact.id);
                listItem.appendChild(factText);
                listItem.appendChild(updateButton);
                listItem.appendChild(deleteButton);
                coolFactsList.appendChild(listItem);
            });
        } catch (error) {
            console.error('Error fetching cool facts:', error);
        }
    }
    async function addCoolFact() {
        const age = document.getElementById('new-fact-age').value;
        const coolfacts = document.getElementById('new-fact-text').value;
        try {
            const response = await fetch(`${pythonURI}/api/coolfacts`, {
                ...fetchOptions,
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ age, coolfacts })
            });
            if (!response.ok) {
                throw new Error('Failed to add cool fact: ' + response.statusText);
            }
            alert('Cool fact added successfully!');
            document.getElementById('new-fact-age').value = ''; // Clear input
            document.getElementById('new-fact-text').value = ''; // Clear input
            fetchCoolFacts(); // Refresh cool facts list
        } catch (error) {
            console.error('Error adding cool fact:', error);
            alert('Error adding cool fact: ' + error.message);
        }
    }
    async function promptUpdateCoolFact(id, age, coolfacts) {
        const updatedAge = prompt('Enter new age:', age);
        const updatedCoolFact = prompt('Enter new cool fact:', coolfacts);
        if (updatedAge && updatedCoolFact) {
            try {
                const response = await fetch(`${pythonURI}/api/coolfacts`, {
                    ...fetchOptions,
                    method: 'PUT',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify({ id, age: updatedAge, coolfacts: updatedCoolFact })
                });
                if (!response.ok) {
                    throw new Error('Failed to update cool fact: ' + response.statusText);
                }
                alert('Cool fact updated successfully!');
                fetchCoolFacts(); // Refresh cool facts list
            } catch (error) {
                console.error('Error updating cool fact:', error);
                alert('Error updating cool fact: ' + error.message);
            }
        }
    }
    async function deleteCoolFact(id) {
        try {
            const response = await fetch(`${pythonURI}/api/coolfacts`, {
                ...fetchOptions,
                method: 'DELETE',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ id })
            });
            if (!response.ok) {
                throw new Error('Failed to delete cool fact: ' + response.statusText);
            }
            alert('Cool fact deleted successfully!');
            fetchCoolFacts(); // Refresh cool facts list
        } catch (error) {
            console.error('Error deleting cool fact:', error);
            alert('Error deleting cool fact: ' + error.message);
        }
    }
    document.getElementById('add-fact-btn').addEventListener('click', addCoolFact);
    fetchCoolFacts();
</script>

<style>
/* General Styles */
body {
    font-family: Arial, sans-serif;
    background-color: #121212;
    color: #fff;
    margin: 0;
    padding: 0;
  }
  h1, h2 {
    text-align: center;
  }
  .container {
    display: flex;
    justify-content: center;
    width: 100%;
    max-width: 1200px;
    padding: 20px;
    box-sizing: border-box;
  }
  .form-container {
    display: flex;
    flex-direction: column;
    max-width: 800px;
    width: 100%;
    background-color: #2C3E50;
    padding: 20px;
    border-radius: 10px;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
    color: #ECF0F1;
  }
  .form-container label, .form-container input, .form-container textarea, .form-container select, .form-container button {
    margin-bottom: 10px;
    padding: 10px;
    border-radius: 5px;
    border: none;
    width: 100%;
  }
  .form-container button {
    background-color: #34495E;
    color: #ECF0F1;
    cursor: pointer;
  }
  .form-container button:hover {
    background-color: #1A252F;
  }
  #coolfacts-list li {
    display: flex;
    align-items: center;
    justify-content: space-between;
    background-color: #34495E;
    padding: 10px;
    margin-bottom: 5px;
    border-radius: 5px;
  }
  #coolfacts-list button {
    background-color: #E74C3C;
    color: #ECF0F1;
    border: none;
    padding: 2px 5px;
    border-radius: 5px;
    cursor: pointer;
    font-size: 12px; /* Make the button smaller */
    width: 60px; /* Make the button smaller horizontally */
    margin-left: 0; /* Move the button closer */
  }
  #coolfacts-list button.update-btn {
    background-color: #3498DB;
    margin-left: 10px; /* Add some space between buttons */
  }
  #coolfacts-list button.update-btn:hover {
    background-color: #2980B9;
  }
  #coolfacts-list span {
    flex-grow: 1; /* Ensure the text takes up available space */
  }
  #coolfacts-list button:hover {
    background-color: #C0392B;
  }
  /* Sidebar */
  .sidebar {
    position: fixed;
    top: 0;
    left: 0;
    width: 180px;
    height: 100%;
    background-color: #121212 !important;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding-top: 20px;
    color: white;
    border-right: 1px solid gray;
  }
  .sidebar-btn {
    background-color: #121212;
    color: white !important;
    border: 2px solid cyan;
    margin: 10px 0;
    padding: 10px;
    border-radius: 8px;
    font-size: 16px;
    width: 160px;
    text-align: center;
    cursor: pointer;
    text-decoration: none;
  }
  .bottom-btn {
    margin-top: auto; /* Pushes the Terms button to the bottom */
  }
  .sidebar-btn:hover {
    background-color: #1E1E1E;
    transform: scale(1.05);
  }
  .sidebar-btn.active {
    background-color: #333;
    font-weight: bold;
  }
</style>  

Call/Request to the Method (Algorithm)

When a user interacts with the interface (e.g., changing the category, adding, updating, or deleting a cool fact), the JavaScript code sends an HTTP request to a Flask backend API.

fetchCoolFacts() function (GET request):

The function fetches cool facts by calling the endpoint: GET /api/coolfact?category=selectedCategory.

Algorithm:

Get the selected category value from the dropdown.
Build the GET request URL using that category.
Send the request to the backend API using fetch.
Handle the response when the request succeeds or fails.

addCoolFact() function (POST request):

The user provides a new cool fact, then clicks a button to add it. The function sends the new cool fact data to the backend using a POST request to the endpoint: POST /api/coolfacts.

Algorithm

Retrieve the new cool fact's content and category from the input fields.
Prepare the request body as a JSON object ({ name: coolFactName, category: category }).
Send the POST request to the backend API.
If the request is successful, alert the user and refresh the cool facts list.

updateCoolFact() function (PUT request):

The user provides the name of the cool fact to be updated and the new content. The function sends the update data to the backend using a PUT request to the endpoint: PUT /api/coolfact.

Algorithm

Retrieve the old cool fact content, new content, and category from the input fields.
Prepare the request body as a JSON object ({ old_name, name, category }).
Send the PUT request to the backend API.
If successful, alert the user and refresh the cool facts list.

deleteCoolFact() function (DELETE request):

The user provides the cool fact content and category to delete.
The function sends the deletion data to the backend using a DELETE request to the endpoint: DELETE /api/coolfact.

Algorithm:

Retrieve the cool fact content and category from the input fields.
Prepare the request body as a JSON object ({ name, category }).
Send the DELETE request to the backend API.
If successful, alert the user and refresh the cool facts list.

2. Return/Response from the Method (Algorithm) and Data Handling

After each request is made, the API responds with data, and the front-end handles it appropriately.

fetchCoolFacts() (GET):

Return Type: The response will be a JSON object with a list of cool_facts from the requested category, e.g.,
{ "category": "science", "cool_facts": ["The Sun is a star", "Water expands when frozen"] }.
Handling Data: The JSON response is parsed, and the cool_facts are extracted and displayed as list items in the DOM.

addCoolFact() (POST):

Return Type: If successful, the response is a JSON object like
{ "message": "Cool fact created", "cool_fact": "Bananas are berries", "category": "botany" }.
Handling Data: The success message is displayed as an alert, and the input fields are cleared. The cool_facts list is then refreshed by calling fetchCoolFacts().

updateCoolFact() (PUT):

Return Type: If successful, the response is a JSON object like
{ "message": "Cool fact updated", "old_fact": "Bananas are berries", "new_fact": "Strawberries are not berries" }.
Handling Data: The success message is displayed as an alert, and the input fields are cleared. The cool_facts list is then refreshed by calling fetchCoolFacts().

deleteCoolFact() (DELETE):

Return Type: If successful, the response is a JSON object like
{ "message": "Cool fact deleted", "fact": "Strawberries are not berries" }.
Handling Data: The success message is displayed as an alert, and the input fields are cleared. The cool_facts list is then refreshed by calling fetchCoolFacts().

3. Changing Data or Method Triggers Different Responses (Normal and Error Conditions)

Normal Conditions:

When the backend API processes a valid request successfully, the response is a success message with the relevant data.

Example:

  • Adding a cool_fact: { "message": "Cool fact created", "cool_fact": "Bananas are berries", "category": "botany" }.
  • Updating a cool_fact: { "message": "Cool fact updated", "old_fact": "Bananas are berries", "new_fact": "Strawberries are not berries" }.
  • Deleting a cool_fact: { "message": "Cool fact deleted", "fact": "Strawberries are not berries" }.

In these cases, the response is handled successfully, and the data is used to update the UI (e.g., refreshing the cool_facts list).

Error Conditions:

If there is an issue with the request (e.g., missing data, invalid category), the API will return a failure message with an error status.

Example:

  • Invalid cool_fact name: { "message": "Cool fact name and category are required" }.
  • Invalid category: { "message": "Category not found" }.

In these cases, the error message is displayed to the user via an alert, and the UI remains unchanged.

Example of Changing Data/Method Triggering Different Responses:

1. Normal Condition:

A user adds a cool_fact, and the backend returns
{ "message": "Cool fact created", "cool_fact": "Bananas are berries", "category": "botany" }.
The cool_fact is added successfully, and the cool_facts list is refreshed.

2. Error Condition:

A user tries to add a cool_fact without a name or category.
The backend returns { "message": "Cool fact name and category are required" }.
The user is alerted with the error message, and no changes are made to the cool_facts list.