From the browser to the server and back—APIs, CORS, auth, and patterns that keep the stack coherent.
From the browser to the server and back—APIs, CORS, auth, and patterns that keep the stack coherent.
Lesson outline
The frontend (browser) and backend (server) do not share memory or a direct connection. They communicate only over HTTP (or HTTPS): the browser sends a request (method, URL, headers, optional body); the server responds with a response (status, headers, body). So "integration" means: the frontend builds the right request (URL, method, headers, body), and the backend understands it and returns the right response. Everything else (REST, GraphQL, gRPC in the browser) is a convention on top of HTTP.
Same-origin vs cross-origin: If the frontend is at `https://app.example.com` and the API is at `https://api.example.com`, that is cross-origin. Browsers restrict cross-origin requests unless the server sends CORS headers (e.g. `Access-Control-Allow-Origin`) allowing it. So the backend must be configured to allow requests from your frontend origin (or from a list of allowed origins). Without CORS, the browser blocks the response from reaching your JS.

REST (Representational State Transfer) is a set of conventions: resources as URLs (`/api/users`, `/api/users/123`), HTTP methods for meaning (GET = read, POST = create, PUT/PATCH = update, DELETE = delete), and status codes (200 OK, 201 Created, 404 Not Found, 401 Unauthorized). The frontend uses `fetch` or a client (axios, etc.) to call these URLs with the right method and body (often JSON).
Contract: Frontend and backend must agree on request/response shape. Many teams use OpenAPI (Swagger) to document the API; some generate types (TypeScript, etc.) from it so the frontend knows exactly what to send and what to expect. That reduces bugs and makes refactors safer.
The backend needs to know *who* is making the request. The frontend typically sends credentials in the request: a cookie (set by the server after login, sent automatically with same-origin requests) or an Authorization header (e.g. `Bearer <token>` for JWT). The backend validates the cookie or token and loads the user (or returns 401).
Cookie vs token: Cookies are managed by the browser and sent only to the same site (or configured domains). Good for web-only apps. Tokens (JWT) are often stored in memory or localStorage and sent in the header; the frontend must attach them to every API call. Tokens work well for SPAs and for mobile or third-party clients that cannot use cookies. The backend must accept whichever you use and validate it consistently.
Request path: client → middleware → backend → data
Client
Browser / app sends request
Middleware
Auth, CORS, rate limit, logging
Backend
Routes, handlers, business logic
Data
DB, cache, external APIs
Middleware runs before your route handlers — auth and CORS are checked first
The frontend should handle loading (show a spinner or skeleton while the request is in flight), success (render data or navigate), and error (show a message, retry, or fallback). Check `response.ok` or status code; parse error bodies if the API returns JSON errors. Do not assume every request succeeds; networks and servers fail.
The backend should return consistent error shapes (e.g. `{ code, message }`) and appropriate status codes so the frontend can distinguish "not found" from "unauthorized" from "server error" and act accordingly.
User logs in → frontend sends POST /api/login with credentials → backend validates, returns token or sets cookie. User opens "My orders" → frontend sends GET /api/orders with Authorization header (or cookie) → backend verifies token, loads orders from DB, returns JSON → frontend renders list. User clicks "Cancel" → frontend sends DELETE /api/orders/123 with auth → backend checks ownership, updates DB, returns 200 → frontend removes item from UI or refetches. Every step is a request and response; the backend never "pushes" to the client unless you add WebSockets or SSE.
End-to-end: frontend to backend and back
Browser
User action → HTTP request (fetch / form)
→Network
HTTPS: URL, method, headers, body
→Server
Route → handler → logic
→Database
Query or write (if needed)
→Response
Status, body → browser updates UI
One request, one response — the same cycle for every API call
The backend must never trust the client for anything that affects security or correctness. That includes: identity (always validate the token or cookie), ownership (check that the user can access the resource), and input (validate and sanitize every field). A malicious user can open DevTools and send arbitrary requests to your API; if the backend relies on "the frontend would never send that," you have a vulnerability.
Defense in depth: Validate on the client for UX (instant feedback), but always validate again on the server. Use rate limiting and CSRF protection where applicable. Log auth failures and suspicious patterns. Full stack integration is not just "frontend calls API"; it is "backend enforces the rules no matter who is calling."
Contract tests: Ensure the API returns the shape the frontend expects (status, body schema). You can write tests that call the API with sample requests and assert on the response; or use OpenAPI to generate and run contract tests. E2E tests: Use a browser automation tool (Playwright, Cypress) to log in, trigger an action that hits the API, and assert the UI updates. That catches integration bugs (wrong URL, missing auth header, CORS) that unit tests miss. Run these in CI so changes to either side do not break the contract.
Ready to see how this works in the cloud?
Switch to Career Paths for structured paths (e.g. Developer, DevOps) and provider-specific lessons.
View role-based pathsSign in to track your progress and mark lessons complete.
Questions? Discuss in the community or start a thread below.
Join DiscordSign in to start or join a thread.