πŸ”Œ API Explainer

How API routes, functions, and the database all connect

This explainer traces how a single API call β€” GET /api/entries β€” travels from the browser all the way to the database and back. Along the way you'll learn what an API endpoint really is, where the code lives, how memory is involved, and how the db object acts as the bridge between Flask and the database.
πŸ“‘
What is an API endpoint?
URLs that return data, not webpages
β–Ό

A URL like /entries returns an HTML webpage. A URL like /api/entries returns raw data β€” usually JSON. The /api/ prefix is just a naming convention. It has no special meaning to Flask, no folder on disk, and no section in memory. It's purely a signal to developers that "this URL gives you data, not a page."

Page route

/entries
Returns entries.html β€” a full webpage the browser renders for the user.

API route

/api/entries
Returns [{"id":1,"content":"..."},...] β€” JSON data that JavaScript uses.

This app has 72 routes total β€” 35 page routes and 37 API routes β€” all defined in the single file app.py.

πŸ—ΊοΈ
The URL map
How Flask knows which function to call
β–Ό

When the Flask app starts up, it reads every @app.route decorator in app.py and builds an internal URL map β€” a dictionary that maps URL patterns + HTTP methods to Python functions. It lives in RAM for the entire lifetime of the process.

Flask URL map (in memory at runtime):
  "GET  /"                 β†’ spa()
  "GET  /api/entries"      β†’ get_entries()
  "POST /api/entries"      β†’ add_entry()
  "PUT  /api/entries/<id>" β†’ update_entry()
  "DELETE /api/entries/<id>" β†’ delete_entry()
  ... 68 more entries ...

Each value in the map is a reference to a Python function object stored on the heap. When a request arrives, Flask looks up the URL and method, finds the function reference, and calls it.

🧠
Where does the function live in memory?
Heap, stack, and code segments
β–Ό

When Python loads app.py, it compiles each function to bytecode and stores a function object on the heap. If you print the function you see its address:

<function get_entries at 0x7f3a1b2c>

0x7f3a1b2c is a real address in RAM β€” it changes every time the process restarts because Python allocates wherever there is free space.

Memory region What's stored there
Heap The function object itself (name, bytecode reference, default args). Lives here for the whole process.
Code segment The compiled bytecode instructions that the function runs.
Stack Local variables (like entries, start_date) β€” only exist while the function is actively running, then gone.
πŸ”
The get_entries() function β€” line by line
app.py lines 766–774
β–Ό
@app.route('/api/entries', methods=['GET']) def get_entries(): """API endpoint to get entries""" start_date = request.args.get('start_date') # from URL ?start_date=2026-01-01 end_date = request.args.get('end_date') limit = request.args.get('limit', type=int) entries = db.get_entries(start_date, end_date, limit) # calls database.py return jsonify(entries) # converts to JSON
  • Line 1: The decorator registers this function into the URL map for GET /api/entries.
  • Lines 4–6: request.args.get() parses optional parameters out of the URL query string. If not present, they are None.
  • Line 8: Calls a method on the db object β€” this is where the SQL actually runs.
  • Line 9: jsonify() converts the Python list of dicts into a JSON string and sets the correct HTTP Content-Type header.
πŸ”—
URL parameters
How the browser passes filters to the function
β–Ό

A URL can carry parameters after a ? β€” called the query string. Flask parses these automatically and makes them available via request.args.

URL: /api/entries?start_date=2026-01-01&limit=50

β†’ request.args.get('start_date') gives "2026-01-01"
β†’ request.args.get('end_date') gives None (not in URL)
β†’ request.args.get('limit', type=int) gives 50

All three values are then passed straight into db.get_entries() as arguments, where they become filters in the SQL WHERE clause.

πŸ—„οΈ
The db object
One Database instance shared by every route
β–Ό

At the top of app.py, one Database object is created:

db = Database() # created once at startup, lives for the whole process

Every route function shares this single db object. The Database class lives in database.py and knows whether it's running against SQLite (local dev) or PostgreSQL (Heroku), and adjusts its SQL accordingly.

  • db.get_entries() β€” SELECT, returns list of dicts
  • db.add_entry() β€” INSERT, returns new row id
  • db.update_entry() β€” UPDATE, modifies existing row
  • db.delete_entry() β€” DELETE, removes row by id
  • Similar method pairs exist for photos, family history, summaries, phone registrations
πŸ”„
The full round trip
Browser β†’ Flask β†’ database β†’ browser
β–Ό
1
Browser JavaScript calls fetch('/api/entries?limit=50')
2
Flask receives the HTTP GET request and looks up /api/entries in its URL map
3
Flask calls get_entries() in app.py (line 767)
4
request.args.get('limit') extracts 50 from the URL
5
db.get_entries(None, None, 50) is called β€” this runs SQL against the database
6
The database returns a list of Python dicts: [{"id":1,"content":"...","pain_level":3}, ...]
7
jsonify(entries) converts the list to a JSON string
8
Flask sends the JSON back to the browser as an HTTP 200 response
9
The JavaScript await res.json() parses it and the page renders the entries
Two layers of code: app.py handles the HTTP request/response. database.py handles the SQL. The route function is the glue between them.
πŸ“‚
app.py vs database.py β€” who does what?
Separation of concerns
β–Ό
File Responsibility Example
app.py Handle HTTP: read URL params, call db or external services, return JSON/HTML get_entries() reads the URL, calls db, returns jsonify()
database.py Run SQL: build queries, talk to SQLite or PostgreSQL, return Python data structures db.get_entries() builds SELECT, runs it, returns list of dicts

This separation means you could swap out the database engine (e.g. replace PostgreSQL with MySQL) by only changing database.py β€” none of the route functions in app.py would need to change. This is called the Repository Pattern.

← Back to All Quizzes