Flask Anatomy

7 min read
  • Application Setup: __init__.py
  • Application Assembly: main.py
  • Separate Demo: app.py
  • HTTP Interfaces: api/
  • User Endpoints: api/user.py
  • Persistence: model/
  • Jokes: HTTP Handler and File-Backed Data
  • Microblog: Authenticated API and Models
  • User Persistence: model/user.py
  • Database Reset: scripts/db_init.py
  • Backend Views: templates/
  • Backend Assets: static/
  • Runtime Data: instance/
  • API Checks: .http Request Files
  • Dependencies: requirements.txt
  • Deployment: Dockerfile
  • Backend Model Example

The Open Coding Society Flask starter is the backend beside your Pages frontend. The tree below shows selected files in that repository, not every feature. Follow a filename to its explanation.

Application Setup: __init__.py

This module creates the shared Flask application and configures extensions including SQLAlchemy, Flask-Login, CORS, and Flask-Migrate. It reads environment settings, including values loaded from your local .env. Keep secrets out of version control.

This starter uses a shared application object, not a create_app() factory. Its setup includes:

app = Flask(__name__)
db = SQLAlchemy(app)

The development server's default FLASK_PORT is 8587; an environment setting can override it. CORS settings determine which frontend origins may make browser requests with credentials.

Application Assembly: main.py

The main module imports the shared objects, imports API blueprints and model classes, registers the blueprints, and defines server-rendered routes. These are excerpts from that assembly, not replacement files:

from __init__ import app, db, login_manager
from api.user import user_api

app.register_blueprint(user_api)

For local development, activate the Flask repository's virtual environment and run the main module from that repository's root:

source venv/bin/activate
python main.py

Its development entry point uses the configured port, debug mode, and use_reloader=False. The Pages frontend runs separately; this command does not start Jekyll.

Separate Demo: app.py

The root app.py creates a different Flask application for an introductory example. It keeps an in-memory InfoModel, exposes /api/data, and defaults to port 5001 when run directly. It is not the full starter's entry point and does not replace the database-backed application assembled by main.py.

HTTP Interfaces: api/

API modules define blueprints and resource handlers. A handler reads a request, validates inputs and permissions, calls the model or other supporting logic, and returns an HTTP response. A module must be registered with the shared application before its routes are available.

Examples in this repository include user.py, section.py, post.py, and microblog_api.py. A filename is not itself a route: combine the blueprint's prefix with its registered resource path.

User Endpoints: api/user.py

The user blueprint has the prefix /api. Flask-RESTful resources add paths such as /authenticate, /id, and /user.

RequestPurpose
POST /api/authenticateAuthenticate and issue the authentication cookie.
GET /api/idRead the currently authenticated user's identity.
/api/userUser CRUD resource; input fields and permissions depend on the HTTP method.

The /login route in the main module serves the backend's HTML login flow. Do not confuse it with the JSON API's /api/authenticate endpoint.

Persistence: model/

The directory is named model, singular. Its modules define database-backed entities and operations. They use the shared db object rather than creating a separate database connection for every API request.

Keep HTTP request handling in API modules and persistence responsibilities in model modules. The same model can support both JSON APIs and server-rendered administration pages.

Jokes: HTTP Handler and File-Backed Data

The blueprint in hacks/joke.py uses the prefix /api/jokes. It calls functions in hacks/jokes.py, which store JSON under the configured data folder. Start with read-only GET /api/jokes/count and GET /api/jokes requests in REST Client, then trace the calls to countJokes() and getJokes().

This is a data layer without SQLAlchemy. Like and jeer requests change stored votes; the create handler is unfinished. Do not assume every registered operation has a complete implementation.

Microblog: Authenticated API and Models

The blueprint in api/microblog_api.py uses /api and registers the /microblog resource. Its CRUD handlers use token_required() and the MicroBlog and Topic classes from model/microblog.py.

After authenticating with the existing REST Client request, send GET /api/microblog?limit=5. Inspect the microblogs array and count field. Compare read filtering with the create handler's required content, 280-character limit, and optional topicId, topicPath, and data. Updates and deletes also check ownership or Admin permissions.

User Persistence: model/user.py

This module defines the user model and related persistence used by the starter. The API imports User from model.user. Read the actual model before choosing JSON field names or assuming a database column is called username.

Database Reset: scripts/db_init.py

Destructive operation: this script can back up, drop and recreate database tables, then seed data. It is not just a harmless db.create_all() helper. Do not run it against a database you need to preserve without checking the selected database, backup, and restore plan.

The script imports the assembled application's app, db, and generate_data from main. It performs schema operations inside an application context. Inspect its prompts and backup requirements with your teacher before resetting a development database.

Backend Views: templates/

Flask uses Jinja templates for server-rendered pages such as index.html, login.html, and u2table.html. For example, the main module's user-table route queries users and passes them to render_template("u2table.html", user_data=users).

These backend views are separate from the Pages site's Jekyll/Liquid templates. JSON API routes serve data to the Pages frontend; Jinja routes render HTML on the Flask server.

Backend Assets: static/

The current repository has static/assets/ and static/js/. Templates can reference these Flask-served assets. There is no root static/styles.css in this starter; check the actual asset directories before adding a stylesheet reference.

Runtime Data: instance/

Local SQLite data is stored under instance/volumes/, including user_management.db. Application configuration also creates upload and data directories under the instance folder. The database configuration can select MySQL when the required database environment settings are supplied. Treat runtime data and backups differently from source files.

API Checks: .http Request Files

Open api/user_auth.http and api/user_crud.http in VS Code with the REST Client extension. The repository's .vscode/settings.json defines shared and environment-specific baseUrl values. Select the local environment before testing; keep credentials out of committed settings.

Authenticate separately, then send CRUD requests one at a time using disposable development records. These files are manual checks, not an automated test suite. Updating or deleting other users requires the appropriate permissions, and requests sent to the deployed environment can change real data.

Use REST Client to compare the user, jokes, and microblog interfaces. Check method, URL, status, response fields, and expected failures before connecting the frontend. Browser-only CORS behavior still needs a browser integration check.

Follow the Flask API learning path: Jokes, Users, and Microblog. Each lesson traces requests into the corresponding data/model calls; detailed model and SQL work belongs in a separate series.

Dependencies: requirements.txt

Install the backend's Python dependencies into its own virtual environment from the Flask repository root:

source venv/bin/activate
pip install -r requirements.txt

Deployment: Dockerfile

The container starts Gunicorn with main:app, importing the assembled application. This differs from running Flask's debug development server. The repository also contains docker-compose.yml and Nginx configuration; review those deployment settings separately from the local startup workflow.

Key Components

  1. Frontend (Dining Area):
    • Customers (Users): Interact with the menu, place orders, and receive food.
    • Menu (User Interface): Displays the options available to customers (e.g., list of users, forms to add new users).
    • Order Form (Forms and Buttons): Allows customers to place orders (e.g., submit data).
  2. Backend API (Waiter):
    • Takes Orders (HTTP Requests): Receives requests from customers (frontend) and delivers them to the kitchen (backend).
    • Brings Food (HTTP Responses): Delivers the prepared food from the kitchen (backend) to the customers (frontend).
  3. Backend Model (Kitchen):
    • Chefs (Server-side Logic): Prepare the food (process data, perform operations) according to user input.
    • Order Processing (Endpoints): Different stations in the kitchen handle different tasks (e.g., fetching user data, adding new users).

Backend Model Example

The is a UML diagram. DRAW.io is also easy to use marketplace plugin to create a UML diagram for database planning. Create a UML diagram prior to creating a model file.

+---------------------+
|        User         |
+--------------------------------+
| - name: String                 |
| - uid: String                  |
| - password: String             |
| - sections: List<SectionID>    |
| - kasm_server_needed: Boolean  |
| - ProfilePicture: Base64 String|
+--------------------------------+
          |
          | 1
          |         (1 * repersents one to many)
          | *
+----------------------+
|      Section         |
+----------------------+
| - SectionID: Integer |
| - Abbreviation: String |
| - Name: String       |
+----------------------+

Computer Science Principles