<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Omar Lashin</title>
    <description>The latest articles on DEV Community by Omar Lashin (@omar_lashin_2badc08a1ddf9).</description>
    <link>https://dev.to/omar_lashin_2badc08a1ddf9</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3926638%2Fb145ba48-e2aa-4e39-b804-12c9433d66f2.jpg</url>
      <title>DEV Community: Omar Lashin</title>
      <link>https://dev.to/omar_lashin_2badc08a1ddf9</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/omar_lashin_2badc08a1ddf9"/>
    <language>en</language>
    <item>
      <title>The "Localhost" Trap: Networking Microservices in Docker Compose</title>
      <dc:creator>Omar Lashin</dc:creator>
      <pubDate>Tue, 12 May 2026 08:23:44 +0000</pubDate>
      <link>https://dev.to/omar_lashin_2badc08a1ddf9/the-localhost-trap-networking-microservices-in-docker-compose-k04</link>
      <guid>https://dev.to/omar_lashin_2badc08a1ddf9/the-localhost-trap-networking-microservices-in-docker-compose-k04</guid>
      <description>&lt;p&gt;&lt;strong&gt;The "It Works On My Machine" Illusion&lt;/strong&gt;&lt;br&gt;
You've built a beautiful, decoupled microservices architecture. Your Node/Express API runs smoothly on port 3000, and your React frontend fetches data perfectly from &lt;a href="http://localhost:3000/api" rel="noopener noreferrer"&gt;http://localhost:3000/api&lt;/a&gt;. You containerize both services, spin them up with Docker Compose, and suddenly the frontend crashes with a Connection Refused error.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happened?&lt;/strong&gt; You fell into the localhost trap.&lt;/p&gt;

&lt;p&gt;Understanding Docker's Internal Network&lt;br&gt;
When running services locally without Docker, localhost refers to your host machine. Both your frontend and backend share this environment. However, when you containerize these services, Docker creates an isolated virtual network. Inside a container, localhost no longer refers to your laptop; it refers to the container itself.&lt;/p&gt;

&lt;p&gt;When your React container tries to fetch from localhost:3000, it is looking inside its own isolated environment, where the Node API does not exist.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;The Solution: DNS Resolution via Compose&lt;/em&gt;&lt;br&gt;
Docker Compose automatically sets up a custom bridge network and provides internal DNS resolution using the service names defined in your docker-compose.yml.&lt;/p&gt;

&lt;p&gt;Let's look at a standard compose file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.8'&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;api-service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./backend&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3000:3000"&lt;/span&gt;

  &lt;span class="na"&gt;web-client&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./frontend&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8080:80"&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;api-service&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To fix the connection refused error, you must stop hardcoding localhost. If your backend needs to communicate with another containerized service from the server-side, it must use the exact service name defined in the YAML file as the hostname.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// BAD: Fails inside a Docker container&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:3000/api/users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// GOOD: Utilizes Docker's internal DNS resolver&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://api-service:3000/api/users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By respecting Docker's internal network topography, we ensure our microservices can communicate seamlessly, regardless of the host machine they are deployed on.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>docker</category>
      <category>microservices</category>
      <category>networking</category>
    </item>
    <item>
      <title>Taming Unpredictable User Input: Building a RAG Triage Agent in Node.js</title>
      <dc:creator>Omar Lashin</dc:creator>
      <pubDate>Tue, 12 May 2026 08:18:12 +0000</pubDate>
      <link>https://dev.to/omar_lashin_2badc08a1ddf9/taming-unpredictable-user-input-building-a-rag-triage-agent-in-nodejs-3pp4</link>
      <guid>https://dev.to/omar_lashin_2badc08a1ddf9/taming-unpredictable-user-input-building-a-rag-triage-agent-in-nodejs-3pp4</guid>
      <description>&lt;p&gt;&lt;strong&gt;The Problem with Raw User Data&lt;/strong&gt;&lt;br&gt;
When building the backend for an urban infrastructure platform, the biggest bottleneck isn't the database, it's the users. A citizen reporting a problem rarely uses structured terminology. They don't say, "Electrical failure, Priority 1, Jurisdiction: City Council." They say, "The streetlamp on 5th avenue is sparking and my dog is terrified."&lt;/p&gt;

&lt;p&gt;Passing this raw text directly into a database requires a human administrator to manually read and route every single ticket. To automate this, we need to extract structured JSON from unstructured panic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The RAG Solution&lt;/strong&gt;&lt;br&gt;
Instead of relying on a raw LLM (which might hallucinate categories that our database doesn't accept), we implemented a lightweight Retrieval-Augmented Generation (RAG) pipeline in Node.js. By feeding the LLM our strict database schemas and city department rules alongside the user prompt, we force it to act as a deterministic triage agent.&lt;/p&gt;

&lt;p&gt;Here is a simplified version of the extraction logic using the OpenAI API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;categorizeIssue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userReport&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cityRulesContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;systemPrompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
    You are a strict city infrastructure triage agent. 
    Analyze the user report against the provided City Rules context.
    You must return ONLY a JSON object with the following keys:
    - category (string: must be one of the approved categories in context)
    - severity (integer: 1-5)
    - department (string: target routing department)
  `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gpt-4-turbo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;response_format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;json_object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;system&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;systemPrompt&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Context: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;cityRulesContext&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\n\nReport: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userReport&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By utilizing the response_format: { type: "json_object" } flag, we ensure the output is ready for our Express.js backend to ingest. The Node server doesn't know it's talking to an AI; it just receives a perfectly formatted JSON payload, completely bridging the gap between natural language and strict database requirements.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>node</category>
      <category>rag</category>
    </item>
  </channel>
</rss>
