Backend Step 6: CORS

Enable your mobile app to connect to the backend by configuring CORS.

What You'll Learn

  • What CORS is and why it exists
  • How to enable CORS in Flask
  • Restricting CORS for security

Step 1: What is CORS?

CORS (Cross-Origin Resource Sharing) is a browser security feature. It prevents a web page from one origin (e.g., http://localhost:8081) from making requests to a different origin (e.g., http://localhost:5000).

In this project: - Your React Native app runs on http://localhost:8081 (Expo dev server) - Your Flask backend runs on http://localhost:5000 - These are different origins (different ports), so the browser blocks the request

React Native note: On a real device, CORS doesn't apply the same way. But the Expo dev server runs in a browser-based environment where CORS matters.

Step 2: Install flask-cors

If you already installed it in Step 1, you're good. If not:

pip install flask-cors

Step 3: Update init.py

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_cors import CORS
from dotenv import load_dotenv

load_dotenv()

db = SQLAlchemy()


def create_app():
    app = Flask(__name__)
    app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///chat.db"
    app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False

    CORS(app)

    db.init_app(app)

    from .routes import api
    app.register_blueprint(api, url_prefix="/api")

    with app.app_context():
        db.create_all()

    return app


if __name__ == "__main__":
    app = create_app()
    app.run(debug=True, port=5000)

The single line CORS(app) enables CORS for all origins, all methods, all headers.

Instead of allowing any origin, restrict to your mobile app:

CORS(app, origins=["http://localhost:8081", "http://localhost:19006", "exp://192.168.1.100:19000"])

Step 5: Test CORS

cd aiproject/backend
source venv/bin/activate
python app/__init__.py

Check the headers:

curl -I http://127.0.0.1:5000/api/status

Look for this header in the response:

Access-Control-Allow-Origin: *

How CORS Works

  1. Your mobile app sends a request to the backend
  2. The browser (or Expo) checks if the response has an Access-Control-Allow-Origin header
  3. If the header matches the app's origin, the request is allowed
  4. If not, the browser blocks the request

CORS(app) automatically adds this header to every response.

Step 6: Add Monitoring

A production app needs observability — you need to know what's happening. Add a health endpoint that checks the database and tracks metrics.

Health Endpoint

Add to backend/app/__init__.py:

@app.route("/api/health")
def health():
    db_ok = False
    try:
        with app.app_context():
            db.session.execute(db.text("SELECT 1"))
            db_ok = True
    except Exception:
        db_ok = False
    return jsonify({
        "status": "ok",
        "version": "1.0.0",
        "database": "connected" if db_ok else "disconnected",
        "metrics": get_metrics(),
    })

Test it:

curl http://127.0.0.1:5000/api/health
# → {"status":"ok","version":"1.0.0","database":"connected","metrics":{...}}

Metrics Endpoint

The /api/metrics endpoint tracks request counts. Add to backend/app/metrics.py:

_request_count = 0

def track_request(response):
    global _request_count
    _request_count += 1
    return response

def register_metrics(app):
    app.after_request(track_request)

    @app.route("/api/metrics")
    def metrics():
        return jsonify({"total_requests": _request_count})

Now every request increments the counter. Visit /api/metrics to see how many requests your server has handled.

Structured Logging

Instead of print() statements, use structured logging. Add to backend/app/logging_config.py:

import logging
import sys

def setup_logging():
    logger = logging.getLogger("aiproject")
    logger.setLevel(logging.INFO)
    handler = logging.StreamHandler(sys.stdout)
    handler.setFormatter(logging.Formatter(
        "%(asctime)s [%(levelname)s] %(message)s"
    ))
    logger.addHandler(handler)
    return logger

Then in routes.py:

logger = logging.getLogger("aiproject")
logger.info("Chat completed: user_msg=%s ai_msg=%s", user_msg.id, ai_msg.id)

Logs show up with timestamps:

2026-05-04 14:30:22 [INFO] Chat completed: user_msg=5 ai_msg=6

Step 7: Set Up Pre-Commit Hooks

Pre-commit hooks automatically run checks before every git commit. If a check fails, the commit is blocked — this prevents bad code from entering your repository.

Install pre-commit:

pip install pre-commit

Install the hooks in your repo:

cd aiproject
pre-commit install

Now every time you run git commit, pre-commit runs: 1. ruff — lint your code 2. ruff-format — auto-format your code 3. Check for trailing whitespace 4. Check for missing newlines at end of files

Try it:

git add .
git commit -m "Test pre-commit hooks"

If ruff finds an issue, the commit is blocked. Fix the issue and try again.

Verification

  1. Backend is running
  2. curl -I shows Access-Control-Allow-Origin: *
  3. curl /api/health shows database connected
  4. Pre-commit hooks run before every commit
  5. Your mobile app can now connect to the backend (we'll test this in the mobile section)