<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[All About Computers - Medium]]></title>
        <description><![CDATA[A hub for everything Computers! Dive into tutorials, tips, projects, and insights on hardware, software, operating systems, programming, networking, cybersecurity, AI, and everything in between — curated for tech enthusiasts by tech enthusiasts. - Medium]]></description>
        <link>https://medium.com/me-n-stack-development?source=rss----cbe80062d41f---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>All About Computers - Medium</title>
            <link>https://medium.com/me-n-stack-development?source=rss----cbe80062d41f---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Thu, 05 Nov 2026 04:11:52 GMT</lastBuildDate>
        <atom:link href="https://medium.com/feed/me-n-stack-development" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Your API Works Fine Until 10,000 Users Arrive. Then What?]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/me-n-stack-development/your-api-works-fine-until-10-000-users-arrive-then-what-65d39bc00c6a?source=rss----cbe80062d41f---4"><img src="https://cdn-images-1.medium.com/max/1536/1*fScyrPgRCNpz-A_ARjf5lQ.png" width="1536"></a></p><p class="medium-feed-snippet">How connection pools, database bottlenecks, concurrency, and downstream dependencies turn a healthy API into a production incident.</p><p class="medium-feed-link"><a href="https://medium.com/me-n-stack-development/your-api-works-fine-until-10-000-users-arrive-then-what-65d39bc00c6a?source=rss----cbe80062d41f---4">Continue reading on All About Computers »</a></p></div>]]></description>
            <link>https://medium.com/me-n-stack-development/your-api-works-fine-until-10-000-users-arrive-then-what-65d39bc00c6a?source=rss----cbe80062d41f---4</link>
            <guid isPermaLink="false">https://medium.com/p/65d39bc00c6a</guid>
            <category><![CDATA[backend-development]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[coding]]></category>
            <dc:creator><![CDATA[Gopi C K]]></dc:creator>
            <pubDate>Wed, 04 Nov 2026 12:51:12 GMT</pubDate>
            <atom:updated>2026-11-04T12:51:12.778Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[How to Design a Real-Time Messaging System: 7 Architecture Decisions Behind Reliable Chat Apps]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/me-n-stack-development/how-to-design-a-real-time-messaging-system-7-architecture-decisions-behind-reliable-chat-apps-26d7ab53f327?source=rss----cbe80062d41f---4"><img src="https://cdn-images-1.medium.com/max/1672/1*t6HsK7EsKN8PhCU8AmYGmQ.png" width="1672"></a></p><p class="medium-feed-snippet">A practical system design guide covering WebSockets, message delivery, ordering, queues, offline messaging, and database architecture.</p><p class="medium-feed-link"><a href="https://medium.com/me-n-stack-development/how-to-design-a-real-time-messaging-system-7-architecture-decisions-behind-reliable-chat-apps-26d7ab53f327?source=rss----cbe80062d41f---4">Continue reading on All About Computers »</a></p></div>]]></description>
            <link>https://medium.com/me-n-stack-development/how-to-design-a-real-time-messaging-system-7-architecture-decisions-behind-reliable-chat-apps-26d7ab53f327?source=rss----cbe80062d41f---4</link>
            <guid isPermaLink="false">https://medium.com/p/26d7ab53f327</guid>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[software-engineering]]></category>
            <dc:creator><![CDATA[Gopi C K]]></dc:creator>
            <pubDate>Fri, 30 Oct 2026 11:20:44 GMT</pubDate>
            <atom:updated>2026-10-30T11:20:44.224Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[Your API Works in Postman. Why Is Your Frontend Still Broken?]]></title>
            <link>https://medium.com/me-n-stack-development/your-api-works-in-postman-why-is-your-frontend-still-broken-5d03d186497f?source=rss----cbe80062d41f---4</link>
            <guid isPermaLink="false">https://medium.com/p/5d03d186497f</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[backend-development]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[technology]]></category>
            <dc:creator><![CDATA[Tech for Her]]></dc:creator>
            <pubDate>Tue, 27 Oct 2026 14:45:44 GMT</pubDate>
            <atom:updated>2026-10-27T14:45:43.628Z</atom:updated>
            <content:encoded><![CDATA[<h4><em>Understanding CORS, headers, authentication, and browser debugging through a real-world JavaScript example.</em></h4><p>There is a particular kind of frustration that comes with web development.</p><p>You build an API request in Postman. It works perfectly. You get a 200 OK, the response contains exactly the data you expected, and for a brief moment, you feel like everything is finally under control.</p><p>Then you open your frontend, click the button that should fetch the same data, and… nothing.</p><p>Maybe the browser console shows a CORS error. Maybe the request returns 401 Unauthorized. Maybe the response is perfectly valid, but your UI still displays an empty list. And sometimes, the request doesn&#39;t even reach your backend.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bpvNApzkXHRPuJlg7YCewg.png" /><figcaption>AI Generated Image</figcaption></figure><p>My first instinct in situations like this is usually to check the backend again. After all, if the API works in Postman, surely the frontend must be doing something strange.</p><p>Well, sometimes it is. But the interesting part is that <strong>an API working in Postman doesn’t guarantee that the same request will work in a browser.</strong></p><p>Postman and browsers operate under different rules. They don’t necessarily send identical requests, they handle authentication differently depending on configuration, and browsers enforce security restrictions that Postman generally doesn’t enforce in the same way.</p><p>Once you understand those differences, debugging API requests becomes much less like guessing and much more like solving a problem systematically.</p><p>Let’s walk through the issues I would investigate first.</p><h3>1. Start by Comparing the Actual Requests</h3><p>Imagine Kapi is building a small dashboard that fetches a list of users from an API.</p><p>The request works in Postman:</p><pre>GET https://api.example.com/users</pre><p>The server returns:</p><pre>{<br>  &quot;users&quot;: [<br>    {<br>      &quot;id&quot;: 1,<br>      &quot;name&quot;: &quot;Kapi&quot;<br>    },<br>    {<br>      &quot;id&quot;: 2,<br>      &quot;name&quot;: &quot;Alex&quot;<br>    }<br>  ]<br>}</pre><p>Everything looks good. So Kapi writes the following JavaScript:</p><pre>async function getUsers() {<br>  const response = await fetch(<br>    &quot;https://api.example.com/users&quot;<br>  );<br>const data = await response.json();<br>  console.log(data);<br>}<br>getUsers();</pre><p>But when she runs the frontend, the request fails.</p><p>Before rewriting the function or changing anything on the backend, I would open the browser’s Developer Tools and inspect the request.</p><p>In Chrome, you can usually open Developer Tools with F12 or Ctrl + Shift + J on Windows and Linux, or Cmd + Option + J on macOS. Select the <strong>Network</strong> tab, reload the page, and click the failed request. The exact shortcuts can vary by browser and operating system.</p><p>Look at the request URL, HTTP method, status code, request headers, response headers, and response body. Also check the Console tab for browser security errors.</p><p>This gives you something much more useful than a vague message saying the API doesn’t work: evidence of what the browser actually attempted to do.</p><p>I like to compare that request with the successful Postman request. Are the URLs identical? Is the same HTTP method being used? Are the headers present? Is the same token being sent? Is the browser following the same authentication flow?</p><p>These questions help narrow the problem before you touch a single line of code.</p><h3>2. The CORS Error That Makes You Question Everything</h3><p>Let’s start with one of the most common problems in frontend development: CORS.</p><p>CORS stands for Cross-Origin Resource Sharing. It’s a browser security mechanism that controls whether JavaScript running on one origin is allowed to access a response from another origin.</p><p>An origin consists of the scheme, host, and port. For example, these are different origins:</p><ul><li><a href="http://localhost:3000">http://localhost:3000</a></li><li><a href="http://localhost:5000">http://localhost:5000</a></li><li><a href="https://api.example.com">https://api.example.com</a></li></ul><p>Even though the first two use localhost, their ports differ, so they are considered separate origins.</p><p>Suppose your React application runs at:</p><pre>http://localhost:3000</pre><p>And your backend runs at:</p><pre>http://localhost:5000</pre><p>Your frontend sends a request:</p><pre>fetch(&quot;http://localhost:5000/users&quot;);</pre><p>The browser checks whether the backend’s response permits the frontend’s origin. If the required CORS headers are missing or don’t match, the browser prevents frontend JavaScript from accessing the response.</p><p>This is where things get confusing.</p><p>The backend might successfully receive the request and generate a perfectly valid response. Yet the browser still refuses to expose that response to your application.</p><p>Postman, on the other hand, doesn’t enforce browser CORS rules in the same way. That’s why the same endpoint can work in Postman and fail in your frontend.</p><h3>How do you fix it?</h3><p>Usually, you need to configure CORS on the server or through the server’s gateway or reverse proxy.</p><p>For example, an Express application using the cors package might look like this:</p><pre>import express from &quot;express&quot;;<br>import cors from &quot;cors&quot;;<br>const app = express();<br>app.use(cors({<br>  origin: &quot;http://localhost:3000&quot;<br>}));<br>app.get(&quot;/users&quot;, (req, res) =&gt; {<br>  res.json({<br>    users: [<br>      { id: 1, name: &quot;Kapi&quot; },<br>      { id: 2, name: &quot;Alex&quot; }<br>    ]<br>  });<br>});<br>app.listen(5000, () =&gt; {<br>  console.log(&quot;Server running on port 5000&quot;);<br>});</pre><p>Here, the server permits browser requests from the specified frontend origin. In a real application, you should configure the allowed origins for your deployment environments rather than blindly copying development settings into production.</p><p>Some requests trigger a <strong>preflight request</strong>, which uses the OPTIONS method. This happens when the browser needs permission to send a cross-origin request with certain methods or headers.</p><p>For example, a request containing an Authorization header or a custom header commonly triggers a preflight.</p><p>The browser might send something like:</p><pre>OPTIONS /users HTTP/1.1<br>Origin: http://localhost:3000<br>Access-Control-Request-Method: GET<br>Access-Control-Request-Headers: authorization</pre><p>The server must respond with appropriate CORS headers allowing the requested origin, method, and headers.</p><p>If the preflight fails, the browser may never send the actual request.</p><p>One important detail: <strong>CORS is not a replacement for authentication or authorization.</strong> It controls browser access to cross-origin responses; it does not stop a client such as Postman or a server-side script from calling a publicly reachable endpoint.</p><p>Also, don’t try to fix CORS by disabling browser security. Configure the server correctly.</p><h3>3. Your Frontend Is Missing an Authentication Header</h3><p>Here’s another situation I’ve run into more than once.</p><p>The endpoint works perfectly in Postman, but the browser returns:</p><pre>401 Unauthorized</pre><p>At first, it looks like the backend is rejecting a valid request for no reason.</p><p>But when you inspect Postman’s request headers, you notice something important:</p><pre>Authorization: Bearer YOUR_ACCESS_TOKEN</pre><p>Postman is sending an access token. Your frontend isn’t.</p><p>The backend isn’t behaving inconsistently. You’re simply making two different requests.</p><p>If an API requires a bearer token, your frontend might need to send it like this:</p><pre>async function getUsers(accessToken) {<br>  const response = await fetch(<br>    &quot;https://api.example.com/users&quot;,<br>    {<br>      headers: {<br>        Authorization: `Bearer ${accessToken}`<br>      }<br>    }<br>  );<br>if (!response.ok) {<br>    throw new Error(<br>      `Request failed: ${response.status}`<br>    );<br>  }<br>  return response.json();<br>}</pre><p>The token in this example should come from your application’s actual authentication flow. Don’t hardcode a real secret or access token into source code that will be shipped to the browser.</p><p>There is another important distinction here: a 401 usually means authentication is missing or invalid, while a 403 generally means the server understood the request but refuses to authorize the operation. Exact conventions depend on the API, but the distinction is useful when debugging.</p><p>Also, if your application uses cookie-based authentication rather than bearer tokens, the solution can be different. Cross-origin fetch() requests don&#39;t include credentials by default. You may need:</p><pre>fetch(&quot;https://api.example.com/users&quot;, {<br>  credentials: &quot;include&quot;<br>});</pre><p>For cross-origin cookie-based requests, the server must also configure credentialed CORS correctly, including a specific allowed origin rather than *, and return Access-Control-Allow-Credentials: true. Cookie attributes and browser privacy policies can affect whether the cookie is sent, too.</p><p>The key is to understand which authentication mechanism your backend expects instead of adding random headers until the request starts working.</p><h3>4. A Successful Response Doesn’t Always Mean Your Code Is Correct</h3><p>Sometimes the request succeeds, but the frontend still breaks.</p><p>This is arguably more annoying because the Network tab shows 200 OK, and you start wondering whether the browser is playing a prank on you.</p><p>Consider this example:</p><pre>async function getUsers() {<br>  const response = await fetch(<br>    &quot;https://api.example.com/users&quot;<br>  );<br>const data = await response.json();<br>  console.log(data.name);<br>}</pre><p>Suppose the server returns:</p><pre>{<br>  &quot;users&quot;: [<br>    { &quot;id&quot;: 1, &quot;name&quot;: &quot;Kapi&quot; },<br>    { &quot;id&quot;: 2, &quot;name&quot;: &quot;Alex&quot; }<br>  ]<br>}</pre><p>The request succeeds. The JSON parses successfully. But data.name is undefined because name isn&#39;t a property at the top level of the response.</p><p>The names are inside the users array.</p><p>The correct code would be:</p><pre>async function getUsers() {<br>  const response = await fetch(<br>    &quot;https://api.example.com/users&quot;<br>  );<br>const data = await response.json();<br>  console.log(data.users);<br>}</pre><p>This is a simple example, but response-shape mismatches are common in real applications. Your frontend might expect an array while the backend returns an object containing an array. A property might be named userId rather than id. An API might return null for a field you assumed would always exist.</p><p>This is why I prefer inspecting the actual response body before changing the UI code.</p><p>Don’t assume that the response matches your mental model just because the status code is successful.</p><p>And remember that fetch() generally rejects for network-level failures, not for HTTP error statuses such as 404 or 500. You need to check response.ok if you want those statuses to become application errors.</p><h3>5. The Request Is Failing, but Your Error Handling Is Hiding the Real Problem</h3><p>Let’s say your frontend contains this code:</p><pre>async function getUsers() {<br>  try {<br>    const response = await fetch(<br>      &quot;https://api.example.com/users&quot;<br>    );<br>const data = await response.json();<br>    return data.users;<br>  } catch (error) {<br>    console.log(&quot;Something went wrong&quot;);<br>  }<br>}</pre><p>It looks reasonable at first. There is a try/catch block, so the application won&#39;t crash because of an unhandled rejection.</p><p>But there’s a problem: the error message tells you almost nothing.</p><p>Was the request blocked by CORS? Did the network connection fail? Did the response body contain invalid JSON? Did the code throw somewhere else?</p><p>Worse, the function doesn’t return anything from the catch block. If the caller expects an array, it may receive undefined and fail somewhere later, making the original issue harder to find.</p><p>During development, I prefer error handling that preserves useful information:</p><pre>async function getUsers() {<br>  const response = await fetch(<br>    &quot;https://api.example.com/users&quot;<br>  );<br>if (!response.ok) {<br>    throw new Error(<br>      `Failed to fetch users: HTTP ${response.status}`<br>    );<br>  }<br>  const data = await response.json();<br>  return data.users;<br>}<br>getUsers()<br>  .then((users) =&gt; {<br>    console.log(&quot;Users:&quot;, users);<br>  })<br>  .catch((error) =&gt; {<br>    console.error(&quot;Could not load users:&quot;, error);<br>  });</pre><p>This version explicitly checks the HTTP status and lets the error propagate to the caller, where it can be logged or displayed appropriately.</p><p>For production applications, you would normally show users a helpful message while recording enough diagnostic information for developers to investigate the issue. Be careful not to expose access tokens, passwords, or other sensitive information in logs.</p><p>Good error handling isn’t about making errors disappear. It’s about making failures understandable and recoverable.</p><h3>6. The Browser Sends a Different Request Than You Expected</h3><p>Headers are easy to overlook because most requests work without much manual configuration.</p><p>But APIs often expect specific headers for authentication, content negotiation, or request-body parsing.</p><p>For example, consider a JSON POST request:</p><pre>async function createUser() {<br>  const response = await fetch(<br>    &quot;https://api.example.com/users&quot;,<br>    {<br>      method: &quot;POST&quot;,<br>      headers: {<br>        &quot;Content-Type&quot;: &quot;application/json&quot;<br>      },<br>      body: JSON.stringify({<br>        name: &quot;Kapi&quot;,<br>        email: &quot;kapi@example.com&quot;<br>      })<br>    }<br>  );<br>if (!response.ok) {<br>    throw new Error(<br>      `Failed to create user: ${response.status}`<br>    );<br>  }<br>  return response.json();<br>}</pre><p>Notice two things.</p><p>First, the request specifies Content-Type: application/json, telling the server how to interpret the request body.</p><p>Second, the JavaScript object is converted into a JSON string using JSON.stringify(). Passing an ordinary JavaScript object directly as the body of a fetch() request doesn&#39;t automatically serialize it into JSON.</p><p>If your backend expects JSON but receives a different content type or malformed body, it may reject the request or parse it incorrectly.</p><p>You should also avoid setting headers unnecessarily. For example, when sending FormData for a file upload, don&#39;t manually set the multipart Content-Type header. The browser needs to generate the boundary parameter itself.</p><p>Once again, the Network tab is your friend. Compare the headers and request body from Postman with those from the browser. Small differences can explain surprisingly large problems.</p><h3>7. The Request Works Locally but Fails After Deployment</h3><p>You finally get everything working on your laptop. You push the code, deploy the application, and discover that the same request fails in production.</p><p>Of course it does. Because apparently, the code wasn’t done testing you yet.</p><p>One common cause is an incorrect API base URL.</p><p>During development, your frontend might call:</p><pre>fetch(&quot;http://localhost:5000/users&quot;);</pre><p>That works because your backend is running on your own machine.</p><p>But once the frontend is deployed, localhost refers to the machine running the browser—not your deployed backend. A visitor opening your website will attempt to connect to their own computer.</p><p>The solution is to configure the correct API URL for each environment.</p><p>For example, with a frontend build tool that supports VITE_ environment variables:</p><pre>const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;<br>async function getUsers() {<br>  const response = await fetch(<br>    `${API_BASE_URL}/users`<br>  );<br>  if (!response.ok) {<br>    throw new Error(<br>      `Request failed: ${response.status}`<br>    );<br>  }<br>  return response.json();<br>}</pre><p>Your development environment might use a local backend URL, while production points to the deployed API.</p><p>Keep in mind that frontend environment variables are generally embedded into the client-side application during the build. They are configuration, not a safe place to store private API keys or other secrets.</p><p>Deployment can introduce other differences, too: HTTPS requirements, reverse-proxy routing, allowed CORS origins, cookie settings, and environment-specific authentication configuration.</p><p>If a request works locally but fails after deployment, compare the actual URLs and browser-visible configuration in both environments before assuming your application logic is broken.</p><h3>8. My Practical Debugging Checklist</h3><p>When an API works in Postman but fails in the frontend, I try to investigate in a consistent order rather than changing five things at once.</p><p><strong>First, inspect the browser request.</strong> Open DevTools, go to Network, reproduce the problem, and check whether the request was sent. If it wasn’t, investigate the frontend code and browser console.</p><p><strong>Second, compare it with Postman.</strong> Check the URL, HTTP method, query parameters, request body, headers, cookies, and authentication. Make sure you’re comparing equivalent requests.</p><p><strong>Third, interpret the failure.</strong> A 401 suggests an authentication issue; a 403 suggests an authorization problem; a 404 may indicate the wrong route; and a 500 points toward a server-side failure. These are clues, not absolute rules. A CORS error may also prevent JavaScript from seeing the actual response details.</p><p><strong>Fourth, check CORS and preflight behavior.</strong> If the browser reports a cross-origin error, inspect the response headers and any OPTIONS request. Verify that the server permits the actual origin, method, and headers required by the frontend.</p><p><strong>Fifth, inspect the response body.</strong> If the status is successful, check whether the JSON structure matches what your JavaScript expects. Look for missing fields, unexpected arrays or objects, and nullable values.</p><p><strong>Finally, verify the environment.</strong> Confirm the deployed API URL, HTTPS configuration, cookies, authentication settings, and server routing.</p><p>This process won’t identify every possible bug automatically, but it gives you a logical starting point. More importantly, it helps you avoid randomly modifying working code and accidentally creating a second problem while trying to fix the first.</p><h3>The Real Lesson: Postman Tests the API, Not Your Entire Application</h3><p>Postman is an excellent tool for testing endpoints, inspecting responses, experimenting with headers, and verifying authentication flows. If an API works there, that’s useful evidence that the endpoint can handle at least that particular request.</p><p>But a browser-based application introduces additional conditions. Your frontend runs under a particular origin, browser security rules apply, credentials may behave differently, and your JavaScript must correctly process the response and update the interface.</p><p>A successful Postman request proves neither that the browser will be allowed to read the response nor that your frontend will interpret it correctly.</p><p>The next time your API works in Postman but fails in your application, resist the urge to rewrite the backend immediately. Open DevTools, inspect the request, compare the evidence, and identify exactly where the behavior starts to differ.</p><p>Sometimes the problem really is CORS. Sometimes it’s a missing token, an unexpected response shape, or a URL that still points to localhost.</p><p>And sometimes, after an hour of investigation, the entire mystery turns out to be one missing header.</p><p>Web development keeps us humble like that.</p><p>But once you learn to debug requests systematically, these problems become much less mysterious — and your coffee has a better chance of staying warm.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5d03d186497f" width="1" height="1" alt=""><hr><p><a href="https://medium.com/me-n-stack-development/your-api-works-in-postman-why-is-your-frontend-still-broken-5d03d186497f">Your API Works in Postman. Why Is Your Frontend Still Broken?</a> was originally published in <a href="https://medium.com/me-n-stack-development">All About Computers</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Your API Is Slow, but the Database Is Fine: How to Find the Real Bottleneck]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/me-n-stack-development/your-api-is-slow-but-the-database-is-fine-how-to-find-the-real-bottleneck-ec73bff55ea7?source=rss----cbe80062d41f---4"><img src="https://cdn-images-1.medium.com/max/1672/1*um_jTJUDcsro5D5_XgW_-A.png" width="1672"></a></p><p class="medium-feed-snippet">A practical guide to diagnosing backend latency with distributed tracing, JVM profiling, thread dumps, connection pool metrics and a&#x2026;</p><p class="medium-feed-link"><a href="https://medium.com/me-n-stack-development/your-api-is-slow-but-the-database-is-fine-how-to-find-the-real-bottleneck-ec73bff55ea7?source=rss----cbe80062d41f---4">Continue reading on All About Computers »</a></p></div>]]></description>
            <link>https://medium.com/me-n-stack-development/your-api-is-slow-but-the-database-is-fine-how-to-find-the-real-bottleneck-ec73bff55ea7?source=rss----cbe80062d41f---4</link>
            <guid isPermaLink="false">https://medium.com/p/ec73bff55ea7</guid>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[backend-development]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[coding]]></category>
            <dc:creator><![CDATA[Gopi C K]]></dc:creator>
            <pubDate>Sun, 25 Oct 2026 09:01:02 GMT</pubDate>
            <atom:updated>2026-10-25T09:01:02.432Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[How Does Your Authenticator Work in Airplane Mode? The System Design Behind It]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/me-n-stack-development/how-does-your-authenticator-work-in-airplane-mode-the-system-design-behind-it-d244f41d44f5?source=rss----cbe80062d41f---4"><img src="https://cdn-images-1.medium.com/max/1672/1*ur0qGWuXzalmyYxml6Kydg.png" width="1672"></a></p><p class="medium-feed-snippet">You switch your phone to airplane mode, disconnect from Wi-Fi, and open your authenticator app. There are no mobile signals, no internet&#x2026;</p><p class="medium-feed-link"><a href="https://medium.com/me-n-stack-development/how-does-your-authenticator-work-in-airplane-mode-the-system-design-behind-it-d244f41d44f5?source=rss----cbe80062d41f---4">Continue reading on All About Computers »</a></p></div>]]></description>
            <link>https://medium.com/me-n-stack-development/how-does-your-authenticator-work-in-airplane-mode-the-system-design-behind-it-d244f41d44f5?source=rss----cbe80062d41f---4</link>
            <guid isPermaLink="false">https://medium.com/p/d244f41d44f5</guid>
            <category><![CDATA[system-design-interview]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[software-development]]></category>
            <dc:creator><![CDATA[Gopi C K]]></dc:creator>
            <pubDate>Wed, 21 Oct 2026 10:46:01 GMT</pubDate>
            <atom:updated>2026-10-21T10:46:01.503Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[JavaScript Is Single-Threaded. So How Does It Handle So Much at Once?]]></title>
            <link>https://medium.com/me-n-stack-development/javascript-is-single-threaded-so-how-does-it-handle-so-much-at-once-2771676e7664?source=rss----cbe80062d41f---4</link>
            <guid isPermaLink="false">https://medium.com/p/2771676e7664</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[technology]]></category>
            <dc:creator><![CDATA[Tech for Her]]></dc:creator>
            <pubDate>Mon, 19 Oct 2026 12:35:48 GMT</pubDate>
            <atom:updated>2026-10-19T12:35:46.823Z</atom:updated>
            <content:encoded><![CDATA[<h4><em>The event loop, call stack, promises, and the little scheduling trick that makes JavaScript feel asynchronous.</em></h4><p>A few days ago, I was looking at a JavaScript program that seemed to be doing everything at once.</p><p>It was fetching data from an API, responding to button clicks, updating the page, and running a few asynchronous operations in the background. Somehow, the interface remained responsive instead of freezing every time the application had to wait for something.</p><p>That made me wonder: if JavaScript runs on a single main thread in the browser, how does it manage all this without getting stuck?</p><p>I already knew about async/await and promises. I had used them in projects, fixed a few errors with them, and occasionally stared at a rejected promise wondering where my afternoon had gone. But knowing how to use asynchronous code and understanding what happens behind the scenes are two very different things.</p><p>The answer turned out to be more interesting than I expected. JavaScript doesn’t magically execute everything simultaneously. Instead, the runtime coordinates execution, delegates certain operations to the surrounding environment, and uses an event loop to decide what runs next.</p><p>Once I understood that, several confusing JavaScript behaviors suddenly made sense.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*3nfUJVDcjE4_8M9zBiYOiA.png" /><figcaption>AI Generated Image</figcaption></figure><h3>First, What Does Single-Threaded Actually Mean?</h3><p>When we say JavaScript is single-threaded, we’re usually talking about execution on the main JavaScript thread in a browser. In the conventional model, that thread executes one JavaScript task at a time. It has a call stack, and functions are pushed onto that stack when called and removed when they finish.</p><p>Consider this simple example:</p><pre>console.log(&quot;First&quot;);<br>function greet() {<br>  console.log(&quot;Second&quot;);<br>}<br>greet();<br>console.log(&quot;Third&quot;);</pre><p>The output is predictable:</p><pre>First<br>Second<br>Third</pre><p>JavaScript doesn’t jump to the last line and then return to the function whenever it feels like it. It follows the execution flow, calling functions and completing them in order.</p><p>When greet() is called, its execution is placed on the call stack. Once the function finishes, it is removed, and execution continues with the next statement.</p><p>So far, nothing surprising.</p><p>But what happens when a function needs to wait for a network response that might take 200 milliseconds — or two seconds? Does JavaScript sit there doing nothing until the server responds?</p><p>If it did that for every network request, our web applications would feel painfully slow. Thankfully, the browser provides more than just a JavaScript engine.</p><h3>The Browser Does More Than Run JavaScript</h3><p>One of the most useful things to understand is that JavaScript and the browser runtime work together, but they aren’t the same thing.</p><p>The JavaScript engine executes JavaScript code. The browser provides additional capabilities, including networking, timers, event handling, and rendering. Some operations can proceed outside the main JavaScript execution thread, allowing the browser to keep doing useful work while JavaScript isn’t actively executing that particular operation.</p><p>Let’s see what that means with a timer.</p><pre>console.log(&quot;Start&quot;);<br>setTimeout(() =&gt; {<br>  console.log(&quot;Timer finished&quot;);<br>}, 1000);<br>console.log(&quot;End&quot;);</pre><p>The output is:</p><pre>Start<br>End<br>Timer finished</pre><p>Wait a second. Literally.</p><p>Why didn’t JavaScript wait for the timer to finish before printing &quot;End&quot;?</p><p>When the runtime encounters setTimeout(), it registers the timer with the host environment. JavaScript continues executing the remaining statements rather than blocking the main thread for a second.</p><p>Once the timer becomes eligible to run, its callback can be scheduled for execution. The callback doesn’t interrupt JavaScript in the middle of another task; it waits until the runtime can run it.</p><p>There’s a subtle detail here: setTimeout(callback, 1000) does not guarantee that the callback runs exactly one second later. It specifies a minimum delay before the callback becomes eligible to run. If the main thread is busy, the callback may execute later.</p><p>That distinction matters when you’re building real applications.</p><h3>Meet the Call Stack: Where JavaScript Gets Its Work Done</h3><p>Before we talk about the event loop, let’s spend a moment with the call stack.</p><p>Imagine Kapi is building a small shopping application. When a user clicks the checkout button, the application calls a function that validates the cart, calculates the total, and prepares an order.</p><p>Each function call adds a frame to the call stack. When the function returns, that frame is removed. The stack keeps track of what JavaScript is currently executing and where it should continue afterward.</p><p>Here’s a tiny example:</p><pre>function calculateTotal() {<br>  return 100 + 50;<br>}<br>function checkout() {<br>  const total = calculateTotal();<br>  console.log(total);<br>}<br>checkout();</pre><p>The execution moves through checkout(), then calculateTotal(), and back to checkout() before printing the result.</p><p>The important point is that ordinary synchronous JavaScript runs to completion before the runtime moves on to another task. The event loop doesn’t jump into a new callback halfway through a function just because a timer has expired.</p><p>This also explains why an expensive loop can freeze a page. If JavaScript spends several seconds performing CPU-heavy work on the main thread, the browser may struggle to respond to clicks, process callbacks, or render updates until that work yields control.</p><p>Single-threaded execution is straightforward, but it means we need to be careful about blocking the main thread.</p><h3>The Event Loop Is the Coordinator</h3><p>Now we get to the part that connects everything together.</p><p>The event loop is a mechanism in the JavaScript host environment that coordinates when queued work gets an opportunity to execute. It doesn’t make a single JavaScript thread execute several callbacks simultaneously. Instead, it helps schedule work so the thread can handle different tasks over time.</p><p>A simplified mental model looks like this:</p><ol><li>JavaScript executes the current task.</li><li>The host environment handles operations such as timers and network activity.</li><li>When callbacks become eligible, they are queued according to the relevant scheduling rules.</li><li>After the current JavaScript execution finishes, the runtime processes pending microtasks at the appropriate checkpoint.</li><li>The browser can then proceed with rendering and other event-loop work as needed.</li></ol><p>The actual browser event loop has more details, including different task sources and rendering opportunities, but this model is enough to understand many everyday JavaScript behaviors.</p><p>One detail is worth remembering: the event loop is not a magical background thread that executes your queued JavaScript. The callback still needs time on the JavaScript thread when its turn arrives.</p><p>That’s why asynchronous code can improve responsiveness without making CPU-heavy JavaScript calculations automatically faster.</p><h3>Tasks vs. Microtasks: Why Promise Callbacks Run First</h3><p>This is where JavaScript starts getting really interesting.</p><p>Not all scheduled callbacks are handled through the same queue. In browser environments, tasks and microtasks have different scheduling rules.</p><p>Timer callbacks and many event callbacks are associated with tasks. Promise reactions, such as the callbacks registered through .then(), are scheduled as microtasks. Microtasks are processed at microtask checkpoints, including after the current task&#39;s JavaScript execution completes, before the browser proceeds to its next task.</p><p>Let’s look at a program that used to confuse me:</p><pre>console.log(&quot;A&quot;);<br>setTimeout(() =&gt; {<br>  console.log(&quot;B&quot;);<br>}, 0);<br>Promise.resolve().then(() =&gt; {<br>  console.log(&quot;C&quot;);<br>});<br>console.log(&quot;D&quot;);</pre><p>What do you think the output will be?</p><p>If you guessed A, B, C, D, you&#39;re not alone. I initially expected the timer callback to run immediately because its delay was zero.</p><p>But the actual output is:</p><pre>A<br>D<br>C<br>B</pre><p>Here’s why.</p><p><strong>First, </strong><strong>&quot;A&quot; is printed.</strong> JavaScript executes the first statement synchronously.</p><p><strong>Next, the timer is registered.</strong> The callback doesn’t execute immediately. It becomes eligible to run according to the timer and task-scheduling rules.</p><p><strong>Then, the promise callback is scheduled as a microtask.</strong> Because the promise is already fulfilled, the .then() reaction becomes eligible to run at the next microtask checkpoint.</p><p><strong>Finally, </strong><strong>&quot;D&quot; is printed.</strong> The current synchronous JavaScript finishes before the runtime moves on to the pending microtask.</p><p>At the microtask checkpoint, &quot;C&quot; is printed. Once the microtask queue has been drained, the event loop can proceed to the timer task, which prints &quot;B&quot;.</p><p>This is the reason the promise callback runs before the timer callback in this example.</p><p>The 0 in setTimeout(..., 0) doesn&#39;t mean &quot;run right now.&quot; It means the callback can become eligible after the minimum delay, subject to scheduling rules and the current state of the event loop.</p><p>Once you understand tasks and microtasks, output-order questions become much easier to reason about.</p><h3>What About async and await?</h3><p>At this point, you might be wondering whether async/await changes the rules.</p><p>It doesn’t. It gives us a more readable way to work with promises.</p><p>Consider this example:</p><pre>async function getData() {<br>  console.log(&quot;Inside function&quot;);<br>const result = await Promise.resolve(&quot;Data received&quot;);<br>  console.log(result);<br>}<br>console.log(&quot;Start&quot;);<br>getData();<br>console.log(&quot;End&quot;);</pre><p>The output is:</p><pre>Start<br>Inside function<br>End<br>Data received</pre><p>The interesting part is that getData() begins executing immediately. It prints &quot;Inside function&quot; before reaching the await expression.</p><p>When execution reaches await, the function suspends until the awaited promise settles. The surrounding JavaScript doesn&#39;t have to stop and wait for the function to resume. It continues to the next statement and prints &quot;End&quot;.</p><p>Because the promise in this example is already fulfilled, the continuation can resume through promise-related microtask scheduling after the current synchronous execution finishes.</p><p>That’s why &quot;Data received&quot; appears last.</p><p>One important distinction: await doesn&#39;t necessarily mean a network request is happening, and it doesn&#39;t automatically move work to another thread. It pauses the execution of the current async function while allowing the surrounding JavaScript to continue.</p><p>If you await a promise representing a network request, the network operation is handled by the host environment. When the response is available and the promise settles, the function can resume.</p><p>And yes, you can still block the main thread inside an async function if you run expensive synchronous code before yielding. Adding the async keyword doesn&#39;t make CPU-heavy calculations magically asynchronous.</p><h3>The Event Loop Doesn’t Make Heavy Computation Free</h3><p>Here’s a mistake that’s easy to make when learning asynchronous JavaScript: assuming that because the event loop handles asynchronous operations, it can also make expensive computations run without blocking the page.</p><p>Imagine this:</p><pre>console.log(&quot;Starting&quot;);<br>let total = 0;<br>for (let i = 0; i &lt; 1_000_000_000; i++) {<br>  total += i;<br>}<br>console.log(&quot;Finished&quot;);</pre><p>The loop runs synchronously on the thread executing it. Until it completes, JavaScript can’t process another task on that same thread.</p><p>If this code takes several seconds, the page can become unresponsive. Clicking a button won’t cause its handler to interrupt the loop, and a timer callback won’t jump in to execute halfway through.</p><p>You could try wrapping the loop in a promise or declaring the surrounding function async, but that alone wouldn&#39;t solve the problem. The heavy computation would still run synchronously.</p><p>For CPU-intensive work, a browser Web Worker may be a better choice. A worker runs JavaScript in a separate worker thread with its own execution context. It can perform calculations without blocking the main thread in the same way, although communication and data transfer still have costs.</p><p>For example, a worker could calculate a large dataset and send the result back to the main thread. The main thread would remain available for interface work while the worker handled the calculation.</p><p>For network requests, timers, and many I/O operations, the host environment’s asynchronous APIs are usually enough. For substantial CPU-bound work, consider a worker or another approach that divides the work into manageable chunks.</p><p>The right solution depends on what is actually taking the time.</p><h3>A Practical Example: Fetching Data Without Freezing the Page</h3><p>Let’s bring these ideas into a more realistic situation.</p><p>Suppose you’re building a dashboard that loads user information from an API. You want to show a loading message, display the results when the request succeeds, and handle failures gracefully.</p><p>Here’s a simple example:</p><pre>async function loadUsers() {<br>  const status = document.querySelector(&quot;#status&quot;);<br>  const list = document.querySelector(&quot;#users&quot;);<br>status.textContent = &quot;Loading users...&quot;;<br>  list.replaceChildren();<br>  try {<br>    const response = await fetch(<br>      &quot;https://jsonplaceholder.typicode.com/users&quot;<br>    );<br>    if (!response.ok) {<br>      throw new Error(`HTTP error: ${response.status}`);<br>    }<br>    const users = await response.json();<br>    for (const user of users) {<br>      const item = document.createElement(&quot;li&quot;);<br>      item.textContent = user.name;<br>      list.appendChild(item);<br>    }<br>    status.textContent = &quot;Users loaded successfully.&quot;;<br>  } catch (error) {<br>    status.textContent = &quot;Could not load users.&quot;;<br>    console.error(&quot;Failed to load users:&quot;, error);<br>  }<br>}<br>loadUsers();</pre><p>This example assumes the page contains elements with IDs status and users. The endpoint is a public demonstration API; in a real application, you&#39;d use your own endpoint and handle its specific requirements.</p><p>Here’s what happens behind the scenes.</p><p>First, the function updates the interface to show that the request has started. Then fetch() initiates a network request through the browser&#39;s networking facilities and returns a promise.</p><p>When JavaScript reaches the first await, the function suspends while the surrounding execution can continue. The browser can handle other work while the request is in progress.</p><p>Once the response becomes available, the promise settles and the function resumes. The code checks response.ok because fetch() does not automatically reject for HTTP error responses such as 404 or 500. It then reads the response body, creates list items, and updates the status message.</p><p>If the request fails or the code throws an error, the catch block handles it.</p><p>Notice what we haven’t done: we haven’t created a separate JavaScript thread just to fetch users. We’ve used an asynchronous API and promise-based scheduling to avoid blocking the main thread while waiting for the network.</p><p>For a small list, rendering the results one by one is perfectly reasonable. For thousands of items, however, rendering and DOM updates could become expensive. At that point, you’d investigate pagination, virtualization, or other performance improvements.</p><p>Understanding the event loop helps you recognize both what asynchronous programming solves and what it doesn’t.</p><h3>A Few Things Worth Remembering</h3><p>After understanding the call stack, host environment, tasks, microtasks, and promises, I started looking at JavaScript in a slightly different way.</p><p>When a callback runs later, it isn’t because JavaScript has been secretly executing it in the background. It’s because the runtime has scheduled it to run when the thread becomes available.</p><p>When a promise callback runs before a timer callback, it’s because microtasks and tasks follow different scheduling rules.</p><p>And when a page freezes during a long calculation, it’s because the main thread is busy doing synchronous work and cannot process other JavaScript tasks until it gets a chance to continue.</p><p>These distinctions are useful when debugging race conditions, understanding asynchronous output, designing responsive interfaces, and figuring out why a supposedly asynchronous operation still makes a page feel slow.</p><p>You don’t need to memorize every browser scheduling detail before you can build useful applications. Start by predicting what a small program will print, then run it and compare the result with your reasoning. Try changing a timer to a promise, adding an await, or introducing a synchronous loop. Those tiny experiments can teach you more than reading ten explanations in a row.</p><h3>JavaScript Isn’t Doing Everything at Once. It’s Taking Turns Well.</h3><p>The more I learned about the event loop, the less mysterious JavaScript’s asynchronous behavior became.</p><p>The main JavaScript thread still has to execute code one piece at a time. But the runtime coordinates timers, network operations, promise reactions, and other scheduled work so the application can respond to events instead of waiting synchronously for everything to finish.</p><p>That design is powerful, but it also places responsibility on us as developers. We need to understand when code blocks the main thread, how asynchronous operations resume, and why different callbacks don’t always execute in the order we first expect.</p><p>The next time a promise prints before a timer or an interface freezes during a calculation, you’ll have a better idea of what’s happening behind the scenes.</p><p>And honestly, that’s one of my favorite things about learning JavaScript: behavior that once looks like magic eventually turns into something you can explain, test, and use deliberately.</p><p>Which is much more satisfying than randomly changing the code until the output looks right.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2771676e7664" width="1" height="1" alt=""><hr><p><a href="https://medium.com/me-n-stack-development/javascript-is-single-threaded-so-how-does-it-handle-so-much-at-once-2771676e7664">JavaScript Is Single-Threaded. So How Does It Handle So Much at Once?</a> was originally published in <a href="https://medium.com/me-n-stack-development">All About Computers</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[I Wish I Knew These 12 Spring Boot Tricks When I Started Java Development]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/me-n-stack-development/i-wish-i-knew-these-12-spring-boot-tricks-when-i-started-java-development-204083e9d155?source=rss----cbe80062d41f---4"><img src="https://cdn-images-1.medium.com/max/2574/1*eOnxzqaU9NszACygaxDI8g.png" width="2574"></a></p><p class="medium-feed-snippet">12 practical techniques that help you write cleaner Java code, avoid common production bugs, and build Spring Boot applications like an&#x2026;</p><p class="medium-feed-link"><a href="https://medium.com/me-n-stack-development/i-wish-i-knew-these-12-spring-boot-tricks-when-i-started-java-development-204083e9d155?source=rss----cbe80062d41f---4">Continue reading on All About Computers »</a></p></div>]]></description>
            <link>https://medium.com/me-n-stack-development/i-wish-i-knew-these-12-spring-boot-tricks-when-i-started-java-development-204083e9d155?source=rss----cbe80062d41f---4</link>
            <guid isPermaLink="false">https://medium.com/p/204083e9d155</guid>
            <category><![CDATA[spring-boot]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[backend-development]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[java]]></category>
            <dc:creator><![CDATA[Aditi Saxena]]></dc:creator>
            <pubDate>Sun, 18 Oct 2026 07:39:11 GMT</pubDate>
            <atom:updated>2026-10-18T07:39:09.815Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[7 Backend Concepts Every Frontend Developer Should Understand]]></title>
            <link>https://medium.com/me-n-stack-development/7-backend-concepts-every-frontend-developer-should-understand-c1a2880fcba2?source=rss----cbe80062d41f---4</link>
            <guid isPermaLink="false">https://medium.com/p/c1a2880fcba2</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[technology]]></category>
            <dc:creator><![CDATA[Tech for Her]]></dc:creator>
            <pubDate>Thu, 15 Oct 2026 15:44:10 GMT</pubDate>
            <atom:updated>2026-10-15T15:44:09.334Z</atom:updated>
            <content:encoded><![CDATA[<h4>Your Frontend Is Only Half the Story — Here’s What Happens Behind the Scenes</h4><p>I used to think the frontend was where most of the interesting things happened. You build a beautiful interface, connect a few buttons, fetch some data, and suddenly you have an application that feels alive. Then you start working on something slightly more complicated, like user authentication or saving data, and you realize that the frontend is only showing one part of a much bigger system. The button might look perfect, but what happens after someone clicks it is an entirely different story.</p><p>I remember how easy it was to think of the backend as a place where requests went, data came from, and mysterious server things happened in between. I could call an API, receive a JSON response, and move on with my day without thinking too much about what happened behind the scenes. That approach worked until something broke. Suddenly, I needed to understand why a request returned a 401, why the server couldn&#39;t find a record, or why the same endpoint behaved differently depending on who was logged in.</p><p>The more I learned about backend development, the more I realized that frontend developers don’t need to become backend experts, but understanding the fundamentals changes how they build applications. It becomes easier to debug issues, design better interfaces, communicate with backend developers, and avoid assumptions that create bugs later. So, if you’ve ever wondered what actually happens after your frontend sends a request, here are seven backend concepts worth understanding.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qhAj4AFRDY-bKl1c_CH0tQ.png" /><figcaption>AI Generated Image</figcaption></figure><h3>1. APIs: How Your Frontend Talks to the Backend</h3><p>An API, or Application Programming Interface, is one of the first backend concepts a frontend developer encounters. Whenever your application loads a profile, retrieves a list of products, or submits a login form, it often communicates with a backend through an API. You send a request containing information about what you need, and the server processes that request before returning a response. The frontend then uses the response to update the interface.</p><p>Imagine you’re building a shopping application. When someone opens the products page, the frontend might request a list of available products from an endpoint such as /api/products. The server receives the request, retrieves the relevant information, and returns a response containing product names, prices, and identifiers. Your frontend doesn&#39;t need to know exactly how the database stores those products. It only needs to understand the API contract, including the request format and the structure of the response.</p><p>A simple JavaScript example might look like this:</p><pre>async function getProducts() {<br>  const response = await fetch(&quot;/api/products&quot;);<br>  if (!response.ok) {<br>    throw new Error(&quot;Failed to fetch products&quot;);<br>  }<br>  return response.json();<br>}</pre><p>This function sends an HTTP request, checks whether the response indicates success, and parses the response body as JSON. Notice that fetch() does not automatically throw an exception for HTTP errors such as 404 or 500, which is why checking response.ok matters. Network failures can still reject the promise, so production code should also handle those failures and display an appropriate loading, success, or error state.</p><p>The important thing to understand is that an API is a contract between two parts of a system. If the backend changes a field from productName to name without updating the contract or coordinating the change, your frontend might suddenly display empty product titles. Good API design makes those expectations explicit, while good frontend code avoids assuming every request will succeed. Once you understand APIs this way, debugging becomes less about randomly changing components and more about identifying which part of the contract has failed.</p><h3>2. HTTP Methods and Status Codes: Understanding What a Request Means</h3><p>When I first started working with APIs, I mostly cared about whether the request worked. If I received data, everything was fine; if I received an error, something was broken. But HTTP methods and status codes provide important information about what the client is asking the server to do and how the server handled that request. Understanding them makes it much easier to design frontend behavior that matches what the backend actually supports.</p><p>Consider a simple application that manages user profiles. A GET request might retrieve a profile, a POST request might create a new resource, a PATCH request might update part of an existing resource, and a DELETE request might remove a resource. These methods communicate intent, although the exact behavior depends on the API&#39;s design. PUT is commonly used to replace a resource representation, while PATCH is commonly used for partial updates.</p><p>Here is a small example using JavaScript:</p><pre>async function updateProfile(profileId, changes) {<br>  const response = await fetch(`/api/profiles/${profileId}`, {<br>    method: &quot;PATCH&quot;,<br>    headers: {<br>      &quot;Content-Type&quot;: &quot;application/json&quot;<br>    },<br>    body: JSON.stringify(changes)<br>  });<br>  if (!response.ok) {<br>    throw new Error(`Request failed: ${response.status}`);<br>  }<br>  return response.json();<br>}</pre><p>The request sends a partial update to a profile endpoint. The Content-Type header tells the server that the request body contains JSON, and JSON.stringify() converts the JavaScript object into a JSON string. The backend still needs to validate the submitted values, verify permissions, and decide what response to return. Sending a request successfully does not automatically mean the update was valid or authorized.</p><p>Status codes help explain the outcome. A 200 generally indicates success, 201 commonly indicates that a resource was created, 400 often indicates an invalid request, 401 indicates missing or invalid authentication credentials, and 403 means the server understood the request but refuses to authorize it. A 404 indicates that the requested resource was not found, while 500 signals an unexpected server-side failure. These meanings have specific HTTP definitions and can be used differently within a particular API&#39;s documented behavior.</p><p>For frontend developers, these distinctions directly affect user experience. An invalid form might need field-level validation messages, an expired session might require the user to sign in again, and a server failure might justify a retry option. Treating every unsuccessful response as “Something went wrong” throws away useful information. Understanding HTTP gives you a better way to connect backend behavior with meaningful feedback in the interface.</p><h3>3. Databases: Where Your Application’s Data Actually Lives</h3><p>A frontend can display information beautifully, but it usually shouldn’t be responsible for permanently storing important application data. When someone creates an account, saves a favorite product, or submits an order, the backend typically coordinates with a database to store and retrieve that information. Understanding this relationship helps explain why a successful button click doesn’t necessarily mean the data has been saved, and why data displayed in the browser can sometimes become outdated.</p><p>There are several database models, but relational databases are a useful starting point. Systems such as PostgreSQL and MySQL organize data into tables containing rows and columns, with relationships connecting related records. A shopping application might store users in one table, products in another, and orders in a third. Each table has its own structure, and the backend uses queries to retrieve or modify records according to the application’s requirements.</p><p>For example, a backend might execute a query like this:</p><pre>SELECT id, name, email<br>FROM users<br>WHERE id = 42;</pre><p>This query retrieves selected fields for a user whose identifier is 42. The frontend usually shouldn&#39;t connect directly to the production database or decide how this query is executed. Instead, it requests a profile through an API, and the backend checks permissions, performs the query safely, and returns the information the current user is allowed to access. Keeping database access behind the backend provides a controlled place to enforce business rules and security.</p><p>Databases also explain why frontend data can become stale. Imagine that a user changes their display name in one browser tab while another tab still shows the previous value. The second tab may be displaying cached data or simply may not have fetched the updated record yet. The database can contain the correct value even while the interface displays something older. Refreshing data, updating local state carefully, and handling failed saves are therefore important parts of frontend development.</p><p>One more thing worth understanding is that databases have schemas and constraints. A column might be required, an email address might need to be unique, or an order might reference an existing user. These rules protect data integrity, even when requests arrive from different clients. Frontend validation is useful for helping people correct mistakes before submitting a form, but the backend and database must still enforce the rules because clients can send unexpected or deliberately manipulated requests.</p><h3>4. Authentication and Authorization: Who Are You, and What Can You Do?</h3><p>Authentication and authorization sound similar, and I definitely understand why developers sometimes mix them up. Authentication answers the question, “Who are you?” Authorization answers, “What are you allowed to do?” They work together, but they solve different problems. A user might successfully sign in to an application and still have no permission to access another user’s private documents or perform administrative actions.</p><p>Imagine you’re building a dashboard with separate views for customers and administrators. After a customer signs in, the application needs some way to establish the user’s identity for subsequent requests. Depending on the architecture, the backend might use a server-side session identified by a cookie or a token-based mechanism. The frontend can use that authentication state to show the appropriate interface, but the backend must independently verify the credentials and permissions whenever a protected operation is requested.</p><p>A simplified frontend request might look like this:</p><pre>const response = await fetch(&quot;/api/my-profile&quot;, {<br>  credentials: &quot;include&quot;<br>});</pre><p>The credentials: &quot;include&quot; option allows the browser to include applicable credentials, such as cookies, with the request, subject to browser rules, cookie attributes, and CORS configuration. This is commonly useful when an application uses cookie-based sessions. The backend then validates the session and determines which user the request belongs to. For cross-origin requests, the server must also configure credentialed CORS correctly, and the cookie settings must be compatible with the deployment.</p><p>The security boundary is the important part. Hiding an admin button in the frontend does not prevent someone from calling the administrative API directly. A malicious user can inspect network requests, modify client-side code, or send requests using tools outside the browser. The backend must verify authorization before performing protected actions, even when the frontend already hides the corresponding controls. Client-side checks improve usability, but they are not a substitute for server-side enforcement.</p><p>Authentication also comes with practical security concerns. Passwords should never be stored as plain text, session identifiers must be protected, and sensitive tokens should not be exposed casually through logs or browser storage. Cookie-based authentication may require appropriate CSRF protections, while token-based systems have their own storage, expiration, and revocation trade-offs. You don’t need to design an entire identity system as a frontend developer, but understanding these basics helps you recognize why authentication bugs can be much more serious than ordinary UI bugs.</p><h3>5. Middleware and Validation: What Happens Before Your Request Reaches the Main Logic?</h3><p>When a request reaches a backend, it doesn’t always go directly to the function that handles the requested feature. Many applications run requests through middleware or similar processing layers first. These layers can perform tasks such as request logging, authentication checks, rate limiting, parsing request bodies, and handling cross-origin rules. Understanding middleware helps explain why a request might fail before the endpoint’s main logic ever runs.</p><p>Imagine a frontend sends a request to update a profile, but the server responds with 401 Unauthorized. You might immediately suspect that the profile endpoint is broken, even though the request may never have reached the profile-handling function. Authentication middleware could have rejected it because the session cookie was missing or expired. Looking at the request headers, browser network panel, and backend logs can help determine whether the failure happened during authentication or inside the endpoint itself.</p><p>Validation is another important part of the process. Frontend forms can prevent many mistakes by checking required fields, email formats, and acceptable input ranges. However, a backend must validate incoming data independently because requests can come from mobile applications, scripts, automated clients, or modified browser requests. If an API expects a positive quantity, it should reject invalid values even if the normal frontend never allows a user to submit them.</p><p>For example, a simplified backend validation function might look like this:</p><pre>def validate_quantity(quantity):<br>    if not isinstance(quantity, int) or quantity &lt; 1:<br>        raise ValueError(&quot;Quantity must be a positive integer&quot;)<br>    return quantity</pre><p>This example checks that the quantity is an integer of at least one, although a production API would normally convert validation failures into a structured client error such as 400 Bad Request or 422 Unprocessable Content, depending on its conventions. It should also account for how incoming JSON values are parsed and how validation errors are returned. The key principle is that the backend must enforce the rules rather than trusting that the frontend has already done so.</p><p>Middleware and validation become especially useful to understand when errors appear inconsistent. Perhaps one endpoint works while another returns 403, or a request is rejected before your handler can log anything. Rather than assuming the business logic is wrong, investigate the request pipeline. Knowing what runs before the endpoint gives you a much better mental model of how backend applications process incoming requests.</p><h3>6. Caching: Why the Data You See Might Not Be the Latest Data</h3><p>Caching is a technique for storing a reusable copy of data so that future requests can be served more quickly or cheaply. Instead of recalculating a result or retrieving the same information from a database every time, an application may temporarily reuse an earlier response. Caching can improve performance and reduce infrastructure costs, but it also introduces a question frontend developers eventually encounter: what happens when the original data changes while a cached copy still exists?</p><p>Imagine a product page that displays a price retrieved from an API. The backend might cache product information for a short period to reduce database load, while the browser might also cache the HTTP response. If the product’s price changes, the interface could continue displaying the older value until the relevant cache expires or is invalidated. The application isn’t necessarily broken; different layers are temporarily working with different versions of the data.</p><p>HTTP caching headers help control some of this behavior. For example, a server might return:</p><pre>Cache-Control: max-age=60</pre><p>This tells compatible caches that the response can generally be considered fresh for up to 60 seconds, subject to the applicable HTTP caching rules. It doesn’t mean every cache will necessarily store the response, nor does it guarantee that all application data will update exactly one minute later. Authentication, cache directives, browser behavior, and intermediary infrastructure can affect the outcome, so caching policies need to be chosen according to the sensitivity and freshness requirements of the data.</p><p>Caching is especially useful for content that changes infrequently, such as public documentation, static assets, or product catalog information. It needs more careful handling for data that changes frequently or must reflect current state, such as account balances, inventory, or order status. A frontend might also cache API responses in application state or a data-fetching library, which means updating the server alone may not immediately update the visible interface.</p><p>The important lesson is that stale data can originate from several layers. If an update appears successful but the old value remains on screen, check whether the backend returned the new value, whether the browser is reusing a cached response, and whether your frontend state was updated. Understanding caching gives you more ways to investigate the problem without immediately assuming that the database failed to save the change.</p><h3>7. Background Jobs and Queues: Not Everything Happens During the Request</h3><p>One of the most useful backend concepts to understand is that not every operation should happen while a user is waiting for an HTTP response. Some tasks take longer than a normal request should reasonably take, such as sending large batches of emails, generating reports, processing uploaded files, or coordinating with slow external services. In those cases, a backend can place the work into a queue and let a background worker process it separately.</p><p>Imagine a user uploads a video to your application. If the backend tries to upload the file, transcode it, generate thumbnails, and update every related record before responding, the request might take too long or time out. A more practical design can store the uploaded file, create a processing job, and return a response indicating that processing has started. A background worker then performs the expensive work and updates the job’s status when it finishes.</p><p>A simplified API response might look like this:</p><pre>{<br>  &quot;jobId&quot;: &quot;job_123&quot;,<br>  &quot;status&quot;: &quot;processing&quot;<br>}</pre><p>The frontend can use this information to show a progress indicator or a message explaining that the task is still running. It might poll a status endpoint periodically, subscribe to server-sent events, or use a WebSocket if the application needs more immediate updates. The right approach depends on the product’s requirements, infrastructure, and expected volume of work. The important part is that the initial request doesn’t have to remain open until every background operation is complete.</p><p>Queues also introduce behaviors that frontend developers should understand. A task can remain pending, fail, retry, or take longer than expected, so a response indicating that processing started should not be presented as proof that the task succeeded. The interface needs to distinguish between states such as queued, processing, completed, and failed. If the user leaves the page and returns later, the application may need to retrieve the job’s current status instead of relying on temporary component state.</p><p>There is also a reliability consideration: background jobs may run more than once, depending on the queue and retry strategy. For operations such as sending payments or creating orders, the backend often needs idempotency or other safeguards to avoid duplicate effects. As a frontend developer, you don’t necessarily need to implement the worker yourself, but knowing that asynchronous processing exists helps you design interfaces that communicate progress accurately instead of leaving users wondering whether their action did anything.</p><h3>Putting These Concepts Together</h3><p>Let’s bring everything together with a familiar example: a user signing in to a web application. The frontend sends an HTTP request to an authentication API, the backend validates the request, authentication logic checks the submitted credentials, and the server establishes an appropriate session or token-based authentication state. If the user is authorized to access their profile, the backend retrieves the relevant database record and returns a response that the frontend can use to render the page.</p><p>Even this seemingly simple flow involves several of the concepts we’ve discussed. The API defines the request and response contract, HTTP status codes communicate success or failure, the database stores the user’s information, and middleware may validate the session before the endpoint runs. Caching might affect how profile information is retrieved, while background jobs could handle tasks such as sending a welcome email. Understanding these relationships makes it easier to reason about the whole application rather than treating every problem as a frontend bug.</p><p>When something goes wrong, the same mental model gives you a practical debugging path. If a request returns 401, investigate authentication and session handling. If the response contains unexpected values, check the API contract and database data. If an operation appears successful but takes time to finish, find out whether the backend processes it asynchronously. Instead of randomly changing components, you can identify which layer is responsible and collect evidence before deciding what to fix.</p><p>You don’t need to memorize every backend framework or become an expert in database administration to benefit from these ideas. Start by understanding the request lifecycle in the applications you already build. Open the browser’s Network panel, inspect request headers and responses, read the API documentation, and ask what the backend is doing behind each important user action. Those small habits will gradually turn backend behavior from a mystery into something you can reason about confidently.</p><h3>You Don’t Need to Build the Backend to Understand It</h3><p>I used to think understanding the backend meant learning an entirely separate world of technologies before I could become a better frontend developer. Now I see it differently. You don’t have to write every database query or configure every server to benefit from understanding APIs, HTTP, authentication, validation, caching, and background processing. You just need enough knowledge to understand how the pieces connect and where responsibility belongs when something goes wrong.</p><p>That understanding changes the way you build interfaces. You start accounting for loading states, expired sessions, validation errors, stale data, and tasks that take time to complete. You stop assuming that a successful click guarantees a successful operation, and you become more careful about which checks belong in the frontend and which must be enforced by the backend. Your code becomes more resilient because you’re designing for the behavior of a real system, not just the happy path shown in a tutorial.</p><p>My advice is to choose one application you’re already working on and trace a single feature from beginning to end. Follow the button click, inspect the API request, examine the response, and find out how the backend stores or retrieves the data. When you encounter a concept you don’t understand, investigate it with a small example instead of trying to learn an entire technology stack at once. You’ll build a much stronger mental model by connecting each concept to something you’ve actually seen happen.</p><p><strong>The best frontend developers don’t need to know everything about the backend, but they benefit enormously from understanding what happens beyond the browser.</strong> Once those invisible parts of the application start making sense, debugging becomes less intimidating, collaboration becomes easier, and building reliable features becomes a much more deliberate process. And honestly, that’s a pretty good reason to spend a little time learning what happens after the request leaves your laptop.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c1a2880fcba2" width="1" height="1" alt=""><hr><p><a href="https://medium.com/me-n-stack-development/7-backend-concepts-every-frontend-developer-should-understand-c1a2880fcba2">7 Backend Concepts Every Frontend Developer Should Understand</a> was originally published in <a href="https://medium.com/me-n-stack-development">All About Computers</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Stop Following Tutorials: Build These 5 Backend Projects Instead]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/me-n-stack-development/stop-following-tutorials-build-these-5-backend-projects-instead-4e69a1718cbf?source=rss----cbe80062d41f---4"><img src="https://cdn-images-1.medium.com/max/1672/1*KWkOWE9HAUwFad46pCZ2oA.png" width="1672"></a></p><p class="medium-feed-snippet">Build These 5 Backend Projects to Master APIs, Databases, System Design, and Production-Level Problem Solving.</p><p class="medium-feed-link"><a href="https://medium.com/me-n-stack-development/stop-following-tutorials-build-these-5-backend-projects-instead-4e69a1718cbf?source=rss----cbe80062d41f---4">Continue reading on All About Computers »</a></p></div>]]></description>
            <link>https://medium.com/me-n-stack-development/stop-following-tutorials-build-these-5-backend-projects-instead-4e69a1718cbf?source=rss----cbe80062d41f---4</link>
            <guid isPermaLink="false">https://medium.com/p/4e69a1718cbf</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[backend]]></category>
            <dc:creator><![CDATA[Gopi C K]]></dc:creator>
            <pubDate>Wed, 14 Oct 2026 14:01:03 GMT</pubDate>
            <atom:updated>2026-10-14T14:01:03.023Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[Stop Waiting on Other Teams With API Testing and Service Virtualization]]></title>
            <link>https://medium.com/me-n-stack-development/stop-waiting-on-other-teams-with-api-testing-and-service-virtualization-89c4c9b48bfc?source=rss----cbe80062d41f---4</link>
            <guid isPermaLink="false">https://medium.com/p/89c4c9b48bfc</guid>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[service-virtualization]]></category>
            <category><![CDATA[software-testing]]></category>
            <category><![CDATA[api-testing]]></category>
            <dc:creator><![CDATA[Sancharini Panda]]></dc:creator>
            <pubDate>Wed, 14 Oct 2026 13:31:05 GMT</pubDate>
            <atom:updated>2026-10-14T13:31:03.701Z</atom:updated>
            <content:encoded><![CDATA[<h4>How a half-finished API spec and a few fake services got me unblocked for good.</h4><figure><img alt="API Testing and Service Virtualization" src="https://cdn-images-1.medium.com/max/1024/1*g9m9b29xTs9vMMZyiAxzmg.png" /><figcaption>Image Generated Using AI, Edited by Author</figcaption></figure><p>A while back I was building a checkout service, and for the first few weeks I hardly tested a thing. I’d love to say that was a choice. It wasn’t. The payments API I needed? Another team was still building it. Inventory lived in a staging setup with an uncanny habit of going down exactly when I sat down to test. So my workflow was basically: write code, open a PR, hope. Not my proudest stretch.</p><p>So what changed? Honestly, it took me a while to see that API testing and service virtualization go together. I’d always filed them as two separate things in my head, one for QA folks and one for… I wasn’t even sure who. Turns out they’re the same habit. If I can run a convincing fake of a dependency on my laptop, I can test against it, and then nobody else’s schedule decides when I get to find my bugs. I’ll walk through how that played out, because it ended up being less about tools and more about how I thought about the services around mine.</p><h3>Blocked by APIs that weren’t ready yet</h3><p>If you’ve worked on a team that splits services across squads, you probably know the feeling. Your feature is done on your side. You need someone else’s endpoint to exist, or to stay up, before you can prove it works. You ping them on Slack. They’re busy shipping their own stuff. Fair enough.</p><p>My first workaround was the obvious one. I hand-wrote little fake responses inside my tests, a dictionary here, a hardcoded JSON blob there. It kind of worked. But I was basically guessing at what the payments team would return, and every time they tweaked their design I had to go hunting through my tests to update the guesses.</p><h3>Virtualizing a dependency from its API contract</h3><p>Things got better the day I asked the payments team for their OpenAPI spec. They had one, half finished, sitting in their repo. Nobody had thought to share it.</p><p>That spec turned out to be gold. I pointed a service virtualization tool at it and, a minute later, had my own little stand-in payments API answering on localhost. Its responses matched the spec field for field. My checkout service had no idea it wasn’t the real one. Neither did my API tests, which finally had something solid to hit. And when the payments team changed a field? They updated the spec, I regenerated the fake, and my tests yelled at me right away about whatever broke.</p><p>Honestly, the bigger win was social. Our two teams got into the habit of hashing out the contract first, before anybody even opened an editor. I’d bet that saved us more Slack threads than every tool put together.</p><h3>Testing the unhappy paths on purpose</h3><p>Here’s something I didn’t expect. A virtual service is better than the real one at certain kinds of testing.</p><p>Ever tried to get a real payments sandbox to time out right when you want it to? Or throw a 429 at you on purpose? Good luck. The virtual one was a lot more cooperative. Slow responses, outright failures, a strange half-empty body, I could dial up whichever one I needed that afternoon. That’s how I found out my retry logic was retrying things it absolutely shouldn’t, like a charge that had already gone through. Would’ve been a fun one to discover in production.</p><h3>When the real service finally shipped</h3><p>Eventually the payments API went live in staging. This is the part people sometimes skip, and it matters. Virtual services are only as good as their match with reality, so the first thing I did was run my API tests against the real thing too, and compare.</p><p>A couple of small differences showed up. A date format here, an extra nullable field there. Nothing dramatic, and because the contract was shared, fixing the spec fixed both sides at once.</p><h3>Recording real traffic instead of writing mocks</h3><p>Once the real services existed, I didn’t want to keep maintaining virtual services by hand forever. That’s where record-and-replay came in.</p><p>The tool I ended up liking for this was Keploy. It’s open source, and it uses eBPF to capture traffic at the kernel level, so I didn’t have to change a line of my service’s code. I ran checkout through it, clicked through a few real purchase flows in staging, and it saved the incoming requests as API tests and every outgoing call (payments, inventory, even the database queries) as mocks. After that, my test suite could replay all of it without any of those services being up.</p><p>That felt like the natural next step after the spec-based setup. The contract got me unblocked early. Recordings kept my tests honest once real traffic existed.</p><h3>How it changed the way our teams work together</h3><p>I used to feel a bit helpless waiting on other teams. Now my default move with any new dependency is pretty simple: get the contract, virtualize it, and start testing that same day. The other team keeps building at their own pace, and nobody’s blocking anybody.</p><p>It also made our conversations better. Instead of “is your API ready yet?”, it became “hey, my tests caught a mismatch between your spec and staging, want to take a look?” Way nicer message to send. And to receive, I’d guess.</p><h3>Conclusion</h3><p>If I could go back and tell my earlier self one thing, it’d be that waiting on other teams was never really a scheduling problem. It was a testing problem, and it had a fix. Pairing <a href="https://keploy.io/blog/community/service-virtualization"><strong>API testing and service virtualization</strong></a> meant my feedback loop was mine again. Whatever state the other teams’ code was in, I could still find out today whether mine worked.</p><p>Stuck in that spot right now? Don’t try to fix everything at once. Message the team you’re waiting on and ask for their API spec. Unfinished is fine, honestly, mine was. Spin up a fake from it this week, write a test where everything goes right and another where the payment fails, and see how it feels. My guess is the waiting stops bothering you pretty quickly.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=89c4c9b48bfc" width="1" height="1" alt=""><hr><p><a href="https://medium.com/me-n-stack-development/stop-waiting-on-other-teams-with-api-testing-and-service-virtualization-89c4c9b48bfc">Stop Waiting on Other Teams With API Testing and Service Virtualization</a> was originally published in <a href="https://medium.com/me-n-stack-development">All About Computers</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>