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.
Step 4: Restrict CORS (Optional but Recommended)
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
- Your mobile app sends a request to the backend
- The browser (or Expo) checks if the response has an
Access-Control-Allow-Originheader - If the header matches the app's origin, the request is allowed
- 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
- Backend is running
curl -IshowsAccess-Control-Allow-Origin: *curl /api/healthshows database connected- Pre-commit hooks run before every commit
- Your mobile app can now connect to the backend (we'll test this in the mobile section)