Calling a Flask API from JS returns Unexpected token '

1 day ago 2
ARTICLE AD BOX

The error Unexpected token '<', "<!DOCTYPE "... is not valid JSON is a classic issue. It simply means your fetch call expects a JSON response, but your server is returning an HTML page (which starts with <!DOCTYPE html>).

In your specific case, this happens because the API request is missing its target route, falling through to your catch-all route (@app.route('/<path:path>')), which then successfully serves index.html with a 200 OK status.

The root cause is how cPanel (Phusion Passenger) handles routing compared to your localhost environment.

Here is how to fix it:

1. Fix the Blueprint Prefix (The Passenger Environment Issue)

When you host a Python app on cPanel, it usually runs via Phusion Passenger. If you configured the app in cPanel to be served at the URI /lawaiapp, Passenger strips this base URI before passing the request to Flask.

So, when your JS fetches https://domain/lawaiapp/api/users:

Localhost sees: /lawaiapp/api/users (Matches your blueprint perfectly).

cPanel/Flask sees: /api/users.

Because your blueprint is registered with url_prefix='/lawaiapp/api', Flask doesn't find a match for /api/users, falls back to your <path:path> route, and serves index.html.

The Fix: Change your blueprint registration to remove the app sub-directory: # Change this: # app.register_blueprint(user_bp, url_prefix='/lawaiapp/api') # To this: app.register_blueprint(user_bp, url_prefix='/api')

(Make sure your JS API_BASE_URL still points to the full URL https://domain/lawaiapp/api/users).

2. Protect API Routes from the Catch-All (Best Practice)

To prevent this headache in the future, your catch-all route should not serve index.html for missing API endpoints. If an API route is completely wrong, it should return a standard JSON 404, not an HTML file.

Update your catch-all function to fail fast on API calls:

@app.route('/', defaults={'path': ''}) @app.route('/<path:path>') def serve(path): # Guard clause: Do not serve HTML for API requests if path.startswith('api/'): return {"error": "API endpoint not found"}, 404 static_folder_path = app.static_folder if static_folder_path is None: return "Static folder not configured", 404 if path != "" and os.path.exists(os.path.join(static_folder_path, path)): return send_from_directory(static_folder_path, path) else: index_path = os.path.join(static_folder_path, 'index.html') if os.path.exists(index_path): return send_from_directory(static_folder_path, 'index.html') else: return "index.html not found", 404

3. Check your .htaccess (If the above doesn't work)

If the Flask app isn't receiving the request at all, ensure your .htaccess inside the public_html/lawaiapp (or wherever the document root is pointing) is correctly configured by cPanel to pass requests to Passenger. Usually, cPanel generates this automatically when you create a "Python App" in the dashboard. It should contain directives like PassengerEnabled on and PassengerAppRoot. If you manually created an .htaccess with RewriteRules, temporarily disable it to see if cPanel's default Passenger routing takes over.

Read Entire Article