Skip to the content.

Map Filter Features

My work on the Map Filter Feature

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. Image A

Image B

Image C

Image d

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 a fetch 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 returns 201 and the new data; missing fields return an error.

  • 6) How do you use db_init, db_restore, and db_backup for tester data creation and recovery?
    db_init creates tables, db_restore reloads saved data, and db_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’s Explore.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 have create(), serialize() (or read()), update(), and delete() 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 the ExploreAPI 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, and delete methods?
    The ExploreAPI 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?
    The post 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 do fetch('/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 parse response.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 successful POST might return 201 and the new record. Missing fields or wrong ID leads to errors like 400 or 404.
  .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

db1

db2

db3