<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Nodejs on David Lang</title>
    <link>https://www.davidlang.tech/tags/nodejs/</link>
    <description>Recent content in Nodejs on David Lang</description>
    <generator>Hugo</generator>
    <language>en</language>
    <lastBuildDate>Wed, 08 Mar 2023 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://www.davidlang.tech/tags/nodejs/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Introduction to LangChain: Building AI-Powered Apps</title>
      <link>https://www.davidlang.tech/posts/introduction-to-langchain-building-ai-powered-apps/</link>
      <pubDate>Wed, 08 Mar 2023 00:00:00 +0000</pubDate>
      <guid>https://www.davidlang.tech/posts/introduction-to-langchain-building-ai-powered-apps/</guid>
      <description>&lt;p&gt;LangChain composes LLM calls with prompts, memory, tools, and retrieval. It standardizes patterns that every AI app eventually needs.&lt;/p&gt;&#xA;&lt;h2 id=&#34;chains-and-prompts&#34;&gt;Chains and Prompts&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#719e07&#34;&gt;from&lt;/span&gt; langchain_openai &lt;span style=&#34;color:#719e07&#34;&gt;import&lt;/span&gt; ChatOpenAI&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#719e07&#34;&gt;from&lt;/span&gt; langchain_core.prompts &lt;span style=&#34;color:#719e07&#34;&gt;import&lt;/span&gt; ChatPromptTemplate&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;llm &lt;span style=&#34;color:#719e07&#34;&gt;=&lt;/span&gt; ChatOpenAI(model&lt;span style=&#34;color:#719e07&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;gpt-4&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;prompt &lt;span style=&#34;color:#719e07&#34;&gt;=&lt;/span&gt; ChatPromptTemplate&lt;span style=&#34;color:#719e07&#34;&gt;.&lt;/span&gt;from_messages([&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;system&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;Answer as a senior engineer.&amp;#34;&lt;/span&gt;),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;user&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#2aa198&#34;&gt;{question}&lt;/span&gt;&lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;&lt;/span&gt;),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;])&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chain &lt;span style=&#34;color:#719e07&#34;&gt;=&lt;/span&gt; prompt &lt;span style=&#34;color:#719e07&#34;&gt;|&lt;/span&gt; llm&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;response &lt;span style=&#34;color:#719e07&#34;&gt;=&lt;/span&gt; chain&lt;span style=&#34;color:#719e07&#34;&gt;.&lt;/span&gt;invoke({&lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;question&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;What is RAG?&amp;#34;&lt;/span&gt;})&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;retrieval&#34;&gt;Retrieval&lt;/h2&gt;&#xA;&lt;p&gt;Load documents, chunk text, embed with OpenAI or open models, store in a vector DB, and retrieve relevant chunks at query time-foundation for RAG systems.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Getting Started with the OpenAI API in Node.js</title>
      <link>https://www.davidlang.tech/posts/getting-started-with-the-openai-api-in-nodejs/</link>
      <pubDate>Thu, 12 Jan 2023 00:00:00 +0000</pubDate>
      <guid>https://www.davidlang.tech/posts/getting-started-with-the-openai-api-in-nodejs/</guid>
      <description>&lt;p&gt;The OpenAI API brought large language models to application developers through a simple HTTP interface. Node.js remains a natural fit for BFF layers that call LLMs.&lt;/p&gt;&#xA;&lt;h2 id=&#34;installation-and-first-request&#34;&gt;Installation and First Request&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm install openai&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-typescript&#34; data-lang=&#34;typescript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#268bd2&#34;&gt;import&lt;/span&gt; OpenAI &lt;span style=&#34;color:#268bd2&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#39;openai&amp;#39;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#268bd2&#34;&gt;const&lt;/span&gt; client &lt;span style=&#34;color:#719e07&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#719e07&#34;&gt;new&lt;/span&gt; OpenAI({ apiKey: &lt;span style=&#34;color:#dc322f&#34;&gt;process.env.OPENAI_API_KEY&lt;/span&gt; });&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#268bd2&#34;&gt;const&lt;/span&gt; completion &lt;span style=&#34;color:#719e07&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#719e07&#34;&gt;await&lt;/span&gt; client.chat.completions.create({&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  model&lt;span style=&#34;color:#719e07&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#39;gpt-4&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  messages&lt;span style=&#34;color:#719e07&#34;&gt;:&lt;/span&gt; [&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    { role&lt;span style=&#34;color:#719e07&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#39;system&amp;#39;&lt;/span&gt;, content&lt;span style=&#34;color:#719e07&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#39;You are a helpful coding assistant.&amp;#39;&lt;/span&gt; },&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    { role&lt;span style=&#34;color:#719e07&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#39;user&amp;#39;&lt;/span&gt;, content&lt;span style=&#34;color:#719e07&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#39;Explain async/await in JavaScript.&amp;#39;&lt;/span&gt; },&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ],&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;console.log(completion.choices[&lt;span style=&#34;color:#2aa198&#34;&gt;0&lt;/span&gt;].message.content);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;production-considerations&#34;&gt;Production Considerations&lt;/h2&gt;&#xA;&lt;p&gt;Never expose API keys in frontend bundles. Proxy requests through your backend. Set &lt;code&gt;max_tokens&lt;/code&gt;, timeouts, and retry policies. Log token usage for cost control.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Prisma ORM: Modern Database Access in Node.js</title>
      <link>https://www.davidlang.tech/posts/prisma-orm-modern-database-access-in-nodejs/</link>
      <pubDate>Tue, 07 Dec 2021 00:00:00 +0000</pubDate>
      <guid>https://www.davidlang.tech/posts/prisma-orm-modern-database-access-in-nodejs/</guid>
      <description>&lt;p&gt;Prisma provides type-safe database access, migrations, and a visual data browser-popular in TypeScript full stack projects.&lt;/p&gt;&#xA;&lt;h2 id=&#34;schema-definition&#34;&gt;Schema Definition&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;model User {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  id        String   @id @default(cuid())&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  email     String   @unique&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  posts     Post[]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  createdAt DateTime @default(now())&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;model Post {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  id       String @id @default(cuid())&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  title    String&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  author   User   @relation(fields: [authorId], references: [id])&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  authorId String&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;queries&#34;&gt;Queries&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-typescript&#34; data-lang=&#34;typescript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#268bd2&#34;&gt;const&lt;/span&gt; users &lt;span style=&#34;color:#719e07&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#719e07&#34;&gt;await&lt;/span&gt; prisma.user.findMany({&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  include&lt;span style=&#34;color:#719e07&#34;&gt;:&lt;/span&gt; { posts: &lt;span style=&#34;color:#dc322f&#34;&gt;true&lt;/span&gt; },&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  where&lt;span style=&#34;color:#719e07&#34;&gt;:&lt;/span&gt; { email&lt;span style=&#34;color:#719e07&#34;&gt;:&lt;/span&gt; { contains&lt;span style=&#34;color:#719e07&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#39;@company.com&amp;#39;&lt;/span&gt; } },&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;migrations&#34;&gt;Migrations&lt;/h2&gt;&#xA;&lt;p&gt;&lt;code&gt;npx prisma migrate dev&lt;/code&gt; applies schema changes in development. Use &lt;code&gt;prisma generate&lt;/code&gt; after schema edits to refresh the client.&lt;/p&gt;</description>
    </item>
    <item>
      <title>MongoDB Best Practices: Schema Design and Indexing</title>
      <link>https://www.davidlang.tech/posts/mongodb-best-practices-schema-design-and-indexing/</link>
      <pubDate>Mon, 25 Oct 2021 00:00:00 +0000</pubDate>
      <guid>https://www.davidlang.tech/posts/mongodb-best-practices-schema-design-and-indexing/</guid>
      <description>&lt;p&gt;MongoDB&amp;rsquo;s flexible documents are powerful-but schema design still matters for performance and maintainability.&lt;/p&gt;&#xA;&lt;h2 id=&#34;embedding-vs-referencing&#34;&gt;Embedding vs Referencing&lt;/h2&gt;&#xA;&lt;p&gt;Embed when data is read together and has a one-to-few relationship (user preferences inside a user doc). Reference when data grows unbounded or is shared (comments on posts).&lt;/p&gt;&#xA;&lt;h2 id=&#34;indexing&#34;&gt;Indexing&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;db.orders.createIndex({ customerId&lt;span style=&#34;color:#719e07&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#2aa198&#34;&gt;1&lt;/span&gt;, createdAt&lt;span style=&#34;color:#719e07&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#719e07&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#2aa198&#34;&gt;1&lt;/span&gt; });&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Compound indexes support queries that filter and sort on the same fields. Use &lt;code&gt;.explain()&lt;/code&gt; to verify index usage.&lt;/p&gt;&#xA;&lt;h2 id=&#34;validation-and-migrations&#34;&gt;Validation and Migrations&lt;/h2&gt;&#xA;&lt;p&gt;Use JSON Schema validation at the collection level. Version documents with a &lt;code&gt;schemaVersion&lt;/code&gt; field for gradual migrations.&lt;/p&gt;</description>
    </item>
    <item>
      <title>WebSockets with Node.js: Real-Time Applications</title>
      <link>https://www.davidlang.tech/posts/websockets-with-nodejs-real-time-applications/</link>
      <pubDate>Wed, 30 Jun 2021 00:00:00 +0000</pubDate>
      <guid>https://www.davidlang.tech/posts/websockets-with-nodejs-real-time-applications/</guid>
      <description>&lt;p&gt;WebSockets provide full-duplex communication over a single TCP connection-ideal for chat, live dashboards, and collaborative editing.&lt;/p&gt;&#xA;&lt;h2 id=&#34;socketio-setup&#34;&gt;Socket.io Setup&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#268bd2&#34;&gt;const&lt;/span&gt; { Server } &lt;span style=&#34;color:#719e07&#34;&gt;=&lt;/span&gt; require(&lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#39;socket.io&amp;#39;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#268bd2&#34;&gt;const&lt;/span&gt; io &lt;span style=&#34;color:#719e07&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#719e07&#34;&gt;new&lt;/span&gt; Server(httpServer, { cors&lt;span style=&#34;color:#719e07&#34;&gt;:&lt;/span&gt; { origin&lt;span style=&#34;color:#719e07&#34;&gt;:&lt;/span&gt; process.env.CLIENT_URL } });&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;io.on(&lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#39;connection&amp;#39;&lt;/span&gt;, (socket) =&amp;gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  socket.on(&lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#39;join-room&amp;#39;&lt;/span&gt;, (roomId) =&amp;gt; socket.join(roomId));&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  socket.on(&lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#39;message&amp;#39;&lt;/span&gt;, (payload) =&amp;gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    io.to(payload.roomId).emit(&lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#39;message&amp;#39;&lt;/span&gt;, payload);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  });&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;scaling-considerations&#34;&gt;Scaling Considerations&lt;/h2&gt;&#xA;&lt;p&gt;Use Redis adapter for Socket.io when running multiple server instances. Sticky sessions or shared pub/sub keep room state consistent.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Building Microservices with Node.js</title>
      <link>https://www.davidlang.tech/posts/building-microservices-with-nodejs/</link>
      <pubDate>Sat, 22 May 2021 00:00:00 +0000</pubDate>
      <guid>https://www.davidlang.tech/posts/building-microservices-with-nodejs/</guid>
      <description>&lt;p&gt;Microservices split a system into independently deployable services. Node.js is a common choice for I/O-bound services, BFF layers, and event-driven workers.&lt;/p&gt;&#xA;&lt;h2 id=&#34;service-boundaries&#34;&gt;Service Boundaries&lt;/h2&gt;&#xA;&lt;p&gt;Split by business capability-not by technical layer. A &lt;code&gt;orders&lt;/code&gt; service owns order data; a &lt;code&gt;notifications&lt;/code&gt; service sends email. Communicate via REST, gRPC, or message queues (RabbitMQ, Kafka).&lt;/p&gt;&#xA;&lt;h2 id=&#34;resilience-patterns&#34;&gt;Resilience Patterns&lt;/h2&gt;&#xA;&lt;p&gt;Implement timeouts, retries with exponential backoff, and circuit breakers. Use correlation IDs across services for distributed tracing (OpenTelemetry).&lt;/p&gt;</description>
    </item>
    <item>
      <title>JWT Authentication: Securing Your REST API</title>
      <link>https://www.davidlang.tech/posts/jwt-authentication-securing-your-rest-api/</link>
      <pubDate>Sat, 05 Sep 2020 00:00:00 +0000</pubDate>
      <guid>https://www.davidlang.tech/posts/jwt-authentication-securing-your-rest-api/</guid>
      <description>&lt;p&gt;JSON Web Tokens (JWT) are a compact way to represent claims between parties. For stateless REST APIs and SPAs, JWT-based auth is a standard pattern-when implemented correctly.&lt;/p&gt;&#xA;&lt;h2 id=&#34;token-structure&#34;&gt;Token Structure&lt;/h2&gt;&#xA;&lt;p&gt;A JWT has three Base64-encoded parts: header, payload, and signature. The server signs the token with a secret (HS256) or private key (RS256). Clients send &lt;code&gt;Authorization: Bearer &amp;lt;token&amp;gt;&lt;/code&gt; on each request.&lt;/p&gt;&#xA;&lt;h2 id=&#34;issuing-tokens-in-nodejs&#34;&gt;Issuing Tokens in Node.js&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#268bd2&#34;&gt;const&lt;/span&gt; jwt &lt;span style=&#34;color:#719e07&#34;&gt;=&lt;/span&gt; require(&lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#39;jsonwebtoken&amp;#39;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#268bd2&#34;&gt;function&lt;/span&gt; login(req, res) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#268bd2&#34;&gt;const&lt;/span&gt; user &lt;span style=&#34;color:#719e07&#34;&gt;=&lt;/span&gt; validateCredentials(req.body);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#719e07&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#719e07&#34;&gt;!&lt;/span&gt;user) &lt;span style=&#34;color:#719e07&#34;&gt;return&lt;/span&gt; res.status(&lt;span style=&#34;color:#2aa198&#34;&gt;401&lt;/span&gt;).json({ error&lt;span style=&#34;color:#719e07&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#39;Invalid credentials&amp;#39;&lt;/span&gt; });&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#268bd2&#34;&gt;const&lt;/span&gt; token &lt;span style=&#34;color:#719e07&#34;&gt;=&lt;/span&gt; jwt.sign(&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    { sub&lt;span style=&#34;color:#719e07&#34;&gt;:&lt;/span&gt; user.id, role&lt;span style=&#34;color:#719e07&#34;&gt;:&lt;/span&gt; user.role },&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    process.env.JWT_SECRET,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    { expiresIn&lt;span style=&#34;color:#719e07&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#39;1h&amp;#39;&lt;/span&gt; }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  );&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  res.json({ token });&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;middleware-verification&#34;&gt;Middleware Verification&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#268bd2&#34;&gt;function&lt;/span&gt; authMiddleware(req, res, next) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#268bd2&#34;&gt;const&lt;/span&gt; header &lt;span style=&#34;color:#719e07&#34;&gt;=&lt;/span&gt; req.headers.authorization;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#719e07&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#719e07&#34;&gt;!&lt;/span&gt;header&lt;span style=&#34;color:#719e07&#34;&gt;?&lt;/span&gt;.startsWith(&lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#39;Bearer &amp;#39;&lt;/span&gt;)) &lt;span style=&#34;color:#719e07&#34;&gt;return&lt;/span&gt; res.sendStatus(&lt;span style=&#34;color:#2aa198&#34;&gt;401&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#719e07&#34;&gt;try&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    req.user &lt;span style=&#34;color:#719e07&#34;&gt;=&lt;/span&gt; jwt.verify(header.slice(&lt;span style=&#34;color:#2aa198&#34;&gt;7&lt;/span&gt;), process.env.JWT_SECRET);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    next();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  } &lt;span style=&#34;color:#719e07&#34;&gt;catch&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    res.sendStatus(&lt;span style=&#34;color:#2aa198&#34;&gt;401&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;security-checklist&#34;&gt;Security Checklist&lt;/h2&gt;&#xA;&lt;p&gt;Keep secrets out of source control. Use short expiration and refresh tokens for long sessions. Never store sensitive data in the payload-it is readable. Prefer HTTPS everywhere.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Introduction to GraphQL: Why It Matters</title>
      <link>https://www.davidlang.tech/posts/introduction-to-graphql-why-it-matters/</link>
      <pubDate>Sat, 25 Jul 2020 00:00:00 +0000</pubDate>
      <guid>https://www.davidlang.tech/posts/introduction-to-graphql-why-it-matters/</guid>
      <description>&lt;p&gt;GraphQL is a query language for APIs that lets clients request exactly the fields they need. Unlike REST, you avoid over-fetching and under-fetching by design.&lt;/p&gt;&#xA;&lt;h2 id=&#34;schema-first-design&#34;&gt;Schema-First Design&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-graphql&#34; data-lang=&#34;graphql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#268bd2&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#268bd2&#34;&gt;Query&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  user(id: &lt;span style=&#34;color:#268bd2&#34;&gt;ID&lt;/span&gt;!): &lt;span style=&#34;color:#268bd2&#34;&gt;User&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  posts(limit: &lt;span style=&#34;color:#268bd2&#34;&gt;Int&lt;/span&gt; = 10): [&lt;span style=&#34;color:#268bd2&#34;&gt;Post&lt;/span&gt;!]!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#268bd2&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#268bd2&#34;&gt;User&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  id: &lt;span style=&#34;color:#268bd2&#34;&gt;ID&lt;/span&gt;!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  name: &lt;span style=&#34;color:#268bd2&#34;&gt;String&lt;/span&gt;!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  posts: [&lt;span style=&#34;color:#268bd2&#34;&gt;Post&lt;/span&gt;!]!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Clients send queries that mirror the shape of the response:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-graphql&#34; data-lang=&#34;graphql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#268bd2&#34;&gt;query&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#268bd2&#34;&gt;user&lt;/span&gt;(id: &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#268bd2&#34;&gt;name&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    posts(limit: &lt;span style=&#34;color:#268bd2&#34;&gt;5&lt;/span&gt;) { title createdAt }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;server-implementation&#34;&gt;Server Implementation&lt;/h2&gt;&#xA;&lt;p&gt;Apollo Server and GraphQL Yoga are popular in Node.js. Resolvers map fields to databases or microservices. Use DataLoader to batch N+1 queries.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Docker for Developers: Containerizing Your Node.js App</title>
      <link>https://www.davidlang.tech/posts/docker-for-developers-containerizing-your-nodejs-app/</link>
      <pubDate>Sat, 30 May 2020 00:00:00 +0000</pubDate>
      <guid>https://www.davidlang.tech/posts/docker-for-developers-containerizing-your-nodejs-app/</guid>
      <description>&lt;p&gt;Docker packages your application and its dependencies into a portable image. For Node.js APIs and React frontends, containers ensure dev, CI, and production environments behave the same way.&lt;/p&gt;&#xA;&lt;h2 id=&#34;a-production-ready-dockerfile&#34;&gt;A Production-Ready Dockerfile&lt;/h2&gt;&#xA;&lt;p&gt;Multi-stage builds keep images small:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-dockerfile&#34; data-lang=&#34;dockerfile&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#719e07&#34;&gt;FROM&lt;/span&gt; &lt;span style=&#34;color:#2aa198&#34;&gt;node:20-alpine&lt;/span&gt; &lt;span style=&#34;color:#719e07&#34;&gt;AS&lt;/span&gt; &lt;span style=&#34;color:#2aa198&#34;&gt;build&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#719e07&#34;&gt;WORKDIR&lt;/span&gt; &lt;span style=&#34;color:#2aa198&#34;&gt;/app&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#719e07&#34;&gt;COPY&lt;/span&gt; package*.json ./&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#719e07&#34;&gt;RUN&lt;/span&gt; npm ci&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#719e07&#34;&gt;COPY&lt;/span&gt; . .&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#719e07&#34;&gt;RUN&lt;/span&gt; npm run build&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#719e07&#34;&gt;FROM&lt;/span&gt; &lt;span style=&#34;color:#2aa198&#34;&gt;node:20-alpine&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#719e07&#34;&gt;WORKDIR&lt;/span&gt; &lt;span style=&#34;color:#2aa198&#34;&gt;/app&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#719e07&#34;&gt;COPY&lt;/span&gt; --from&lt;span style=&#34;color:#719e07&#34;&gt;=&lt;/span&gt;build /app/dist ./dist&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#719e07&#34;&gt;COPY&lt;/span&gt; --from&lt;span style=&#34;color:#719e07&#34;&gt;=&lt;/span&gt;build /app/node_modules ./node_modules&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#719e07&#34;&gt;ENV&lt;/span&gt; &lt;span style=&#34;color:#268bd2&#34;&gt;NODE_ENV&lt;/span&gt;&lt;span style=&#34;color:#719e07&#34;&gt;=&lt;/span&gt;production&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#719e07&#34;&gt;EXPOSE&lt;/span&gt; &lt;span style=&#34;color:#2aa198&#34;&gt;3000&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#719e07&#34;&gt;CMD&lt;/span&gt; [&lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;node&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#34;dist/server.js&amp;#34;&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;docker-compose-for-local-dev&#34;&gt;docker-compose for Local Dev&lt;/h2&gt;&#xA;&lt;p&gt;Pair your API with PostgreSQL or Redis:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Building REST APIs with Node.js and Express</title>
      <link>https://www.davidlang.tech/posts/building-rest-apis-with-nodejs-and-express/</link>
      <pubDate>Sun, 22 Mar 2020 00:00:00 +0000</pubDate>
      <guid>https://www.davidlang.tech/posts/building-rest-apis-with-nodejs-and-express/</guid>
      <description>&lt;p&gt;Express remains the most popular framework for building REST APIs in Node.js. It is minimal, unopinionated, and pairs well with middleware for auth, validation, and logging.&lt;/p&gt;&#xA;&lt;h2 id=&#34;project-setup&#34;&gt;Project Setup&lt;/h2&gt;&#xA;&lt;p&gt;Initialize a project and install Express:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm init -y&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm install express&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Create a basic server with JSON body parsing:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#268bd2&#34;&gt;const&lt;/span&gt; express &lt;span style=&#34;color:#719e07&#34;&gt;=&lt;/span&gt; require(&lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#39;express&amp;#39;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#268bd2&#34;&gt;const&lt;/span&gt; app &lt;span style=&#34;color:#719e07&#34;&gt;=&lt;/span&gt; express();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;app.use(express.json());&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#268bd2&#34;&gt;const&lt;/span&gt; items &lt;span style=&#34;color:#719e07&#34;&gt;=&lt;/span&gt; [];&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;app.get(&lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#39;/api/items&amp;#39;&lt;/span&gt;, (req, res) =&amp;gt; res.json(items));&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;app.post(&lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#39;/api/items&amp;#39;&lt;/span&gt;, (req, res) =&amp;gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#268bd2&#34;&gt;const&lt;/span&gt; item &lt;span style=&#34;color:#719e07&#34;&gt;=&lt;/span&gt; { id&lt;span style=&#34;color:#719e07&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b58900&#34;&gt;Date&lt;/span&gt;.now(), ...req.body };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  items.push(item);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  res.status(&lt;span style=&#34;color:#2aa198&#34;&gt;201&lt;/span&gt;).json(item);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;app.listen(&lt;span style=&#34;color:#2aa198&#34;&gt;3000&lt;/span&gt;, () =&amp;gt; console.log(&lt;span style=&#34;color:#2aa198&#34;&gt;&amp;#39;API running on :3000&amp;#39;&lt;/span&gt;));&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;structure-for-production&#34;&gt;Structure for Production&lt;/h2&gt;&#xA;&lt;p&gt;Organize routes by resource (&lt;code&gt;/users&lt;/code&gt;, &lt;code&gt;/orders&lt;/code&gt;), use a router per domain, and separate controllers from route definitions. Add &lt;code&gt;helmet&lt;/code&gt; for security headers, &lt;code&gt;cors&lt;/code&gt; for cross-origin access, and a centralized error handler that returns consistent JSON error shapes.&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
