When a browser page fails, “the API is broken” is a symptom label, not an explanation. A typical web request can pass through browser code, a network, a proxy or CDN, an application route, authorization checks, business logic, and a database. Any boundary can reject, change, delay, or fail the work.
This guide follows a hypothetical GET /api/projects/42 request. It is illustrative. Your architecture may use a service mesh, serverless function, gateway, or direct database access, but the method of tracing evidence still applies.
The path at a glance
Browser UI
│ fetch /api/projects/42
▼
DNS + connection + TLS, if applicable
▼
CDN / reverse proxy / API gateway
▼
Application route ── authenticate ── authorize ── validate
▼
Business logic / service
▼
Database or another service
│ result or error
▼
HTTP response → browser code → rendered page
HTTP describes requests and responses between a client and server. A browser page usually triggers several requests for its HTML, scripts, styles, images, and later API calls. Proxies and caches may sit between the browser and application. The diagram is a map; do not assume every deployment contains every layer.
Trace one request
1. Start in the browser
Open the browser’s Network panel, reproduce the action, and select the failing request. Record the method, path, status code, duration, request payload shape, response body, and any request or trace ID. Redact cookies, authorization headers, tokens, and personal data before sharing a screenshot or log.
Confirm whether the request was sent at all. A browser console exception can prevent it. A CORS error can block browser JavaScript from reading a response even when a server responded. A cached response or service worker can make the displayed result differ from a direct request.
2. Check routing and the edge
If the request left the browser, identify its host and environment. A wrong preview API URL may reach staging or an old deployment. A proxy may reject a request, enforce size limits, apply a redirect, or return a cached result. Use the response headers and request ID to tell whether the response came from the application or an upstream layer where your platform exposes that evidence.
3. Follow the application boundary
Find the route handler and trace in order:
- Authentication: who is making the request?
- Authorization: may this caller read project 42?
- Validation: is the path ID and query input well formed?
- Business rule: should this project be visible in this state?
- Data access: what query or service call runs, and what does it return?
- Response mapping: how does the handler convert success and failure into HTTP status and body?
Do not treat authentication and authorization as synonyms. A caller can be signed in but still lack permission to read a particular record. Also check whether the route’s error handler preserves meaningful client errors or converts every exception into a generic server error.
4. Compare the next boundary
For each boundary, write down expected input, actual input, expected output, and actual output. Use logs with a request ID to connect messages across services. Avoid broad logging; never record credentials, session cookies, payment details, or unnecessary personal information.
A realistic debugging example
A teammate reports that GET /api/projects/42 returns 500 on a new mobile client. The first assumption is that the database is overloaded because the endpoint reads a project. But the database metrics look normal, and the request ID has no matching query. The application log shows a validation exception before the service is called: the new client sends the identifier as project_id while the route expects the path segment. The database was not reached.
The next experiment is to send the same request shape from a safe test client and compare the route the server registered with the mobile request URL. Once the contract mismatch is confirmed, decide whether the client or server should change, add a contract or request test, and verify a valid and invalid identifier. Do not add database retries to a request that never reaches the database.
Interpret status codes with context
Status codes classify the response, not the root cause:
- 2xx: the server reports success; verify the body and intended side effect too.
- 3xx: the client may be redirected; inspect
Locationand redirect behavior. - 4xx: the request was not accepted as sent, often due to input, authentication, permission, or missing resource.
- 5xx: the server or an upstream component failed to fulfill the request; correlate logs and IDs to locate the source.
The exact choice of status depends on the API contract and security policy. For example, some systems deliberately avoid revealing whether a forbidden resource exists. Follow the product’s conventions and HTTP specification rather than relying on status numbers alone.
Checklist for an API failure
- Was the request sent to the expected host and environment?
- What method, path, status, duration, and request ID did it use?
- Did a proxy, cache, gateway, or browser policy affect the response?
- Which application boundary was reached before the first divergence?
- Were authentication, authorization, and validation checked separately?
- Does the request ID connect to a service or database log entry?
- Did I remove secrets and private data from evidence?
- Does a regression test cover the real request and its failure path?
Practice
Choose a read-only request in a local or safe test application. Trace the browser request to its route, permission check, service call, and response. Draw the boundaries and note the evidence available at each one. Then explain where you would start if the route returned 500 but there were no database log entry.