[go: up one dir, main page]

0% found this document useful (0 votes)
12 views28 pages

Project Implementation Step-By-Step Guide

Uploaded by

dnyanesh.agale
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
12 views28 pages

Project Implementation Step-By-Step Guide

Uploaded by

dnyanesh.agale
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 28

Building a Full-Stack Food Analyzer: A

Step-by-Step Guide with Python, Flask,


and JavaScript
Part I: Project Foundation and Environment Setup
This initial phase of the project is dedicated to establishing a robust and professional foundation.
Before any code is written, it is crucial to understand the architectural design of the application,
configure a clean and isolated development environment, and create a well-organized directory
structure. These preliminary steps are not mere formalities; they are fundamental practices that
ensure the project is scalable, maintainable, and aligned with modern software engineering
standards. By investing time in this foundational setup, developers can prevent common pitfalls
and create a workflow that is both efficient and effective.

Section 1.1: Architecting the Application: The "Why" Before the


"How"
The application will be constructed using a decoupled, three-tier architecture. This design
pattern intentionally separates the major components of the system—the frontend (user
interface), the backend (server-side logic), and the external data source—into distinct,
independently operating layers. This separation is a cornerstone of modern web development,
offering significant advantages in terms of flexibility, scalability, and collaborative development.
The flow of information in this architecture can be visualized as follows:
1.​ Frontend (The Presentation Layer): This is the client-side application that runs in the
user's web browser. It is built using HTML, CSS, and JavaScript. Its sole responsibilities
are to present the user interface, capture user input (such as a product barcode), and
communicate with the backend via HTTP requests. It has no direct knowledge of the
backend's internal logic or how data is ultimately sourced.
2.​ Backend (The Logic Layer): This is the server-side application, which will be built using
the Python Flask framework. It acts as an intermediary. It exposes a set of well-defined
API endpoints that the frontend can call. When it receives a request, it processes the
request, performs the necessary business logic (such as fetching and analyzing data),
and sends a structured response back to the frontend, typically in JSON format.
3.​ External Data Source (The Data Layer): In this project, the data layer is the Open Food
Facts REST API. Our backend communicates with this external service to retrieve
detailed food product information. The backend is responsible for abstracting this
interaction, meaning the frontend does not need to know or care where the food data
comes from; it only needs to communicate with our backend.
This decoupled approach contrasts with more traditional, monolithic frameworks where the
backend is also responsible for rendering the HTML that is sent to the browser. While monolithic
architectures can be effective for certain types of standard applications, the decoupled model
provides superior modularity. This separation of concerns allows frontend and backend
development to proceed in parallel. A frontend team can build the user interface as long as they
know the structure of the data the backend will provide, and a backend team can build the logic
without being concerned with the specifics of the UI's presentation.
The communication bridge between these layers is the Application Programming Interface
(API). The API serves as a formal "contract" that defines how the frontend and backend will
interact. It specifies the available endpoints (URLs), the expected request formats, and the
structure of the data that will be returned. This contract-based approach is fundamental to
building scalable and maintainable systems, as it allows either the frontend or the backend to be
updated, replaced, or scaled independently, as long as the contract of the API is honored. This
project will therefore provide practical experience in designing and consuming a simple REST
API, a critical skill for any modern web developer.

Section 1.2: Establishing the Development Environment


A clean, reproducible development environment is a prerequisite for any professional software
project. It ensures that the code runs consistently across different machines and that project
dependencies do not conflict with other projects or system-level packages. The primary tool for
achieving this in the Python ecosystem is the virtual environment.
Step 1: Verify Python Installation Before proceeding, it is necessary to ensure that a recent
version of Python (Python 3.6 or higher is recommended) is installed on the system. This can be
verified by opening a terminal or command prompt and executing the following command:
python3 --version​

If Python is installed, this command will output the version number. If it is not installed, it must be
downloaded and installed from the official Python website. The installation process is generally
straightforward on most operating systems.
Step 2: Create the Project Root Directory All project files will be contained within a single root
directory. Create this directory and navigate into it:
mkdir food-analyzer​
cd food-analyzer​

Step 3: Create and Activate a Python Virtual Environment A virtual environment is an


isolated directory that contains a specific version of Python and its own set of installed
packages. This prevents dependencies for this project (like Flask) from being installed globally,
which could cause version conflicts with other projects.
To create a virtual environment named venv within the food-analyzer directory, run the following
command:
python3 -m venv venv​

This command uses Python's built-in venv module to create the venv folder. This folder contains
a copy of the Python interpreter and a location for installing project-specific libraries.
Once created, the virtual environment must be activated. The activation command differs slightly
between operating systems :
●​ On macOS and Linux:​
source venv/bin/activate​

●​ On Windows (Command Prompt):​


venv\Scripts\activate.bat​
●​ On Windows (PowerShell):​
venv\Scripts\Activate.ps1​

After activation, the command prompt will typically be prefixed with (venv), indicating that the
virtual environment is active. Any Python packages installed from this point forward will be
placed inside the venv directory, completely isolated from the system's global Python
environment.
The value of this approach extends beyond simple isolation. When combined with a
dependency manifest file (which will be introduced later as requirements.txt), the virtual
environment becomes a blueprint for a reproducible build. This means that any other developer,
or any deployment server, can create an identical environment by installing the exact same
versions of the required packages. This practice is fundamental to collaborative development
and reliable deployment, as it effectively eliminates the common "it works on my machine" class
of problems by making the environment itself a version-controlled and reproducible artifact of
the project.

Section 1.3: Initializing the Project Directory Structure


A well-organized directory structure is critical for project clarity and maintainability. It separates
code by concern, making it easier to locate files and understand the overall architecture. The
following structure will be created to enforce a clean separation between the backend API and
the frontend user interface from the outset.
From within the root food-analyzer directory, execute the following commands to create the
complete folder and file structure:
# Create the main backend and frontend directories​
mkdir backend frontend​

# Create the backend application package structure​
mkdir -p backend/app​
touch backend/app/__init__.py​
touch backend/app/routes.py​
touch backend/app/services.py​
touch backend/app/analysis.py​
touch backend/run.py​

# Create the frontend files​
touch frontend/index.html​
touch frontend/style.css​
touch frontend/app.js​

# Create a.gitignore file​
touch.gitignore​

The resulting project structure will be as follows:


food-analyzer/​
├── backend/​
│ ├── app/​
│ │ ├── __init__.py # Initializes the 'app' folder as a
Python package and contains the application factory.​
│ │ ├── routes.py # Defines the API endpoints (URL routes).​
│ │ ├── services.py # Handles communication with the external
Open Food Facts API.​
│ │ └── analysis.py # Contains the business logic for
nutritional analysis.​
│ └── run.py # A script to start the Flask development
server.​
├── frontend/​
│ ├── index.html # The main HTML file for the user
interface.​
│ ├── style.css # The CSS file for styling the
application.​
│ └── app.js # The JavaScript file for handling user
interaction and API calls.​
├── venv/ # The Python virtual environment
directory.​
└──.gitignore # Specifies files and directories to be
ignored by version control (Git).​

This structure is a deliberate choice, drawing from best practices for scalable Flask applications
and standard web development. The backend/app directory is structured as a Python package,
which facilitates modular design and testing. The frontend directory keeps all client-side assets
neatly separated.
Finally, the .gitignore file should be populated to prevent version control from tracking
unnecessary or sensitive files. A good starting point for a Python project is:
#.gitignore​

# Virtual Environment​
venv/​

# Python cache​
__pycache__/​
*.pyc​

# IDE / Editor specific files​
.vscode/​
.idea/​

This configuration tells Git to ignore the virtual environment directory, Python bytecode cache
files, and common editor-specific setting folders, keeping the repository clean and focused on
the source code.

Part II: Engineering the Backend API with Flask


This part focuses on the construction of the server-side application using Flask, a lightweight
and flexible Python web framework. Unlike more opinionated, full-stack frameworks like Django
which provide many built-in tools but less flexibility, Flask offers a minimal core, allowing
developers to choose the components and design patterns that best suit their project. This
makes it an excellent choice for building microservices and APIs. The following sections will
guide the developer through scaffolding the application, defining the API endpoint, interacting
with an external service, implementing the core business logic, and handling cross-origin
requests.

Section 2.1: Step-by-Step Flask Application Scaffolding


With the virtual environment active and the directory structure in place, the first step is to install
the necessary Python packages and create the initial Flask application object.
Step 1: Install Flask Using pip, the Python package installer, install Flask into the activated
virtual environment. This command will also install Flask's essential dependencies, such as
Werkzeug (a WSGI utility library) and Jinja2 (a templating engine).
(venv) pip install flask​

Step 2: Implement the Application Factory Instead of creating a global Flask application
instance, this project will use the "application factory" pattern. This is a best practice for Flask
applications of any non-trivial size as it offers several advantages: it improves testability, allows
for the creation of multiple application instances with different configurations, and helps avoid
circular import issues as the application grows.
The factory function, conventionally named create_app, will be defined in the
backend/app/__init__.py file. This file's presence also tells Python to treat the app directory as a
package.
Populate backend/app/__init__.py with the following code:
# backend/app/__init__.py​

from flask import Flask​

def create_app():​
"""​
Application factory function.​
"""​
app = Flask(__name__)​

# The __name__ argument helps Flask locate resources like
templates and static files.​

# Register blueprints, extensions, and other configurations here
in a real application.​
# For now, we will just return the app instance.​

return app​

This code defines the create_app function, which initializes and returns a Flask application
instance. Later, this function will be expanded to register API routes and configure extensions.
Step 3: Create the Application Entry Point While the application object is created within the
app package, an entry point script is needed to run it. This script will import the factory function
and start the development server.
Populate backend/run.py with the following code:
# backend/run.py​

from app import create_app​

app = create_app()​

if __name__ == '__main__':​
# The debug=True argument enables Flask's debugger and automatic
reloader.​
# The host='0.0.0.0' makes the server publicly available on the
local network.​
# The port can be set to any available port, 5000 is the Flask
default.​
app.run(host='0.0.0.0', port=5000, debug=True)​

To run the backend server, execute this file from the backend directory:
(venv) cd backend​
(venv) python run.py​

The terminal should display output indicating that the Flask development server is running,
typically on http://127.0.0.1:5000/. At this point, visiting this URL in a browser will result in a "Not
Found" error, as no routes have been defined yet.

Section 2.2: Designing and Implementing the API Endpoint


An API endpoint is a specific URL where the application listens for requests. This project
requires a single endpoint that accepts a product barcode and returns nutritional information.
This endpoint will be defined in the backend/app/routes.py file.
First, the create_app function in __init__.py needs to be modified to be aware of the routes. This
is typically done using a Flask feature called Blueprints, which allows for modular organization
of routes. For simplicity in this introductory project, we will directly register the routes with the
app instance.
Modify backend/app/__init__.py to import and register the routes:
# backend/app/__init__.py​

from flask import Flask​

def create_app():​
app = Flask(__name__)​

with app.app_context():​
# Import parts of our application​
from. import routes​

return app​
Now, define the actual endpoint in backend/app/routes.py. This route will handle GET requests
to URLs like /api/product/123456789.
# backend/app/routes.py​

from flask import current_app as app, jsonify​

@app.route('/api/product/<string:barcode>', methods=)​
def get_product(barcode):​
"""​
Endpoint to retrieve and analyze a food product by its barcode.​
"""​
if not barcode.isdigit():​
return jsonify({"error": "Invalid barcode format. Barcode must
be numeric."}), 400​

# This is a placeholder response.​
# In the next steps, this will be replaced with actual data
fetching and analysis.​
response_data = {​
"barcode": barcode,​
"product_name": "Placeholder Product",​
"message": "Data analysis is not yet implemented."​
}​

return jsonify(response_data), 200​

Code Explanation:
●​ from flask import current_app as app, jsonify: We import jsonify, a helper function to
create a JSON response, and current_app, a proxy that points to the application handling
the current request.
●​ @app.route('/api/product/<string:barcode>', methods=): This decorator registers the
get_product function as the handler for the specified URL pattern.
○​ The <string:barcode> part is a dynamic route variable. It captures the part of the
URL after /api/product/ and passes it as an argument named barcode to the
function.
○​ methods= explicitly states that this endpoint only responds to HTTP GET requests,
which are used for retrieving data.
●​ def get_product(barcode):: The view function that receives the barcode from the URL.
●​ if not barcode.isdigit(): A simple validation check to ensure the barcode contains only
digits. If not, it returns an error message with a 400 Bad Request status code.
●​ jsonify(response_data): The function takes a Python dictionary and converts it into a
JSON formatted response with the correct Content-Type header (application/json).
●​ , 200: The function returns a tuple where the second element is the HTTP status code.
200 OK indicates a successful request.
With these changes, running the server and navigating to
http://127.0.0.1:5000/api/product/12345 in a web browser should now display the placeholder
JSON response.
Section 2.3: The Open Food Facts Service Layer
To maintain a clean and organized codebase, it is a good practice to separate the logic for
communicating with external services from the route handlers. This is known as creating a
"service layer." This layer will be responsible for making HTTP requests to the Open Food Facts
API and handling the responses.
Step 1: Install the requests Library The requests library is the de facto standard for making
HTTP requests in Python. Install it into the virtual environment:
(venv) pip install requests​

Step 2: Create the Service Class The service logic will be implemented in
backend/app/services.py. This file will contain a class that encapsulates all interactions with the
Open Food Facts API.
Populate backend/app/services.py with the following code:
# backend/app/services.py​

import requests​

class OpenFoodFactsService:​
"""​
A service class to interact with the Open Food Facts API.​
"""​
BASE_URL = "https://world.openfoodfacts.net/api/v2/product"​

def get_product_by_barcode(self, barcode):​
"""​
Fetches product data from the Open Food Facts API for a given
barcode.​

Args:​
barcode (str): The product barcode.​

Returns:​
dict: A dictionary containing the API response data, or
None if the product is not found or an error occurs.​
"""​
# Define the fields we want to retrieve to keep the response
lightweight.​
fields_to_request =
"product_name,nutriments,nutrition_grades,nova_group,ingredients_text"​

request_url =
f"{self.BASE_URL}/{barcode}?fields={fields_to_request}"​

# It is good practice to set a custom User-Agent header to
identify your application.​
headers = {​
'User-Agent': 'FoodAnalyzerApp/1.0 -
your-contact-info@example.com'​
}​

try:​
response = requests.get(request_url, headers=headers)​
response.raise_for_status() # Raises an HTTPError for bad
responses (4xx or 5xx)​

data = response.json()​

if data.get("status") == 0 or "product" not in data:​
# API indicates product not found​
return None​

return data.get("product")​

except requests.exceptions.HTTPError as http_err:​
print(f"HTTP error occurred: {http_err}")​
return None​
except requests.exceptions.RequestException as err:​
print(f"An error occurred: {err}")​
return None​

Code Explanation:
●​ BASE_URL: The base endpoint for fetching a product by its barcode, as specified in the
API documentation.
●​ fields_to_request: A comma-separated string of the specific data fields required for the
application. Requesting only necessary fields is an important optimization that reduces
network traffic and speeds up the response.
●​ headers: A custom User-Agent header is included. The Open Food Facts API
documentation encourages this practice so they can identify the application making
requests and contact the developer if issues arise.
●​ requests.get(): Makes the GET request to the constructed URL.
●​ response.raise_for_status(): A convenient method that checks if the request was
successful. If the HTTP status code indicates an error (e.g., 404 Not Found, 503 Service
Unavailable), it will raise an exception.
●​ response.json(): Parses the JSON response body into a Python dictionary.
●​ Error Handling: The try...except block gracefully handles potential network errors or bad
responses from the external API, preventing the backend from crashing. If an error occurs
or the product is not found (indicated by status: 0 in the API response), the function
returns None.
Step 3: Integrate the Service into the Route Now, the get_product route handler in routes.py
can be updated to use this new service.
Modify backend/app/routes.py:
# backend/app/routes.py​

from flask import current_app as app, jsonify​
from.services import OpenFoodFactsService​

@app.route('/api/product/<string:barcode>', methods=)​
def get_product(barcode):​
if not barcode.isdigit():​
return jsonify({"error": "Invalid barcode format. Barcode must
be numeric."}), 400​

service = OpenFoodFactsService()​
product_data = service.get_product_by_barcode(barcode)​

if product_data is None:​
return jsonify({"error": f"Product with barcode '{barcode}'
not found."}), 404​

# The analysis logic will be added here in the next step.​
# For now, just return the fetched data.​
return jsonify(product_data), 200​

With this change, the endpoint now makes a live call to the Open Food Facts API. Testing it with
a valid barcode (e.g., 3017620422003 for Nutella) should return a rich JSON object with the
product's name and nutritional information. If an invalid barcode is used, it will return a 404 Not
Found error.

Section 2.4: Implementing the Health Score Algorithm


This section implements the core business logic of the application: analyzing the nutritional data
of a food product to provide a simple health assessment. This logic will be contained within the
backend/app/analysis.py file to keep it separate from the routing and service layers.
The analysis will not be a complex numerical score but rather a series of qualitative flags based
on established nutritional guidelines. This approach, often referred to as a "traffic light" system,
provides clear, actionable feedback to the user. The thresholds for what constitutes a "High"
(Red), "Medium" (Amber), or "Low" (Green) amount of a nutrient are based on guidelines
provided by health organizations like the UK's National Health Service (NHS).
The following table outlines the scoring rubric that will be implemented, based on nutrient values
per 100g of the product.
Nutrient Low (Green) Medium (Amber) High (Red)
Total Fat $ \le 3.0g $ $ > 3.0g $ and $ \le $ > 17.5g $
17.5g $
Saturated Fat $ \le 1.5g $ $ > 1.5g $ and $ \le $ > 5.0g $
5.0g $
Sugars $ \le 5.0g $ $ > 5.0g $ and $ \le $ > 22.5g $
22.5g $
Salt $ \le 0.3g $ $ > 0.3g $ and $ \le $ > 1.5g $
1.5g $
These guidelines provide a clear, data-driven basis for the analysis function. Presenting them in
a table makes the logic of the subsequent Python code transparent and easy to verify. This
separation of the rules (the data) from the implementation (the code) is a key software design
principle that improves maintainability.
Step 1: Create the Analysis Function Populate backend/app/analysis.py with the function that
implements the logic from the table above.
# backend/app/analysis.py​

def analyze_product_nutrition(nutriments):​
"""​
Analyzes the nutritional information of a product and returns a
health assessment.​

Args:​
nutriments (dict): A dictionary of nutritional values,
typically from the Open Food Facts API.​

Returns:​
dict: A dictionary containing the analysis results for key
nutrients.​
"""​
analysis = {}​

# The API provides values per 100g, which is what the guidelines
are based on.​
# We use.get(key, 0) to handle cases where a nutrient might be
missing from the API data.​

# 1. Analyze Total Fat​
fat_100g = nutriments.get('fat_100g', 0)​
if fat_100g > 17.5:​
analysis['fat'] = {'level': 'High', 'value': fat_100g}​
elif fat_100g > 3.0:​
analysis['fat'] = {'level': 'Medium', 'value': fat_100g}​
else:​
analysis['fat'] = {'level': 'Low', 'value': fat_100g}​

# 2. Analyze Saturated Fat​
saturated_fat_100g = nutriments.get('saturated-fat_100g', 0)​
if saturated_fat_100g > 5.0:​
analysis['saturates'] = {'level': 'High', 'value':
saturated_fat_100g}​
elif saturated_fat_100g > 1.5:​
analysis['saturates'] = {'level': 'Medium', 'value':
saturated_fat_100g}​
else:​
analysis['saturates'] = {'level': 'Low', 'value':
saturated_fat_100g}​

# 3. Analyze Sugars​
sugars_100g = nutriments.get('sugars_100g', 0)​
if sugars_100g > 22.5:​
analysis['sugars'] = {'level': 'High', 'value': sugars_100g}​
elif sugars_100g > 5.0:​
analysis['sugars'] = {'level': 'Medium', 'value': sugars_100g}​
else:​
analysis['sugars'] = {'level': 'Low', 'value': sugars_100g}​

# 4. Analyze Salt​
salt_100g = nutriments.get('salt_100g', 0)​
if salt_100g > 1.5:​
analysis['salt'] = {'level': 'High', 'value': salt_100g}​
elif salt_100g > 0.3:​
analysis['salt'] = {'level': 'Medium', 'value': salt_100g}​
else:​
analysis['salt'] = {'level': 'Low', 'value': salt_100g}​

return analysis​

Step 2: Integrate the Analysis into the Route Finally, update the get_product route in
routes.py to call this analysis function and include its results in the final API response.
Modify backend/app/routes.py:
# backend/app/routes.py​

from flask import current_app as app, jsonify​
from.services import OpenFoodFactsService​
from.analysis import analyze_product_nutrition​

@app.route('/api/product/<string:barcode>', methods=)​
def get_product(barcode):​
if not barcode.isdigit():​
return jsonify({"error": "Invalid barcode format. Barcode must
be numeric."}), 400​

service = OpenFoodFactsService()​
product_data = service.get_product_by_barcode(barcode)​

if product_data is None:​
return jsonify({"error": f"Product with barcode '{barcode}'
not found."}), 404​

# Perform the nutritional analysis​
nutriments = product_data.get('nutriments', {})​
nutritional_analysis = analyze_product_nutrition(nutriments)​

# Combine the original product data with our analysis​
final_response = {​
"product": product_data,​
"analysis": nutritional_analysis​
}​

return jsonify(final_response), 200​

The backend is now feature-complete. When the API endpoint is called, it fetches data from the
external API, passes the nutritional information to the analysis module, and returns a composite
JSON object containing both the raw product data and the generated health assessment.

Section 2.5: Enabling Cross-Origin Resource Sharing (CORS)


A fundamental security feature of modern web browsers is the Same-Origin Policy (SOP). This
policy restricts how a document or script loaded from one "origin" can interact with a resource
from another origin. An origin is defined by the combination of protocol (e.g., http), hostname
(e.g., localhost), and port (e.g., 8080).
In this project's decoupled architecture, the frontend will be served from one origin (e.g.,
http://localhost:8080) and the backend API from another (e.g., http://localhost:5000). When the
JavaScript on the frontend attempts to make a fetch request to the backend, the browser will
block it by default due to the SOP.
To permit this cross-origin communication, the server must implement Cross-Origin Resource
Sharing (CORS). CORS is a mechanism that uses additional HTTP headers to tell a browser to
let a web application running at one origin have permission to access selected resources from a
server at a different origin.
Understanding this mechanism is a crucial step in comprehending modern web security. The
browser's default blocking behavior is a protective measure against threats like Cross-Site
Request Forgery (CSRF), where a malicious site could try to make requests to a legitimate site
where the user is logged in. By configuring CORS, the server is explicitly telling the browser, "I
trust requests coming from this specific frontend origin; it is safe to allow them." This transforms
CORS from a development nuisance into a security feature that must be configured correctly
and deliberately.
Step 1: Install Flask-CORS Flask-CORS is a Flask extension that makes handling CORS
straightforward. Install it into the virtual environment:
(venv) pip install flask-cors​

Step 2: Configure CORS in the Application Factory The Flask-CORS extension should be
initialized within the create_app factory in __init__.py. This allows for fine-grained control over
which origins and routes are permitted.
Modify backend/app/__init__.py:
# backend/app/__init__.py​

from flask import Flask​
from flask_cors import CORS​

def create_app():​
app = Flask(__name__)​

# Initialize CORS. By default, this allows all origins.​
# For production, it's better to restrict it to the specific
frontend domain.​
# Example for production: CORS(app, resources={r"/api/*":
{"origins": "https://your-frontend-domain.com"}})​
CORS(app)​

with app.app_context():​
# Import parts of our application​
from. import routes​

return app​

By default, initializing CORS(app) allows requests from any origin for all routes. While this is
convenient for local development, in a production environment, it is critical to restrict the allowed
origins to only the domain where the frontend application is hosted. This prevents other,
potentially malicious websites from making requests to the API.
With CORS enabled, the backend is now fully prepared to receive and respond to requests from
the frontend application, completing the server-side development phase.

Part III: Crafting the Interactive Frontend


This part of the guide focuses on building the client-side of the application—the user interface
that runs in the web browser. The frontend will be constructed using the three core technologies
of the web: HTML for the structure and content, CSS for the styling and presentation, and
vanilla JavaScript (meaning, plain JavaScript without any frameworks or libraries) for the
interactivity and logic. Adhering to a clear separation of these concerns is a fundamental
principle of frontend development that results in code that is easier to maintain, debug, and
expand.

Section 3.1: Structuring the Frontend Files


As established in Part I, the frontend code will reside in the /frontend directory. This directory
contains three essential files, each with a distinct role :
●​ index.html: This file defines the structure and content of the web page. It contains all the
text, input fields, buttons, and containers that the user will see and interact with. It acts as
the skeleton of the application.
●​ style.css: This file controls the visual presentation of the HTML elements. It defines the
layout, colors, fonts, and spacing, ensuring the application is aesthetically pleasing and
user-friendly. It is the "skin" of the application.
●​ app.js: This file contains the application's behavior and logic. It listens for user actions
(like button clicks), communicates with the backend API to fetch data, and dynamically
manipulates the HTML to display the results. It is the "brain" of the client-side application.
These three files will be linked together within the index.html file, forming a complete, interactive
web page.

Section 3.2: Building the User Interface with HTML5


The index.html file provides the structural foundation for the user interface. It is important to use
semantic HTML5 elements (<header>, <main>, <section>, <label>) where appropriate.
Semantic markup improves accessibility for users relying on screen readers and can also
benefit search engine optimization (SEO) by providing more context about the page's content.
Populate frontend/index.html with the following code:
<!DOCTYPE html>​
<html lang="en">​
<head>​
<meta charset="UTF-8">​
<meta name="viewport" content="width=device-width,
initial-scale=1.0">​
<title>Food Product Analyzer</title>​
<link rel="stylesheet" href="style.css">​
</head>​
<body>​

<header class="header">​
<h1>Food Product Analyzer</h1>​
<p>Enter a product barcode to get its nutritional
analysis.</p>​
</header>​

<main class="main-content">​
<section class="search-section">​
<form id="search-form">​
<label for="barcode-input">Product Barcode:</label>​
<input type="text" id="barcode-input"
placeholder="e.g., 3017620422003" required>​
<button type="submit"
id="search-button">Analyze</button>​
</form>​
</section>​

<section id="results-section" class="results-section">​
<div id="loader" class="loader hidden"></div>​

<div id="error-message" class="error-message
hidden"></div>​

<div id="product-info" class="product-info hidden">​
<h2 id="product-name"></h2>​
<div id="nutritional-analysis"
class="nutritional-analysis">​
</div>​
<p id="ingredients"></p>​
</div>​
</section>​
</main>​

<script src="app.js"></script>​
</body>​
</html>​

HTML Structure Breakdown:


●​ <head>: Contains metadata about the page, including the character set, viewport settings
for responsiveness, the page title, and a link to the external style.css stylesheet.
●​ <header>: A semantic container for the main title and introductory text.
●​ <main>: A container for the primary content of the page.
●​ <form id="search-form">: The form element that encapsulates the user input field and
submission button. The required attribute on the input provides basic browser-level
validation.
●​ <section id="results-section">: A dedicated section to display the output of the
analysis. It contains several div elements with unique IDs that will be targeted by
JavaScript:
○​ #loader: A placeholder for a loading indicator.
○​ #error-message: A container for displaying error messages to the user.
○​ #product-info: The main container for the fetched product data and analysis, which
will be populated dynamically.
●​ <script src="app.js">: The script tag, placed at the end of the <body>, links and
executes the external JavaScript file. Placing it here ensures that the HTML document is
fully parsed and the DOM is ready before the script attempts to manipulate it.

Section 3.3: Styling the Application with Modern CSS


The style.css file is responsible for the application's visual design. The following CSS provides a
clean, modern, and responsive layout using Flexbox for alignment and a simple color palette. It
also defines styles for the different states of the UI (e.g., hidden elements, loading spinner) and
the color-coded analysis results, which provide immediate visual feedback to the user, inspired
by the traffic light labeling system.
Populate frontend/style.css with the following code:
/* General Body & Font Styling */​
body {​
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI",
Roboto, Helvetica, Arial, sans-serif;​
line-height: 1.6;​
background-color: #f4f7f6;​
color: #333;​
margin: 0;​
padding: 20px;​
display: flex;​
flex-direction: column;​
align-items: center;​
}​

/* Header Styling */​
.header {​
text-align: center;​
margin-bottom: 2rem;​
max-width: 600px;​
width: 100%;​
}​

.header h1 {​
color: #2c3e50;​
margin-bottom: 0.5rem;​
}​

/* Main Content Area */​
.main-content {​
background-color: #ffffff;​
padding: 2rem;​
border-radius: 8px;​
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);​
width: 100%;​
max-width: 600px;​
}​

/* Search Form Styling */​
#search-form {​
display: flex;​
flex-direction: column;​
gap: 1rem;​
}​

#search-form label {​
font-weight: bold;​
}​

#barcode-input {​
padding: 0.75rem;​
font-size: 1rem;​
border: 1px solid #ccc;​
border-radius: 4px;​
}​

#search-button {​
padding: 0.75rem;​
font-size: 1rem;​
font-weight: bold;​
color: #fff;​
background-color: #3498db;​
border: none;​
border-radius: 4px;​
cursor: pointer;​
transition: background-color 0.3s ease;​
}​

#search-button:hover {​
background-color: #2980b9;​
}​

/* Results Section */​
.results-section {​
margin-top: 2rem;​
}​

.product-info h2 {​
margin-top: 0;​
color: #2c3e50;​
border-bottom: 2px solid #ecf0f1;​
padding-bottom: 0.5rem;​
}​

.nutritional-analysis {​
display: grid;​
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));​
gap: 1rem;​
margin: 1.5rem 0;​
}​

.nutrient-card {​
padding: 1rem;​
border-radius: 4px;​
text-align: center;​
color: #fff;​
}​

.nutrient-card.level {​
font-size: 1.2rem;​
font-weight: bold;​
text-transform: uppercase;​
}​

.nutrient-card.value {​
font-size: 0.9rem;​
margin-top: 0.5rem;​
}​

/* Traffic Light Colors for Analysis */​
.level-High { background-color: #e74c3c; /* Red */ }​
.level-Medium { background-color: #f39c12; /* Amber */ }​
.level-Low { background-color: #2ecc71; /* Green */ }​

#ingredients {​
font-style: italic;​
color: #555;​
margin-top: 1.5rem;​
font-size: 0.9rem;​
}​

/* Utility Classes */​
.hidden {​
display: none;​
}​

.error-message {​
color: #e74c3c;​
background-color: #fbeae5;​
padding: 1rem;​
border: 1px solid #e74c3c;​
border-radius: 4px;​
text-align: center;​
}​

/* Loading Spinner */​
.loader {​
border: 5px solid #f3f3f3;​
border-top: 5px solid #3498db;​
border-radius: 50%;​
width: 40px;​
height: 40px;​
animation: spin 1s linear infinite;​
margin: 2rem auto;​
}​

@keyframes spin {​
0% { transform: rotate(0deg); }​
100% { transform: rotate(360deg); }​
}​

Section 3.4: Implementing Frontend Logic with Vanilla JavaScript


The app.js file is where the application comes to life. The script will be responsible for three
primary tasks:
1.​ DOM Element Selection: Getting programmatic references to the HTML elements that
need to be manipulated.
2.​ Event Handling: Listening for the form submission event to trigger the data-fetching
process.
3.​ API Communication and DOM Manipulation: Using the modern fetch API to
communicate with the backend, and then using the response data to dynamically update
the web page's content.
Populate frontend/app.js with the following code:
// Wait for the DOM to be fully loaded before running the script​
document.addEventListener('DOMContentLoaded', () => {​

// 1. DOM Element Selection​
const searchForm = document.getElementById('search-form');​
const barcodeInput = document.getElementById('barcode-input');​
const loader = document.getElementById('loader');​
const errorMessage = document.getElementById('error-message');​
const productInfo = document.getElementById('product-info');​
const productName = document.getElementById('product-name');​
const nutritionalAnalysis =
document.getElementById('nutritional-analysis');​
const ingredients = document.getElementById('ingredients');​

const API_BASE_URL = 'http://localhost:5000/api';​

// 2. Event Handling​
searchForm.addEventListener('submit', async (event) => {​
event.preventDefault(); // Prevent the default form submission
(page reload)​

const barcode = barcodeInput.value.trim();​
if (!barcode) {​
displayError('Please enter a barcode.');​
return;​
}​

// Reset UI state before new search​
resetUI();​
loader.classList.remove('hidden');​

try {​
// 3. API Communication​
const response = await
fetch(`${API_BASE_URL}/product/${barcode}`);​

if (!response.ok) {​
const errorData = await response.json();​
throw new Error(errorData.error |​

| `HTTP error! Status: ${response.status}`);​
}​

const data = await response.json();​
displayProductData(data);​

} catch (error) {​
displayError(error.message);​
} finally {​
loader.classList.add('hidden');​
}​
});​

// 4. DOM Manipulation Functions​
function displayProductData(data) {​
// Display product name​
productName.textContent = data.product.product_name |​

| 'Product name not available';​

// Display ingredients​
ingredients.textContent = `Ingredients:
${data.product.ingredients_text |​

| 'Not available'}`;​

// Clear previous analysis and create new nutrient cards​
nutritionalAnalysis.innerHTML = ''; ​
for (const [nutrient, details] of
Object.entries(data.analysis)) {​
const card = document.createElement('div');​
card.className = `nutrient-card level-${details.level}`;​

card.innerHTML = `​
<div class="level">${details.level}</div>​
<div
class="nutrient-name">${nutrient.charAt(0).toUpperCase() +
nutrient.slice(1)}</div>​
<div class="value">${details.value.toFixed(2)}g per
100g</div>​
`;​
nutritionalAnalysis.appendChild(card);​
}​

productInfo.classList.remove('hidden');​
}​

function displayError(message) {​
errorMessage.textContent = message;​
errorMessage.classList.remove('hidden');​
}​

function resetUI() {​
errorMessage.classList.add('hidden');​
productInfo.classList.add('hidden');​
nutritionalAnalysis.innerHTML = '';​
}​
});​

JavaScript Logic Breakdown:


●​ DOMContentLoaded Listener: The entire script is wrapped in this event listener to
ensure that the code only runs after the HTML page has been fully loaded and parsed.
This prevents errors that would occur if the script tried to find DOM elements that do not
yet exist.
●​ async (event) => {... }: The event listener for the form submission is an async function.
This is necessary to use the await keyword, which simplifies handling asynchronous
operations like fetch requests.
●​ event.preventDefault(): This crucial line stops the browser's default behavior of reloading
the page when a form is submitted. This allows for the creation of a Single-Page
Application (SPA) experience where content is updated dynamically without full page
refreshes.
●​ fetch(...): The fetch API is used to make the GET request to the backend. It returns a
Promise, which is handled cleanly by await. The URL is constructed dynamically using the
barcode from the input field.
●​ Error Handling: The try...catch...finally block provides robust error handling.
○​ The try block contains the asynchronous API call. If the response.ok property is
false (meaning an HTTP status code outside the 200-299 range), an error is
manually thrown to be caught by the catch block.
○​ The catch block calls the displayError function to show a user-friendly error
message in the UI.
○​ The finally block always executes, ensuring the loading spinner is hidden
regardless of whether the request succeeded or failed.
●​ displayProductData(data): This function is responsible for taking the JSON data from
the backend and updating the DOM. It sets the product name and ingredients text. It then
iterates over the analysis object from the API response, dynamically creating a div
element (a "card") for each nutrient, styling it with the appropriate color class (level-High,
level-Medium, or level-Low), and appending it to the results container. This dynamic
creation of HTML is a core concept in modern web development.
●​ resetUI(): This helper function clears any previous results or error messages from the
screen, ensuring a clean state for each new search.

Part IV: Full-Stack Integration and Finalization


With both the backend API and the frontend interface developed, this part focuses on bringing
them together into a cohesive, fully functional application. It involves tracing the complete flow of
data from user interaction to final display, implementing robust error handling across the entire
stack, and providing clear instructions for running both components concurrently for live testing.
This integration phase is critical for validating that the "API as a contract" has been successfully
implemented and for hardening the application against potential failures.
Section 4.1: The End-to-End Data Flow
To fully understand how the application works, it is essential to trace a single user request
through the entire system. This sequence demonstrates the interaction between the decoupled
components and the journey of data from the user's browser to the external API and back again.
The sequence of events for a successful analysis is as follows:
1.​ User Action (Frontend): The user types a barcode (e.g., 3017620422003) into the input
field on the index.html page and clicks the "Analyze" button.
2.​ Event Capture (Frontend - app.js): The JavaScript submit event listener on the form is
triggered. It calls event.preventDefault() to stop the page from reloading.
3.​ HTTP Request (Frontend - app.js): The fetch function is called, initiating an
asynchronous GET request to the backend API endpoint. The URL is dynamically
constructed: http://localhost:5000/api/product/3017620422003. The browser, respecting
the CORS headers sent by the backend, allows this cross-origin request to proceed.
4.​ Request Reception (Backend - routes.py): The Flask development server, listening on
port 5000, receives the incoming GET request. Flask's routing mechanism matches the
URL to the @app.route('/api/product/<string:barcode>') decorator and calls the
get_product function, passing "3017620422003" as the barcode argument.
5.​ Service Layer Invocation (Backend - routes.py): The get_product function instantiates
the OpenFoodFactsService and calls its get_product_by_barcode method.
6.​ External API Call (Backend - services.py): The OpenFoodFactsService constructs the
URL for the external Open Food Facts API, including the specific fields to retrieve. It then
uses the requests library to make a GET request to
https://world.openfoodfacts.net/api/v2/product/3017620422003?fields=....
7.​ External API Response (Data Layer): The Open Food Facts server processes the
request and sends back a JSON response containing the requested data for the specified
product.
8.​ Data Processing (Backend - services.py): The OpenFoodFactsService receives the
response, parses the JSON into a Python dictionary, and returns the relevant product data
object to the route handler.
9.​ Business Logic Execution (Backend - routes.py & analysis.py): The get_product
function extracts the nutriments dictionary from the received data and passes it to the
analyze_product_nutrition function in the analysis module.
10.​Analysis Generation (Backend - analysis.py): The analyze_product_nutrition function
applies the predefined nutritional rules (the traffic light system) to the nutriments data and
returns a new dictionary containing the analysis results (e.g., {'fat': {'level': 'High',...}}).
11.​Final Response Assembly (Backend - routes.py): The get_product function combines
the original product_data and the nutritional_analysis into a single Python dictionary. It
then uses Flask's jsonify function to serialize this dictionary into a JSON string and sends
it back to the browser as the HTTP response, with a 200 OK status code.
12.​Response Handling (Frontend - app.js): The await in the fetch call resolves, and the
JavaScript code receives the JSON response from the backend. The .json() method is
called on the response object to parse it into a JavaScript object.
13.​DOM Manipulation (Frontend - app.js): The displayProductData function is called with
the received data object. It dynamically creates and inserts HTML elements into the
#product-info section of the page, displaying the product's name, ingredients, and the
color-coded nutritional analysis cards.
This end-to-end flow solidifies the developer's understanding of the full-stack request-response
cycle and highlights the distinct responsibilities of each layer in the application's architecture.

Section 4.2: Error Handling and User Feedback


A robust application must anticipate and handle errors gracefully. Without proper error handling,
network issues, invalid user input, or problems with external services can lead to a crashed
application or a confusing, broken user interface. Error handling must be implemented on both
the frontend and the backend.
Frontend Error Handling (app.js) The frontend is responsible for catching errors that occur
during the API call and displaying a clear, helpful message to the user.
●​ Network and Server Errors: The try...catch block surrounding the fetch call in app.js is
the primary mechanism for this. If the fetch promise rejects (e.g., due to a network failure)
or if the server responds with a non-successful HTTP status code (triggering the throw
new Error(...) line), the catch block will execute. Inside this block, the displayError function
is called, which updates the DOM to show the error message in a designated area.
●​ User Input Validation: While the backend performs its own validation, the frontend
should also perform client-side validation for a better user experience. The current
implementation checks if the barcode input is empty. This could be expanded to check for
non-numeric characters before even sending the request, providing instant feedback.
Backend Error Handling (routes.py and services.py) The backend must handle errors
robustly and return meaningful HTTP status codes to the client. This allows the frontend to
programmatically understand the nature of the error.
●​ Invalid Input (routes.py): The get_product route handler checks if the provided barcode
is numeric. If not, it immediately returns a JSON error message with a 400 Bad Request
status code. This prevents invalid data from being processed further.
●​ Product Not Found (routes.py): When the OpenFoodFactsService returns None
(indicating the product was not found in the external API), the route handler returns a
JSON error message with a 404 Not Found status code. This is the correct semantic
status code for a missing resource.
●​ External API Failures (services.py): The try...except block within the
get_product_by_barcode method handles failures in communication with the Open Food
Facts API. If requests raises an HTTPError (for a 4xx or 5xx response) or any other
RequestException (like a timeout or DNS failure), the error is logged to the console, and
the method returns None. This prevents the backend from crashing and allows the route
handler to treat it as a "product not found" scenario, returning a 404 to the user. In a more
advanced application, this could be distinguished with a 503 Service Unavailable or 502
Bad Gateway status code to indicate that the problem lies with an upstream service.
By implementing these checks at each layer, the application becomes more resilient and
provides a more predictable and user-friendly experience, even when things go wrong.

Section 4.3: Running the Full Application Concurrently


To test the complete, integrated application, both the backend server and the frontend assets
must be served simultaneously. Since they are separate components running on different ports,
this requires two separate terminal processes.
Step 1: Run the Backend Server
1.​ Open a new terminal window or tab.
2.​ Navigate to the project's root directory (food-analyzer).
3.​ Activate the Python virtual environment:
○​ macOS/Linux: source venv/bin/activate
○​ Windows: venv\Scripts\activate.bat
4.​ Navigate into the backend directory: cd backend
5.​ Start the Flask development server: python run.py The terminal will show output indicating
the server is running on http://localhost:5000. This terminal window must remain open for
the backend to stay active.
Step 2: Run the Frontend Server The frontend consists of static files (.html, .css, .js) that need
to be served by a simple web server. A common and easy way to do this is using the http-server
package from npm, or by using a built-in feature of a code editor like VS Code's "Live Server"
extension. An alternative using only Python is also available.
●​ Method A (Using http-server - Recommended):
1.​ If Node.js and npm are not already installed, they must be installed first.
2.​ Install http-server globally: npm install -g http-server
3.​ Open a second, separate terminal window.
4.​ Navigate to the project's root directory (food-analyzer).
5.​ Navigate into the frontend directory: cd frontend
6.​ Start the static file server: http-server The terminal will show output indicating the
server is running, typically on http://localhost:8080.
●​ Method B (Using Python's built-in server):
1.​ Open a second, separate terminal window.
2.​ Navigate to the project's root directory (food-analyzer).
3.​ Navigate into the frontend directory: cd frontend
4.​ Start the server: python3 -m http.server 8080 This will serve the contents of the
frontend directory on http://localhost:8080.
Step 3: Test the Application
1.​ With both servers running, open a web browser.
2.​ Navigate to the frontend URL: http://localhost:8080.
3.​ The Food Product Analyzer interface should appear.
4.​ Enter a valid product barcode and click "Analyze."
5.​ Observe the network requests in the browser's developer tools (Network tab) to see the
fetch call to localhost:5000.
6.​ The results should appear on the page, confirming that the frontend and backend are
communicating correctly.

Part V: Beyond Development: Deployment and


Expansion
Completing the local development of the Food Analyzer application is a significant achievement.
It provides a solid foundation in full-stack principles, API integration, and modern development
practices. However, the journey of a software project does not end with a functional local
version. This final part provides a high-level overview of the next steps: moving the application
from a local development environment to a live production server and exploring potential
pathways to expand the project's functionality. These sections are intended to serve as a guide
for continued learning, transforming this project from a standalone tutorial into a launchpad for
more advanced topics.

Section 5.1: A Primer on Production Deployment


The development servers used in this project (Flask's built-in server and Python's http.server)
are designed for convenience during development. They are not suitable for a production
environment because they are not built to be secure, stable, or performant enough to handle
real-world traffic.
To deploy a Flask application to production, a production-grade Web Server Gateway Interface
(WSGI) server is required. A WSGI server is a robust piece of software that sits between a
traditional web server (like Nginx or Apache) and the Flask application. It is responsible for
efficiently handling concurrent requests and managing application processes.
●​ WSGI Servers: A popular and widely-used WSGI server for Python applications is
Gunicorn ("Green Unicorn"). It is simple to configure and is known for its stability and
performance.
●​ Web Servers: A WSGI server is often run behind a reverse proxy web server like Nginx.
Nginx is highly efficient at handling static files, terminating SSL (HTTPS), and forwarding
dynamic requests to the Gunicorn server. This combination of Nginx + Gunicorn + Flask is
a standard and battle-tested deployment stack.
●​ Platform-as-a-Service (PaaS): For developers looking for a simpler deployment path,
PaaS providers like Heroku, Vercel, or DigitalOcean App Platform offer a more managed
experience. These platforms typically abstract away the complexities of server
configuration. The developer can often deploy their application by simply pushing their
code to a Git repository, and the platform automatically provisions the necessary servers,
installs dependencies, and runs the application using a production-grade stack.
Deploying the frontend is typically simpler, as it consists of static files. These files can be served
by the same Nginx server that is proxying requests to the backend, or they can be hosted on a
dedicated static hosting service or a Content Delivery Network (CDN) for optimal performance.

Section 5.2: Pathways for Project Expansion


This project provides an excellent foundation upon which to build more complex features. By
expanding the application, developers can gain experience with new technologies and
concepts. Here are several potential pathways for enhancement:
●​ Add a Database for Search History:
○​ Concept: Persist data by saving each successfully analyzed product to a database.
○​ Implementation: Integrate Flask-SQLAlchemy, a Flask extension that makes
working with databases like SQLite or PostgreSQL much easier. Create a database
model (a Python class) to represent a Product. Modify the API to include a new
endpoint, such as GET /api/history, that retrieves the list of previously searched
products from the database and displays it on the frontend.
●​ Implement User Accounts:
○​ Concept: Allow users to register for an account and log in. This would enable
personalized features.
○​ Implementation: Add user registration and login forms to the frontend. On the
backend, create a User database model and implement routes for handling
registration (POST /api/register) and login (POST /api/login). This would involve
password hashing for security and session management (using Flask sessions or
JWT tokens) to keep users logged in across requests. A logged-in user could then,
for example, save products to a personal "favorites" list.
●​ Perform Advanced Nutritional Analysis:
○​ Concept: Provide more detailed and nuanced health information beyond the basic
traffic light system.
○​ Implementation: Leverage more of the data available from the Open Food Facts
API.
■​ Food Additives: Fetch the list of ingredients and check for the presence of
common additives of concern, such as artificial colors (Red 40, Yellow 5),
preservatives (BHA, sodium nitrite), or artificial sweeteners (aspartame).
Display warnings or information about these additives to the user.
■​ Allergens: The API provides allergen information. Highlight common
allergens like nuts, dairy, wheat, and soy in the user interface.
■​ Processing Level (NOVA Score): The Open Food Facts API often includes
a NOVA group classification, which categorizes foods based on their level of
processing. Displaying this score can help users understand the difference
between minimally processed foods and ultra-processed foods (UPFs).
●​ Incorporate Data Visualization:
○​ Concept: Present nutritional data in a more engaging and easy-to-understand
format.
○​ Implementation: Use a simple, lightweight JavaScript charting library (such as
Chart.js or D3.js) on the frontend. After fetching the product data, use the library to
generate a bar chart that visually compares the amounts of fat, carbohydrates,
sugar, and protein in the product. This can provide a much clearer at-a-glance
understanding of the product's macronutrient profile than text alone.
By pursuing these or other expansions, the developer can continue to build upon the skills
learned in this guide, tackling progressively more complex challenges and deepening their
understanding of full-stack web development. This project is not an end-point, but a starting
point for a continuous journey of learning and building.

Works cited

1. A Beginner's Introduction to Best Python Web Frameworks in 2022 - STX Next,


https://www.stxnext.com/blog/beginners-introduction-python-frameworks 2. Build a JavaScript
Front End for a Flask API - Real Python,
https://realpython.com/flask-javascript-frontend-for-rest-api/ 3. Python backend with JavaScript
frontend: how to - TMS Developer ...,
https://tms-dev-blog.com/python-backend-with-javascript-frontend-how-to/ 4. Python Projects -
Beginner to Advanced - GeeksforGeeks,
https://www.geeksforgeeks.org/python/python-projects-beginner-to-advanced/ 5. Python For
Beginners | Python.org, https://www.python.org/about/gettingstarted/ 6. Project Layout — Flask
Documentation (3.1.x), https://flask.palletsprojects.com/en/stable/tutorial/layout/ 7. How to Build
a Flask Python Web Application from Scratch - DigitalOcean,
https://www.digitalocean.com/community/tutorials/how-to-make-a-web-application-using-flask-in-
python-3 8. Build a Scalable Flask Web Project From Scratch – Real Python,
https://realpython.com/flask-project/ 9. Flask Templates — Python Beginners documentation,
https://python-adv-web-apps.readthedocs.io/en/latest/flask3.html 10. Flask Tutorial -
GeeksforGeeks, https://www.geeksforgeeks.org/python/flask-tutorial/ 11. How To Structure a
Large Flask Application with Flask Blueprints and Flask-SQLAlchemy,
https://www.digitalocean.com/community/tutorials/how-to-structure-a-large-flask-application-with
-flask-blueprints-and-flask-sqlalchemy 12. Flask Tutorial - Tutorialspoint,
https://www.tutorialspoint.com/flask/index.htm 13. Tutorial on using the Open Food Facts API -
Product Opener (Open ...,
https://openfoodfacts.github.io/openfoodfacts-server/api/tutorial-off-api/ 14. Introduction to Open
Food Facts API documentation, https://openfoodfacts.github.io/openfoodfacts-server/api/ 15.
Food labels - NHS,
https://www.nhs.uk/live-well/eat-well/food-guidelines-and-food-labels/how-to-read-food-labels/
16. AI Chat: JavaScript frontend + Python backend - JavaScript on Azure | Microsoft Learn,
https://learn.microsoft.com/en-us/azure/developer/javascript/ai/chat-app-with-separate-front-bac
k-end 17. Python Flask Tutorial - FULL COURSE - YouTube,
https://www.youtube.com/watch?v=2YOBmELm_v0 18. Learn Web Development Basics with
HTML CSS and JavaScript - GeeksforGeeks,
https://www.geeksforgeeks.org/javascript/learn-web-development-basics-with-html-css-and-java
script/ 19. Tutorial — Flask Documentation (3.1.x),
https://flask.palletsprojects.com/en/stable/tutorial/ 20. EWG's Dirty Dozen Guide to Food
Chemicals: The top 12 to avoid,
https://www.ewg.org/consumer-guides/ewgs-dirty-dozen-guide-food-chemicals-top-12-avoid 21.
Food additives | Better Health Channel,
https://www.betterhealth.vic.gov.au/health/conditionsandtreatments/food-additives 22. Should
You Be Concerned About Food Additives? - University Hospitals,
https://www.uhhospitals.org/blog/articles/2025/01/should-you-be-concerned-about-food-additive
s 23. Food Labeling on Packaged Food - Rhode Island Department of Health,
https://health.ri.gov/food-safety/food-labeling-packaged-food 24. Craving some burger and
chips? According to the AHA, these are the best and worst ultra-processed foods one can eat,
https://timesofindia.indiatimes.com/life-style/food-news/craving-some-burger-and-chips-accordin
g-to-the-aha-these-are-the-best-and-worst-ultra-processed-foods-one-can-eat/articleshow/1233
41410.cms

You might also like