About our project:
- our project aids travelers in picking a vacation spot most suitable for them based the features we provided, including a frontend quiz, a reccommended destinations feature, and an explore feature, and about each landscape and a comemnts feature. All of these features work together to assist travelers into picking the perfect vacation spot based off their wants and needs.
What is my Fetaure?
- My feature consists of an interactable map fiilter
- the user can pick criteria based off of a perfect vacation spot
- one criteria consists of category (historical, cultural, natural, religious, scenic, modern )
- another criteria consists of interest tags (tags abouit the locarion ex:famous landmarks/activities)
- They can view said vacation spot on in integrated world map
Purpose of My feature:
- The goal of my feature is to allow users to input more vacation spots to travel to
- Doing so, users may share their own spots and update spot criteria (tags and categories)
- others may hbe inclined to go to other spots with interesting tags
- Users can click on tags to view location name and tags which interest them
Frontend work:
- I added a new area for users to input a new location
- The user needs to first select the desired location on the map, and a Longitude and Latitude will pop up. I added a functionality where the longitude and latitude automatically get inputted in but can be edited by the user
- Next they need to name the location and assign that named location a value, which is usually same as the location name
- Finally they need to input the category, which there are 6 to to pick from and then assingn any interest tags. It can be literally anything as long as it is seperated by a comma.
- I added a postt feature that adds this location to the map
- GREEN markers are new/added locations, BLUE markers are default locations
Backend work:
- I have a GET request to retrieve all sumbitted locations
- I have a POST request to post new locations and assign filters to that location
- I gave a DELETE request to delete the location
Inputs and outputs
On my frontend page “explore”, users are able to input text into the name, location, and interest tag fields to single out a singular or multiple locations on a world map. The page consists of a mini survey that enables users to type in location data which can be applied to the filters and the map. The User also has the ability to delete and update locations on the map. The delete function completely gets rid of a location and its data whereas the updatae function updates existing locations and its data. This data removal, update, and input is displayed in the frontend map and in the backend database.
from flask import Blueprint, request
from flask_restful import Api, Resource
from flask_cors import CORS
from model.explore import db, Explore, initExplore
# Blueprint + CORS for /api routes
explore_api = Blueprint('explore_api', __name__, url_prefix='/api')
CORS(explore_api)
api = Api(explore_api)
class ExploreAPI(Resource):
"""
A RESTful API for handling Explore resources.
Supports GET (all), POST (create), PUT (update), and DELETE (by id).
"""
def get(self):
"""Retrieve all Explore records from the database."""
try:
explores = Explore.query.all()
# Return a list of dictionaries. Flask-RESTful will auto-JSONify.
return [explore.serialize() for explore in explores], 200
except Exception as e:
return {"error": str(e)}, 500
def post(self):
"""
Create a new Explore entry from JSON payload.
Required JSON fields: 'name', 'value', 'position', 'category', 'interest'.
"""
try:
data = request.get_json()
new_explore = Explore(
name=data['name'],
value=data['value'],
position=data['position'],
category=data['category'],
interest=data['interest']
)
new_explore.create() # Writes to DB
# Return a dict (Flask-RESTful auto-JSONifies); status code 201 indicates "Created"
return new_explore.serialize(), 201
except Exception as e:
return {"error": str(e)}, 400
def put(self):
"""
Update an existing Explore entry by 'id'.
Required JSON fields: 'id', plus any of the fields you want to update:
'name', 'value', 'position', 'category', 'interest'.
"""
try:
data = request.get_json()
explore_id = data.get('id', None)
if explore_id is None:
return {"error": "Missing 'id' in request"}, 400
explore = Explore.query.get(explore_id)
if explore is None:
return {"error": f"Explore with ID {explore_id} not found"}, 404
# Option A: call model's update() with all data
explore.update(data)
# or Option B: manually set fields:
# explore.name = data.get('name', explore.name)
# explore.value = data.get('value', explore.value)
# ... etc. then db.session.commit() ...
return explore.serialize(), 200
except Exception as e:
return {"error": str(e)}, 400
def delete(self):
"""
Delete an Explore entry by 'id'.
Required JSON field: 'id'.
"""
try:
data = request.get_json()
explore_id = data.get('id', None)
if explore_id is None:
return {"error": "Missing 'id' in request"}, 400
explore = Explore.query.get(explore_id)
if explore:
explore.delete()
return {"message": f"Successfully deleted Explore with ID {explore_id}"}, 200
else:
return {"error": f"Explore with ID {explore_id} not found"}, 404
except Exception as e:
return {"error": str(e)}, 400
# OPTIONAL: If you want an endpoint to re-initialize default data (Tokyo, etc.)
@explore_api.route('/explores/init', methods=['POST'])
def explore_init():
"""
Re-create the 'explores' table (if needed) and seed with default data.
You can call this route from Postman: POST /api/explores/init
"""
try:
initExplore()
return {"message": "Explore table initialized with default data"}, 201
except Exception as e:
return {"error": str(e)}, 500
# Register the Resource with the API
api.add_resource(ExploreAPI, '/explores')
from __init__ import app, db
import logging
class Explore(db.Model):
__tablename__ = 'explores'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), nullable=False)
value = db.Column(db.String(255), nullable=False)
position = db.Column(db.String(255), nullable=False)
category = db.Column(db.String(255), nullable=False)
interest = db.Column(db.String(255), nullable=False)
def __init__(self, name, value, position, category, interest):
self.name = name
self.value = value
self.position = position
self.category = category
self.interest = interest
def create(self):
"""Insert this Explore into the database."""
try:
db.session.add(self)
db.session.commit()
except Exception as e:
db.session.rollback()
logging.warning(f"Error creating the map filter: {str(e)}")
return None
return self
def delete(self):
"""Delete this Explore from the database."""
try:
db.session.delete(self)
db.session.commit()
except Exception as e:
db.session.rollback()
logging.warning(f"Error deleting map filter: {str(e)}")
raise e
def serialize(self):
"""Return object data in easily serializable format."""
return {
'id': self.id,
'name': self.name,
'value': self.value,
'position': self.position,
'category': self.category,
'interest': self.interest
}
def read(self):
"""Alias for serialize, if needed by other parts of your code."""
return self.serialize()
def update(self, data):
"""
Update existing fields based on a dict 'data'.
Example: data = {
"name": "...",
"value": "...",
"position": "...",
"category": "...",
"interest": "..."
}
"""
try:
for field in ["name", "value", "position", "category", "interest"]:
if field in data:
setattr(self, field, data[field])
db.session.commit()
return self
except Exception as e:
db.session.rollback()
logging.warning(f"Error updating Explore: {str(e)}")
return None
@staticmethod
def restore(data):
"""
Re-inserts Explore records from a list of dictionaries (typically from backup).
Only inserts records that don't exist already.
"""
try:
for item in data:
existing_explore = Explore.query.filter_by(
name=item['name'],
value=item['value'],
position=item['position'],
category=item['category'],
interest=item['interest']
).first()
if not existing_explore:
explore = Explore(
name=item['name'],
value=item['value'],
position=item['position'],
category=item['category'],
interest=item['interest']
)
db.session.add(explore)
db.session.commit()
return True
except Exception as e:
db.session.rollback()
logging.warning(f"Error restoring explores: {str(e)}")
return False
def initExplore():
"""
Creates the 'explores' table (if it doesn't exist) and populates it with default data.
Used for initial setup or re-initialization.
"""
db.create_all()
# Only add default data if the table is empty
if not Explore.query.first():
explores = [
Explore(name="Tokyo", value="tokyo", position="35.6895, 139.6917", category="Modern",
interest="TOKYO:, technology, anime, Cherry Blossom, Temples, Shibuya"),
Explore(name="Mumbai", value="mumbai", position="19.0760, 72.8777", category="Religious",
interest="MUMBAI:, bollywood, curry, Ganesh, Beaches, Elephants, Street Food, Taj Mahal"),
Explore(name="Cairo", value="cairo", position="30.0444, 31.2357", category="historical",
interest="CAIRO:, pyramids, Egypt, Sphinx, Nile River, mosques"),
Explore(name="Lagos", value="lagos", position="6.5244, 3.3792", category="Scenic",
interest="LAGOS:, afrobeat, Beaches, Nike Art gallery, Jazz, Nightlife, Makoko"),
Explore(name="London", value="london", position="51.5074, -0.1278", category="historical",
interest="LONDON:, theatre, Buckingham Palace, Big Ben, King of England, Harry Potter, Tea"),
Explore(name="Paris", value="paris", position="48.8566, 2.3522", category="cultural",
interest="PARIS:, fashion, Eiffel Tower, Louvre Museum, France, Baguette, Notre Dame Cathedral"),
Explore(name="New York City", value="new_york_city", position="40.7128, -74.0060", category="Modern",
interest="NEW YORK CITY:, Empire State, Times Square, Central Park, Broadway, Statue of Liberty, Wall Street, 9/11 memorial, Brooklyn Bridge, pizza, hot dogsc"),
Explore(name="Mexico City", value="mexico_city", position="19.4326, -99.1332", category="cultural",
interest="MEXICO CITY:, Hispanic, Volcanic horizons, Day of the dead, Mariachi, tacos, burritos, Lucha Libre"),
Explore(name="Sao Paulo", value="sao_paulo", position="-23.5505, -46.6333", category="Natural",
interest="SAO PAULO:, Neon parties, Samba Beats, Soccer, Urban Jungles, party, Carnival, Brazil, Football, Street Art, Paulista Avenue, Beco do Batman"),
Explore(name="Buenos Aires", value="buenos_aires", position="-34.6037, -58.3816", category="historical",
interest="BUENOS AIRES:, football, Argentina, Steak, La Boca Neighborhood, Tango, Cafe Culture, Palermo Park")
]
for explore in explores:
explore.create()
-
1) What is the purpose of your group’s program?
Our program stores data about different cities so people can explore or learn about them. … -
2) What is the purpose of your individual feature(s)?
I built the part that lets users add and delete city data. -
3) How do you handle input/output (demo ways to input to your full stack feature)?
Users type city details in a form, and the server returns JSON confirming success or errors. -
4) How do you show an API request and response in the frontend (live demo)?
We click a button that runs afetch
call to our API. The JSON response appears in the webpage. -
5) How do you show raw API requests and RESTful responses in Postman?
We send JSON in a POST request to/api/explores
. A valid request returns201
and the new data; missing fields return an error. -
6) How do you use
db_init
,db_restore
, anddb_backup
for tester data creation and recovery?
db_init
creates tables,db_restore
reloads saved data, anddb_backup
saves current data for safety. -
7) How do you use lists, dictionaries, and the database in your code?
A query returns a list of rows. Each row is turned into a dictionary (like{"id": 1, "name": "Tokyo"}
) when we serialize it. -
8) How do you format JSON response data from the API into the DOM?
We loop over the JSON objects in JavaScript and build HTML elements to display each field.
function fetchDataFromBackend() {
fetch('http://127.0.0.1:8887/api/explores')
.then(response => {
if (!response.ok) {
throw new Error('Error fetching data from /api/explores');
}
return response.json();
- 9) How do you query the database and get a Python list of rows?
We use SQLAlchemy’sExplore.query.all()
to get a list of rows, then convert each row to a dictionary.
@staticmethod
def restore(data):
"""
Re-inserts Explore records from a list of dictionaries (typically from backup).
Only inserts records that don't exist already.
"""
try:
for item in data:
existing_explore = Explore.query.filter_by(
name=item['name'],
value=item['value'],
position=item['position'],
category=item['category'],
interest=item['interest']
).first()
if not existing_explore:
explore = Explore(
name=item['name'],
value=item['value'],
position=item['position'],
category=item['category'],
interest=item['interest']
)
db.session.add(explore)
db.session.commit()
return True
except Exception as e:
db.session.rollback()
logging.warning(f"Error restoring explores: {str(e)}")
return False
- 10) What methods did you create in your class to handle columns (create, read, update, delete)?
We havecreate()
,serialize()
(orread()
),update()
, anddelete()
which manage rows in the database.
from __init__ import app, db
import logging
class Explore(db.Model):
__tablename__ = 'explores'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), nullable=False)
value = db.Column(db.String(255), nullable=False)
position = db.Column(db.String(255), nullable=False)
category = db.Column(db.String(255), nullable=False)
interest = db.Column(db.String(255), nullable=False)
def __init__(self, name, value, position, category, interest):
self.name = name
self.value = value
self.position = position
self.category = category
self.interest = interest
- 11) What is an algorithmic code block that handles a request?
Each method in theExploreAPI
reads input, interacts with the database, and returns a JSON response.
try:
data = request.get_json()
new_explore = Explore(
name=data['name'],
value=data['value'],
position=data['position'],
category=data['category'],
interest=data['interest']
)
new_explore.create() # Writes to DB
# Return a dict (Flask-RESTful auto-JSONifies); status code 201 indicates "Created"
return new_explore.serialize(), 201
except Exception as e:
return {"error": str(e)}, 400
- 12) How does your API class perform
get
,post
,put
, anddelete
methods?
TheExploreAPI
has four methods named for each HTTP verb. Each one deals with data differently.
def get(self):
"""Retrieve all Explore records from the database."""
try:
explores = Explore.query.all()
# Return a list of dictionaries. Flask-RESTful will auto-JSONify.
return [explore.serialize() for explore in explores], 200
except Exception as e:
return {"error": str(e)}, 500
def post(self):
"""
Create a new Explore entry from JSON payload.
Required JSON fields: 'name', 'value', 'position', 'category', 'interest'.
"""
try:
data = request.get_json()
new_explore = Explore(
name=data['name'],
value=data['value'],
position=data['position'],
category=data['category'],
interest=data['interest']
)
new_explore.create() # Writes to DB
# Return a dict (Flask-RESTful auto-JSONifies); status code 201 indicates "Created"
return new_explore.serialize(), 201
except Exception as e:
return {"error": str(e)}, 400
def put(self):
"""
Update an existing Explore entry by 'id'.
Required JSON fields: 'id', plus any of the fields you want to update:
'name', 'value', 'position', 'category', 'interest'.
"""
try:
data = request.get_json()
explore_id = data.get('id', None)
if explore_id is None:
return {"error": "Missing 'id' in request"}, 400
explore = Explore.query.get(explore_id)
if explore is None:
return {"error": f"Explore with ID {explore_id} not found"}, 404
# Option A: call model's update() with all data
explore.update(data)
# or Option B: manually set fields:
# explore.name = data.get('name', explore.name)
# explore.value = data.get('value', explore.value)
# ... etc. then db.session.commit() ...
return explore.serialize(), 200
except Exception as e:
return {"error": str(e)}, 400
def delete(self):
"""
Delete an Explore entry by 'id'.
Required JSON field: 'id'.
"""
try:
data = request.get_json()
explore_id = data.get('id', None)
if explore_id is None:
return {"error": "Missing 'id' in request"}, 400
explore = Explore.query.get(explore_id)
if explore:
explore.delete()
return {"message": f"Successfully deleted Explore with ID {explore_id}"}, 200
else:
return {"error": f"Explore with ID {explore_id} not found"}, 404
except Exception as e:
return {"error": str(e)}, 400
- 13) Can you give an example of a method/procedure that uses sequencing, selection, and iteration?
Thepost
method: It reads JSON (sequence), checks for missing fields (selection), and loops over any data if needed (iteration).
def restore(data):
"""
Re-inserts Explore records from a list of dictionaries (typically from backup).
Only inserts records that don't exist already.
"""
try:
for item in data:
existing_explore = Explore.query.filter_by(
name=item['name'],
value=item['value'],
position=item['position'],
category=item['category'],
interest=item['interest']
).first()
if not existing_explore:
explore = Explore(
name=item['name'],
value=item['value'],
position=item['position'],
category=item['category'],
interest=item['interest']
)
db.session.add(explore)
db.session.commit()
return True
except Exception as e:
db.session.rollback()
logging.warning(f"Error restoring explores: {str(e)}")
return False
- 14) What are the parameters (body of request) and return type (
jsonify
) of a function?
We pass data in JSON (like{ "name": "Tokyo" }
). The function returns a dictionary that Flask turns into JSON automatically.
def get(self):
"""Retrieve all Explore records from the database."""
try:
explores = Explore.query.all()
# Return a list of dictionaries. Flask-RESTful will auto-JSONify.
return [explore.serialize() for explore in explores], 200
except Exception as e:
return {"error": str(e)}, 500
-
15) Show the definition of the code block that makes a request (Call to Algorithm).
On the frontend, we dofetch('/api/explores', { method: 'POST', body: JSON... })
. This is the main call. -
16) How do you discuss the call/request to the method with Algorithm (fetch to endpoint)?
We specify the URL, HTTP method, headers, and body. Then we wait for the JSON reply.
fetch('http://127.0.0.1:8887/api/explores', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(requestBody)
- 17) How do you handle the return/response in fetch and manage the data?
If the response is OK, we parseresponse.json()
and display it. If not, we show an error message.
if (!response.ok) {
throw new Error('Error adding new explore location');
}
return response.json();
})
.then(data => {
alert(`New location '${data.name}' added successfully!`);
fetchDataFromBackend();
clearForm();
})
.catch(error => {
console.error('Error adding new explore:', error);
alert('Failed to add the new location. Check console for details.');
});
}
- 18) How does changing data or method trigger different responses (normal vs. error conditions)?
A successfulPOST
might return201
and the new record. Missing fields or wrong ID leads to errors like400
or404
.
.then(response => {
if (!response.ok) {
throw new Error('Error adding new explore location');
}
return response.json();
db init/ Db backup/ the backup table view
How DB backup works:
It runs restore_data_command, which is defined in main.py This command contains a restore command for each table. Each model file has defines their restore function, which is a static method and goes through the data checks if a location with the given value already exists in the database using a query Then, if the location exsists, it updates its data, and if it doesn’t it create a new Location instance using the provided data
Here are some images that sow how to run the functions/ the tables of the images