Premier League Predictor: FastAPI & PostgreSQL — Chapter 12, Exercise 3 ==================================================== TASK Explain why the tag fix works without ever needing to change on the localhost:8000 version of the app, tracing the explanation back to how a browser resolves a relative URL. SOLUTION A browser resolves a relative URL (one with no leading slash, like fetch('api/seasons')) against the document's own "base URL." By default, that base URL is simply the URL of the page itself, up to and including its own final path segment being dropped in favor of the directory it lives in. The tag exists specifically to override that default and tell the browser to use a different base URL instead, for every relative URL resolution on that page — links, scripts, and fetch() calls alike. On the deployed version, mounted at /predictor/, the page is loaded from something like https://example.com/predictor/index.html, and the explicit tag tells the browser to resolve every relative path against /predictor/ specifically, so fetch('api/seasons') becomes https://example.com/predictor/api/seasons — correctly routed through nginx's own /predictor/ location block. On localhost, the app is already served from the root — http://localhost:8000/index.html. With no tag present at all, the browser falls back to its own default behavior: resolving a relative URL against the current page's own location, which is already http://localhost:8000/. fetch('api/seasons') resolves to http://localhost:8000/api/seasons — exactly the correct URL, with zero configuration needed, because the default base URL the browser would have used anyway already happens to be the site root. In other words: the tag doesn't change how relative URL resolution works — it only overrides WHERE that resolution starts from. Since localhost's own default starting point (the page's own actual location) is already correct, there's nothing for a tag to override there; it's only needed once the real starting point (the deployed page's own sub-path location) diverges from what the app was originally written assuming. WHY THIS WORKS AS AN ANSWER ---------------------------- It explains the real browser mechanism (relative URLs resolve against a base URL, which defaults to the current page's own location unless overridden), and traces precisely why that default already produces the correct result on localhost while needing an explicit override once the app is genuinely mounted somewhere other than the root.