|
| 1 | +# KT — Browser DevTools |
| 2 | + |
| 3 | +--- |
| 4 | + |
| 5 | +## What is DevTools? |
| 6 | + |
| 7 | +DevTools is a set of built-in developer tools in every modern browser (Chrome, Firefox, Edge). It lets you inspect everything that is happening inside the browser — the HTML structure, JavaScript errors, network requests, cookies, storage, and performance. |
| 8 | + |
| 9 | +Open it with: `F12` or `Right click → Inspect` |
| 10 | + |
| 11 | +--- |
| 12 | + |
| 13 | +## The Tabs — What Each One Is For |
| 14 | + |
| 15 | +| Tab | What it shows | When you use it | |
| 16 | +|---|---|---| |
| 17 | +| **Elements** | The live HTML/CSS of the page | Debugging layout, styles, DOM structure | |
| 18 | +| **Console** | JS errors, logs, run JS manually | Debugging JS, seeing `console.log()` output | |
| 19 | +| **Sources** | Your actual JS/CSS source files | Setting breakpoints, debugging JS step by step | |
| 20 | +| **Network** | Every HTTP request the browser makes | Debugging API calls, checking payloads, headers | |
| 21 | +| **Performance** | Page load and rendering timeline | Diagnosing slow pages | |
| 22 | +| **Memory** | JavaScript heap memory usage | Debugging memory leaks | |
| 23 | +| **Application** | Cookies, localStorage, sessionStorage | Inspecting stored data, clearing sessions | |
| 24 | +| **Security** | SSL certificate details | Checking HTTPS is valid | |
| 25 | + |
| 26 | +As a backend/full-stack developer, you will live in **Network** and **Console** 90% of the time. **Application** is useful for auth debugging (checking JWT tokens in storage). |
| 27 | + |
| 28 | +--- |
| 29 | + |
| 30 | +## Network Tab — Deep Dive |
| 31 | + |
| 32 | +### The request list (left side) |
| 33 | + |
| 34 | +When you open the Network tab and use your app, every HTTP request appears as a row. The columns: |
| 35 | + |
| 36 | +| Column | What it means | |
| 37 | +|---|---| |
| 38 | +| **Name** | Last segment of the URL path (explained below) | |
| 39 | +| **Status** | HTTP response code — 200, 401, 404, 500 | |
| 40 | +| **Type** | What kind of resource — fetch, xhr, document, script, img | |
| 41 | +| **Initiator** | What triggered this request | |
| 42 | +| **Size** | Response size (bytes) | |
| 43 | +| **Time** | Total time from request sent to response received | |
| 44 | +| **Waterfall** | Visual bar showing when this request happened relative to others | |
| 45 | + |
| 46 | +### Where the "Name" comes from |
| 47 | + |
| 48 | +The Name column shows the **last segment of the URL path**. It comes directly from the URL — you do not set it anywhere. |
| 49 | + |
| 50 | +``` |
| 51 | +URL: http://localhost/api/auth/login → Name: login |
| 52 | +URL: http://localhost/api/notes/ → Name: notes |
| 53 | +URL: http://localhost/ → Name: localhost |
| 54 | +URL: http://localhost/assets/index.js → Name: index.js |
| 55 | +``` |
| 56 | + |
| 57 | +If the name looks cryptic (like `index-Bx3kP9.js`), that is a hashed filename — the build tool (Vite/Webpack) adds a hash to the filename for cache busting. It is still just the last part of the URL. |
| 58 | + |
| 59 | +### Filters |
| 60 | + |
| 61 | +At the top of the Network tab you can filter by type: |
| 62 | +- **All** — everything |
| 63 | +- **Fetch/XHR** — only API calls (what you care about most) |
| 64 | +- **Doc** — HTML documents |
| 65 | +- **JS** — JavaScript files |
| 66 | +- **CSS** — stylesheets |
| 67 | +- **Img** — images |
| 68 | +- **Font** — fonts |
| 69 | +- **WS** — WebSocket connections |
| 70 | + |
| 71 | +For API debugging, always switch to **Fetch/XHR** so you only see your API calls. |
| 72 | + |
| 73 | +--- |
| 74 | + |
| 75 | +## When You Click a Request — The Sub-tabs |
| 76 | + |
| 77 | +### Headers |
| 78 | + |
| 79 | +Shows two things: |
| 80 | + |
| 81 | +**Request Headers** — what the browser sent to the server: |
| 82 | +``` |
| 83 | +Authorization: Bearer eyJhbGc... ← JWT token |
| 84 | +Content-Type: application/json ← telling server the body is JSON |
| 85 | +Host: localhost |
| 86 | +``` |
| 87 | + |
| 88 | +**Response Headers** — what the server sent back: |
| 89 | +``` |
| 90 | +X-Kong-Upstream-Latency: 4 ← time Kong spent waiting for FastAPI |
| 91 | +X-Kong-Proxy-Latency: 1 ← time Kong itself spent processing |
| 92 | +Content-Type: application/json |
| 93 | +``` |
| 94 | + |
| 95 | +### Payload |
| 96 | + |
| 97 | +Shows the **request body** — what the browser sent to the server. Only present for POST, PUT, PATCH requests. |
| 98 | + |
| 99 | +```json |
| 100 | +{ |
| 101 | + "username": "alice", |
| 102 | + "password": "secret123" |
| 103 | +} |
| 104 | +``` |
| 105 | + |
| 106 | +This is where you see the raw password during login (before TLS encrypts it on the wire). |
| 107 | + |
| 108 | +### Preview |
| 109 | + |
| 110 | +The **response body formatted** — JSON is shown as a collapsible tree. Easier to read than raw text. |
| 111 | + |
| 112 | +### Response |
| 113 | + |
| 114 | +The **raw response body** as text. Useful when Preview fails to format it correctly. |
| 115 | + |
| 116 | +### Initiator |
| 117 | + |
| 118 | +Shows **what triggered this request** — the call stack inside your JavaScript that led to this HTTP request being made. |
| 119 | + |
| 120 | +Example: |
| 121 | +``` |
| 122 | +app.js:47 fetch('/api/auth/login', ...) |
| 123 | +app.js:112 handleLoginSubmit() |
| 124 | +(anonymous) onClick event |
| 125 | +``` |
| 126 | + |
| 127 | +This tells you: the login button's onClick handler called `handleLoginSubmit()` on line 112, which called `fetch()` on line 47. Useful for tracing where a request comes from when you have a large codebase. |
| 128 | + |
| 129 | +### Timing |
| 130 | + |
| 131 | +Shows a **breakdown of time** spent on each phase of the request: |
| 132 | + |
| 133 | +| Phase | What it means | |
| 134 | +|---|---| |
| 135 | +| **Queueing** | Browser queued the request (waiting for a connection slot) | |
| 136 | +| **Stalled** | Request was ready but waiting to be sent | |
| 137 | +| **DNS Lookup** | Time to resolve the domain name to an IP | |
| 138 | +| **Initial connection** | TCP handshake — establishing the connection | |
| 139 | +| **SSL** | TLS handshake — encrypting the connection (HTTPS only) | |
| 140 | +| **Request sent** | Time to send the request bytes to the server | |
| 141 | +| **Waiting (TTFB)** | **Time To First Byte** — server is processing, you are waiting | |
| 142 | +| **Content Download** | Time to download the response body | |
| 143 | + |
| 144 | +**TTFB is the most important one.** If TTFB is high (hundreds of ms), your server is slow — database query is slow, or the server is under load. If Content Download is high, the response payload is large. |
| 145 | + |
| 146 | +--- |
| 147 | + |
| 148 | +## Console Tab |
| 149 | + |
| 150 | +Shows: |
| 151 | +- `console.log()` output from your JavaScript |
| 152 | +- JavaScript errors (in red) with file and line number |
| 153 | +- Network errors ("Failed to fetch", CORS errors) |
| 154 | +- Warnings (in yellow) |
| 155 | + |
| 156 | +You can also type JavaScript directly into the console and run it — useful for quick debugging. |
| 157 | + |
| 158 | +CORS errors always appear here first: |
| 159 | +``` |
| 160 | +Access to fetch at 'http://localhost/api/login' from origin 'http://localhost' |
| 161 | +has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header |
| 162 | +``` |
| 163 | + |
| 164 | +--- |
| 165 | + |
| 166 | +## Application Tab |
| 167 | + |
| 168 | +### localStorage |
| 169 | + |
| 170 | +Key-value storage in the browser that persists across page refreshes. Your frontend stores the JWT token here after login. |
| 171 | + |
| 172 | +``` |
| 173 | +Key: token |
| 174 | +Value: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... |
| 175 | +``` |
| 176 | + |
| 177 | +You can expand the token at jwt.io to read its contents. This is useful when debugging auth issues. |
| 178 | + |
| 179 | +### sessionStorage |
| 180 | + |
| 181 | +Same as localStorage but cleared when the browser tab is closed. |
| 182 | + |
| 183 | +### Cookies |
| 184 | + |
| 185 | +HTTP cookies set by the server. If your app used cookie-based sessions instead of JWT, you would see the session token here. |
| 186 | + |
| 187 | +--- |
| 188 | + |
| 189 | +## Practical Debugging Workflow |
| 190 | + |
| 191 | +**API call not working?** |
| 192 | +1. Open Network tab → filter by Fetch/XHR |
| 193 | +2. Find the failing request → check Status code |
| 194 | +3. Click it → check Payload (did the browser send the right data?) |
| 195 | +4. Check Response (what did the server return? Is there an error message?) |
| 196 | +5. Check Headers (is the Authorization header present?) |
| 197 | + |
| 198 | +**CORS error?** |
| 199 | +1. Open Console → read the full error message |
| 200 | +2. Open Network tab → find the OPTIONS preflight request |
| 201 | +3. Check Response Headers — is `Access-Control-Allow-Origin` present? |
| 202 | + |
| 203 | +**Slow API call?** |
| 204 | +1. Click the request → Timing tab |
| 205 | +2. Check TTFB — if high, server is slow |
| 206 | +3. Check Content Download — if high, response is too large |
| 207 | + |
| 208 | +**JWT token missing or expired?** |
| 209 | +1. Application tab → localStorage |
| 210 | +2. Find the token key — is it there? |
| 211 | +3. Copy the value → paste at jwt.io → check expiry |
0 commit comments