<?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>Forem: Drew Schillinger</title>
    <description>The latest articles on Forem by Drew Schillinger (@doctorew).</description>
    <link>https://forem.com/doctorew</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%2F740976%2Fab288a59-9f30-4803-a48a-9dc7d9ddae28.png</url>
      <title>Forem: Drew Schillinger</title>
      <link>https://forem.com/doctorew</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/doctorew"/>
    <language>en</language>
    <item>
      <title>Public vs. Private LLMs: Another One Rides the Bus</title>
      <dc:creator>Drew Schillinger</dc:creator>
      <pubDate>Sat, 16 Aug 2025 03:02:26 +0000</pubDate>
      <link>https://forem.com/doctorew/public-vs-private-llms-another-one-rides-the-bus-37a7</link>
      <guid>https://forem.com/doctorew/public-vs-private-llms-another-one-rides-the-bus-37a7</guid>
      <description>&lt;p&gt;Weird Al popped into my head at lunch this week (not exactly unusual if we're being honest) while I was talking with a friend about the pros and cons of public vs. private LLMs. We work in wildly different industries, with vastly different AI experience — he's just starting to explore LLMs, and I've been building GPT-powered pipelines since the GPT-2 days — yet our perspectives on the tech, the people, and the problems lined up almost perfectly.&lt;/p&gt;

&lt;p&gt;Somewhere in our conversation about data sanitization and between bites (&lt;em&gt;Just Eat It!&lt;/em&gt;), the line from &lt;em&gt;Another One Rides The Bus&lt;/em&gt; popped into my head:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Ridin' in the bus down the boulevard, and the place was pretty packed… It was smellin' like a locker room // There was junk all over the floor…&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It fit our conversation perfectly. What happens when you don't want your proprietary dataset helping your competitors — or worse, seeing traces of their &lt;em&gt;smelly data&lt;/em&gt; (my friend's words) in your results?&lt;/p&gt;

&lt;p&gt;And then there's reliability. The bus can break down — sometimes for minutes, sometimes for hours — and you're stuck on the curb waiting for service to resume. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzmcwu1q1s3slw9sgkdc6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzmcwu1q1s3slw9sgkdc6.png" alt="ChatGPT Down" width="800" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or maybe the bus driver (read: OpenAI, Anthropic, Google, etc.) decides overnight to change the route entirely. One day you're happily riding GPT-4o, the next you're handed GPT-5 — a completely different personality — without so much as a stop-announcement. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flkrp5b53wop9ptb1nl9s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flkrp5b53wop9ptb1nl9s.png" alt="personalities of 4o vs 5" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's not hypothetical; it happened this past week with the replacement of GPT-4o with 5, and the uproar from developers and end-users alike was proof that we've all gotten a bit too comfortable trusting someone else's transit map.&lt;/p&gt;

&lt;p&gt;To quote a comment (&lt;a href="https://www.linkedin.com/in/jimdiroffii/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/jimdiroffii/&lt;/a&gt;) I read on LI:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Imagine if when Python 3 was released, the public wasn't allowed to test it, and all access to Python 2 was simultaneously restricted. It would have been calamitous."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When you're dependent on someone else's fleet, you inherit their scheduling, their maintenance priorities, and their budget decisions — even if those decisions wreck your carefully tuned workflows. In other words: you might be paying for a ticket, but you're not steering the wheel.&lt;/p&gt;

&lt;p&gt;Weird Al might have been singing about public transportation, but the analogy works frighteningly well for public Large Language Models (LLMs) like GPT, Gemini, Perplexity, Grok, or Claude: easy to hop on, zero maintenance (for us), and they usually get you where you need to go. Usually. But when &lt;em&gt;another one rides the bus&lt;/em&gt; — or a few million others do — the limitations of a shared ride become very clear.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Private LLMs: Owning the Car&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;If public LLMs are the bus, then private LLMs are your own set of wheels. You choose the route, pick the passengers, and set the speed — no surprise detours (unless something doesn't build, a dependency doesn’t work), no mystery riders peeking into your data, and definitely no &lt;em&gt;smelly data&lt;/em&gt; stinking up the back seat.&lt;/p&gt;

&lt;p&gt;But car ownership isn't free. Running your own model — whether on-prem, in a private cloud, or on rented GPUs — means you're paying for the &lt;em&gt;car&lt;/em&gt; &lt;strong&gt;and&lt;/strong&gt; the &lt;em&gt;garage&lt;/em&gt;. The garage is the capital expenditure (or OpEx if you're renting) of the infrastructure: racks of servers, high-end GPUs that can run into the tens of thousands each (or \$2–\$5/hour per A100/H100 on AWS if you're renting &lt;a href="https://www.trgdatacenters.com/resource/aws-gpu-pricing/" rel="noopener noreferrer"&gt;source&lt;/a&gt;), the network backbone, and the cooling and power to keep it all alive.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fatc8y6yob63i3tis2avs.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fatc8y6yob63i3tis2avs.jpg" alt="Pricey cars" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then there's the &lt;em&gt;gas&lt;/em&gt;: training your models isn't just costly in dollars — it burns time, patience, and talent. Fine-tuning or pretraining requires huge datasets, long-running compute jobs, and often, iteration after iteration before you get something production-worthy.&lt;/p&gt;

&lt;p&gt;Owning the car also means you're both the &lt;strong&gt;driver&lt;/strong&gt; and the &lt;strong&gt;mechanic&lt;/strong&gt;. You handle the monitoring, patching, scaling, and security hardening. You plan the oil changes (retraining schedules) and replace the tires (deprecated libraries and outdated dependencies). You keep a constant eye on performance, guard against drift, and respond fast if something breaks down at 2 a.m.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flsj2ais6sz9cwfpyvdr2.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flsj2ais6sz9cwfpyvdr2.webp" alt="Car breakdowns" width="765" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And don't overlook the &lt;em&gt;opportunity cost&lt;/em&gt;. Every hour our engineers spend babysitting infrastructure and wrangling GPUs is an hour they're not building new customer-facing features — the stuff that actually differentiates your brand and makes money.&lt;/p&gt;

&lt;p&gt;If public LLMs sometimes feel like a noisy city bus at rush hour, private models are the quiet, climate-controlled road trip where you control the playlist. But that playlist comes with a service manual — and you're the one holding the wrench.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Choosing Your Ride&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Whether you're boarding the bus or grabbing the keys, the choice between public and private LLMs boils down to trade-offs. Public models are fast, cheap to board, and require zero maintenance — but you share the ride, the baggage, and the consequences when the driver changes the route without warning. Private models give you control over every turn of the wheel, every passenger, and every mile per hour — but you pay for the privilege in cost, complexity, and upkeep.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi19jgu8yet7yxhdm91ic.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi19jgu8yet7yxhdm91ic.jpg" alt="Busy town traffic" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Public vs. Private LLMs at a Glance&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Public LLMs – The Bus&lt;/strong&gt;&lt;br&gt;
[✓] Fast boarding — API key and go&lt;br&gt;
[✓] Maintenance-free — someone else handles scaling and patches&lt;br&gt;
[✓] Great for quick, low-sensitivity projects&lt;br&gt;
[!] Noisy neighbors can cause slowdowns&lt;br&gt;
[!] Shared baggage — your data may mix into the communal pool&lt;br&gt;
[!] Privacy leaks possible&lt;br&gt;
[!] Routes change without notice (model swaps, price hikes)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Private LLMs – The Car&lt;/strong&gt;&lt;br&gt;
[✓] Full control over architecture, data, and updates&lt;br&gt;
[✓] No smelly data from competitors&lt;br&gt;
[✓] Fine-tuned for your exact needs&lt;br&gt;
[✓] Predictable privacy boundaries&lt;br&gt;
[!] You’re the driver &lt;em&gt;and&lt;/em&gt; the mechanic&lt;br&gt;
[!] Gas isn’t cheap — GPUs, training costs, MLOps overhead&lt;br&gt;
[!] Longer on-ramp to production&lt;br&gt;
[!] Feature velocity can slow if you’re stuck under the hood&lt;/p&gt;




&lt;p&gt;In the end, it's about priorities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Need speed, flexibility, and low commitment?&lt;/strong&gt; Hop on the bus and enjoy the ride.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Need control, privacy, and consistency?&lt;/strong&gt; Grab the keys and drive yourself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just remember: in both cases, you're not immune to road hazards. Public buses can get rerouted without notice, and private cars can break down if you skip maintenance. &lt;/p&gt;

&lt;p&gt;You could be sharing a spot that's &lt;em&gt;"smellin' like a locker room [with] junk all over the floor"&lt;/em&gt; or take more time than expected training your model.&lt;/p&gt;

&lt;p&gt;The trick is knowing which trade-offs you can live with — and which ones will leave you stranded by the side of the road, humming Weird Al while you wait for a tow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdflnumrgcswi63k6o7we.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdflnumrgcswi63k6o7we.jpg" alt="Weird AI" width="728" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>llm</category>
      <category>chatgpt</category>
      <category>ai</category>
      <category>aiops</category>
    </item>
    <item>
      <title>Building a RAG Chatbot with LlamaIndex and eBay API Integration</title>
      <dc:creator>Drew Schillinger</dc:creator>
      <pubDate>Tue, 20 Aug 2024 21:52:12 +0000</pubDate>
      <link>https://forem.com/doctorew/building-a-rag-chatbot-with-llamaindex-and-ebay-api-integration-2kee</link>
      <guid>https://forem.com/doctorew/building-a-rag-chatbot-with-llamaindex-and-ebay-api-integration-2kee</guid>
      <description>&lt;p&gt;RAG (Retrieval-Augmented Generation) is all the rage. And there's a good reason why. Like so many others, I instinctively felt an air of excitement at the beginning of the internet. The Browser Wars, Java vs Mocha. And then again in 2007 when the iPhone led a paradigm shift to how, where, and when we consume media. Just as I do now,&lt;/p&gt;

&lt;p&gt;In the rapidly advancing field of AI, Retrieval-Augmented Generation (RAG) has become a crucial technique, enhancing the capabilities of large language models by integrating external knowledge sources. By leveraging RAG, you can build chatbots that generate responses informed by real-time data, ensuring both coherence and relevance. This guide will provide you with a step-by-step walkthrough of integrating the eBay API with LlamaIndex to develop your own RAG-powered chatbot.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Why RAG?&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;RAG enhances the capabilities of your chatbot by allowing it to access and retrieve information from external sources in real time. Instead of relying solely on pre-trained data, your chatbot can now query external APIs or databases to obtain the most relevant and up-to-date information. This ensures that the responses generated are not only accurate but also contextually relevant, reflecting the latest available data. It’s like moving from managing a static collection of DVDs or Blu-Rays to streaming on-demand content, where the latest information is always at your fingertips.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Step 1: Setting Up LlamaIndex&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;To kick off, you’ll need to set up LlamaIndex, a powerful tool that simplifies the integration of external data sources into your chatbot.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Installation&lt;/strong&gt;: Start by running the following command in your terminal:
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;npx create-llama@latest&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;This command scaffolds out a Next.js project and walks you through the initial setup, including key concepts of RAG and LLMs like document scraping and multi-agent systems. It will provide sample pdfs to work off of. You'll want to remove this if you have an idea in mind, or expect to scrape the web, and want to host your app on a worker like Vercel or Cloudflare.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Configuration&lt;/strong&gt;: Once the setup is complete, navigate to the &lt;code&gt;llama.config.js&lt;/code&gt; file. Here, you’ll define the sources your chatbot will retrieve information from. For our purposes, we’ll be focusing on integrating the eBay API.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Step 2: Integrating the eBay API&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Now, let's connect your chatbot to the vast repository of data available through the eBay API.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;OAuth Authentication&lt;/strong&gt;: eBay’s API requires OAuth for secure access. You’ll first need to generate an OAuth token. Here’s a quick function to handle this:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const eBayAuthToken = require("ebay-oauth-nodejs-client");

const ebayClientId = process.env.EBAY_API_KEY || "";
const ebayClientSecret = process.env.EBAY_CLIENT_SECRET || "";
const redirectUri = process.env.EBAY_REDIRECT_URI || ""; // Optional unless you're doing user consent flow

const authToken = new eBayAuthToken({
  clientId: ebayClientId,
  clientSecret: ebayClientSecret,
  redirectUri: redirectUri, // Optional unless you're doing user consent flow
});

let cachedToken: string | null = null;
let tokenExpiration: number | null = null;

export async function getOAuthToken(): Promise&amp;lt;string | null&amp;gt; {
  if (cachedToken &amp;amp;&amp;amp; tokenExpiration &amp;amp;&amp;amp; Date.now() &amp;lt; tokenExpiration) {
    return cachedToken;
  }

  try {
    const response = await authToken.getApplicationToken("PRODUCTION"); // or 'SANDBOX'
    let tokenData;

    if (typeof response === "string") {
      // Parse the response string into a JSON object
      tokenData = JSON.parse(response);
    } else {
      tokenData = response;
    }

    cachedToken = tokenData.access_token;
    tokenExpiration = Date.now() + tokenData.expires_in * 1000 - 60000; // Set expiration time

    return cachedToken;
  } catch (error) {
    console.error("Error obtaining OAuth token:", error);
    throw new Error("Failed to obtain OAuth token");
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Replace `YOUR_BASE64_ENCODED_CREDENTIALS` with your actual credentials.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Fetching Data&lt;/strong&gt;: With your token in hand, you can now query the eBay API to fetch relevant data. Here’s how you can fetch the price of a specific item:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import axios from 'axios';

export async function fetchCardPrices(searchTerm: string) {
  const token = await getOAuthToken();
  if (!token) throw new Error("No OAuth token available");

  const response = await axios.get(`https://api.ebay.com/buy/browse/v1/item_summary/search?q=${encodeURIComponent(searchTerm)}`, {
    headers: {
      'Authorization': `Bearer ${token}`,
    },
  });

  return response.data.itemSummaries.map(item =&amp;gt; ({
    title: item.title,
    price: item.price.value,
    currency: item.price.currency,
  }));
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function returns an array of items with their titles and prices, which your chatbot can use to provide users with up-to-date information.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Step 3: Querying and Responding&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;With LlamaIndex and eBay integrated, it’s time to build the logic that allows your chatbot to query these sources and generate informed responses.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Extracting Search Terms&lt;/strong&gt;: Before querying the eBay API, you need to extract relevant search terms from the user's input. Here’s a helper function to do that:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function extractSearchTerm(query: string): string {
   // Simple keyword extraction logic
      return query.replace(/.*price of/i, '').trim();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Handling API Responses&lt;/strong&gt;: Finally, you can tie everything together by creating a route in your Next.js app to handle incoming requests, query eBay, and return the results:&lt;/p&gt;

&lt;p&gt;typescript&lt;br&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {NextApiRequest, NextApiResponse} from 'next';
import {fetchCardPrices} from './utils/fetchCardPrices';

export default async (req: NextApiRequest, res: NextApiResponse) =&amp;gt; {
    const query = req.query.q as string;
    const searchTerm = extractSearchTerm(query);
    const prices = await fetchCardPrices(searchTerm);
    res.status(200).json(prices);
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Challenges and Solutions&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;As you build your RAG chatbot, you might encounter some common pitfalls. For instance, I use GPT-4o and Claude Sonnet-3.5 as coding interns. While setting up LlamaIndex in a Python app, I asked GPT to help me debug and the code snippets were outdated.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;By following these steps, you’ve empowered your chatbot to fetch and utilize real-time data from eBay, enhancing its usefulness and relevance to your users. RAG is a powerful technique that unlocks a wide range of possibilities, and with the right tools and guidance, you can leverage it to create truly intelligent applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Deploying to Vercel: Challenges with Edge Functions&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;When it comes to deploying your application on Vercel, it's important to be aware of some limitations, particularly when using edge functions. Vercel's edge functions are designed for low-latency responses, but they do come with some constraints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Unsupported Modules on Edge Functions&lt;/strong&gt;: Certain Node.js modules, like &lt;code&gt;sharp&lt;/code&gt; and &lt;code&gt;onnxruntime-node&lt;/code&gt;, are not supported in Vercel Edge Functions due to the limitations of the edge runtime environment. If your application relies on these modules, you'll need to ensure they are only used in serverless functions or consider replacing them with alternative solutions that are compatible with the edge environment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Module Not Found Errors&lt;/strong&gt;: You might encounter "Module not found" errors during the build process, especially when modules are not correctly installed or are being used in the wrong environment. To resolve these issues, double-check that all necessary modules are installed and that they are configured to run in the appropriate environment (Edge vs. Serverless). It's crucial to separate the logic that requires these modules from the parts of your app that run on the edge.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While Vercel provides a powerful platform for deploying your applications with minimal overhead, being mindful of these challenges will save you from headaches during deployment and ensure your app runs smoothly in production.&lt;/p&gt;

</description>
      <category>rag</category>
      <category>ai</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>OpenAI can detect ChatGPT-written content, but couldn't we all?</title>
      <dc:creator>Drew Schillinger</dc:creator>
      <pubDate>Thu, 08 Aug 2024 16:34:18 +0000</pubDate>
      <link>https://forem.com/doctorew/openai-can-detect-chatgpt-written-content-but-couldnt-we-all-17a8</link>
      <guid>https://forem.com/doctorew/openai-can-detect-chatgpt-written-content-but-couldnt-we-all-17a8</guid>
      <description>&lt;p&gt;&lt;a href="https://www.tomshardware.com/tech-industry/artificial-intelligence/openai-has-built-a-text-watermarking-method-to-detect-chatgpt-written-content-company-has-mulled-its-release-over-the-past-year" rel="noopener noreferrer"&gt;OpenAI has built a text watermarking method to detect ChatGPT-written content — company has mulled its release over the past year&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ah, the mouse has become the cat, now able to catch people "sneaking a cheat" and detect when content is crafted by AI. (My rendition of how AI writes.) &lt;/p&gt;

&lt;p&gt;Although GPT has made significant strides from 3.5 turbo to 4o, I thought it was obvious which content was written by a person and which was artificially generated. In fact, I've had to tone down my writing over the last few years. &lt;/p&gt;

&lt;p&gt;I am in that 69% camp of fearing and being falsely accused of using AI to write for me. My emails have always leaned a bit on the pedantic, academic, and "fussy" side. Years back, I was beyond proud achieving a Flesch-Kincaid grade level of 18. (I was an English major and always been a logophile after all). &lt;/p&gt;

&lt;p&gt;Commentary aside, I am very interested to watch this play out if it is true that GPT has been embedding thumbprint patterns in their responses. (and if that thumbprint looks like "ah, the old thumbprint in the code..."). &lt;/p&gt;

&lt;p&gt;On a side note, I have seen where some job posters surreptitiously embed a prompt for an AI bot to The debate surrounding this technology highlights the complex interplay between advancing AI capabilities and maintaining trust and transparency. &lt;/p&gt;

&lt;p&gt;As OpenAI continues to refine its approach, it remains crucial for users and developers alike to stay informed and critical, ensuring that the integration of AI into our daily lives is both ethical and beneficial. &lt;br&gt;
(Flesch-Kincaid grade level: 17.6)&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>chatgpt</category>
      <category>ai</category>
    </item>
    <item>
      <title>Building a Modern Full-Stack MonoRepo Application: A Journey with GraphQL, NextJS, Bun, and AWS</title>
      <dc:creator>Drew Schillinger</dc:creator>
      <pubDate>Sun, 26 Nov 2023 22:43:34 +0000</pubDate>
      <link>https://forem.com/doctorew/building-a-modern-full-stack-monorepo-application-a-journey-with-graphql-nextjs-bun-and-aws-4225</link>
      <guid>https://forem.com/doctorew/building-a-modern-full-stack-monorepo-application-a-journey-with-graphql-nextjs-bun-and-aws-4225</guid>
      <description>&lt;p&gt;Welcome to my exploration of building a modern full-stack application using a monorepo approach. With over 20 years of experience in web development, including roles at NBA.com, Adult Swim, and Goodr, I've had the opportunity to delve deeply into these various technologies. I just never took the time to write them up. And since I worked for companies with closed-source code and NDAs, it made sense to build something from the ground up!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pwag.doctorew.com/rick-and-morty/" rel="noopener noreferrer"&gt;Ricks Associated with their Morties&lt;/a&gt; is the NextJS running on CloudFront by way of Amplify and relying on a GraphQL Apollo "server" running on a lambda @ the Edge, both in a &lt;a href="https://github.com/doctor-ew/graph-spa-bun" rel="noopener noreferrer"&gt;monorepo&lt;/a&gt; that at some point used bun and then switched back to yarn:&lt;/p&gt;

&lt;p&gt;This blog post is a journey through a project leveraging GraphQL, Apollo Server, AWS Amplify, Lambda @ Edge, monorepos, and Progressive Web Apps (PWAs), demonstrating practical applications and insights gained along the way. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Project Overview:&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F79ktoabxpwen5l973f8i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F79ktoabxpwen5l973f8i.png" alt="Ricks and Morties" width="800" height="342"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This project was conceived as a coding challenge and a demonstration of integrating modern web technologies into a cohesive application. The core of this project involves leveraging GraphQL to interact with the open-source &lt;a href="https://rickandmortyapi.com/" rel="noopener noreferrer"&gt;Rick and Morty API&lt;/a&gt;, a task I often set for potential hires. &lt;/p&gt;

&lt;p&gt;This task was not just a technical exercise but also an opportunity to showcase my expertise in federating data via GraphQL, developing PWAs with NextJS, and experimenting with Bun, especially in relation to Express, Docker, and Serverless technologies. And as I write this blog entry, I am expanding my GraphQL resolver to include the Morties from the PocketMorties game.&lt;/p&gt;

&lt;p&gt;One of the unique aspects of this project was creating associations between Ricks and their corresponding Morties within the API—a relationship that doesn't exist in the original data sources. This challenge was an exciting way to demonstrate the power of GraphQL and my experience in crafting complex data relationships.&lt;/p&gt;

&lt;p&gt;In addition to GraphQL, the project also focused on exploring the capabilities of Bun, particularly its speed in compilation and Docker compatibility. However, practical challenges led to a pivot back to Yarn, highlighting the importance of choosing the right tool for the job and balancing efficiency with stability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deep Dives into Key Technologies
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Bun: Performance and Design Philosophy
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbt3yf8w6cjyicuzy1jun.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbt3yf8w6cjyicuzy1jun.png" alt="Bun's Speed" width="800" height="149"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Bun: Performance and Design Philosophy&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Bun emerged as a compelling choice for this project due to its significant differentiation from traditional package managers like NPM, Pnpm, and Yarn. It's built using Zig, a language known for its performance and safety, allowing for rapid task execution. Key features include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Speed&lt;/strong&gt;: Bun's core feature is its speed in various operations, from installing packages to running scripts, significantly outpacing traditional package managers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concurrency Model&lt;/strong&gt;: Unlike NPM and Yarn, Bun adopts a concurrency model similar to languages like Go, enabling efficient resource utilization and faster I/O-bound tasks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Package Installation&lt;/strong&gt;: Bun's approach to package installation, involving a global cache and concurrent downloading, contrasts with the more linear methods of NPM and Yarn.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Despite these advantages, practical challenges, such as the &lt;a href="https://github.com/oven-sh/bun/issues/4947" rel="noopener noreferrer"&gt;GraphQL integration issue&lt;/a&gt;, led me back to Yarn, emphasizing the need for stability in web development.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. AWS Amplify: Simplifying Cloud Integration
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://camo.githubusercontent.com/b0221b7ebe904cfd5e7b338a9aa49dd8a001a472f74ca69b14da60dc4d1f6abd/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6177732d6d6f62696c652d6875622d696d616765732f6177732d616d706c6966792d6c6f676f2e706e67" class="article-body-image-wrapper"&gt;&lt;img src="https://camo.githubusercontent.com/b0221b7ebe904cfd5e7b338a9aa49dd8a001a472f74ca69b14da60dc4d1f6abd/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6177732d6d6f62696c652d6875622d696d616765732f6177732d616d706c6966792d6c6f676f2e706e67" alt="AWS Amplify" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;#### The Role of AWS Amplify in the Project&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;AWS Amplify played a critical role in this project, streamlining the deployment and management of cloud services, and offering an integrated approach for both backend and frontend development. Amplify's suite of tools and services provided a cohesive platform that significantly simplified complex cloud operations.&lt;/p&gt;

&lt;h5&gt;
  
  
  Streamlined Workflow and Integration
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Streamlined Workflow&lt;/strong&gt;: Amplify's ability to abstract the complexities of cloud infrastructure provided a more user-friendly approach compared to managing custom Docker scripts. Its automated CI/CD pipelines facilitated continuous integration and delivery, ensuring a smooth deployment process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend and Frontend Integration&lt;/strong&gt;: Amplify's integration with backend AWS services and frontend optimizations, like server-side rendering and edge deployment, significantly enhanced the application's performance and user experience.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Cloud Storage, Delivery, and Security
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cloud Storage and Delivery&lt;/strong&gt;: Amplify utilized AWS S3 for storing front-end assets, ensuring high durability and availability. The integration with Amazon CloudFront, AWS's CDN, allowed for efficient content delivery, reducing latency and improving load times globally.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSL and Custom Domains&lt;/strong&gt;: The provision of SSL encryption and support for custom domains enhanced the security and brand identity of the application, making it more professional and trustworthy.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Amplify's Developer-Friendly Nature
&lt;/h5&gt;

&lt;p&gt;Amplify's developer-friendly interface, backed by extensive community support, made it a superior choice over custom Docker builds. This approach not only optimized the development process but also aligned with best practices for cloud-based applications.&lt;/p&gt;

&lt;h4&gt;
  
  
  Insights Gained from CloudFormation Designer Template
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6cf5k8hcuvcgsnirzfl1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6cf5k8hcuvcgsnirzfl1.png" alt="CloudFormation Designer Template" width="800" height="753"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The project's use of AWS CloudFormation, visualized in the CloudFormation Designer template, represents the infrastructure as code (IaC) aspect of our deployment. This template is a visual representation of the serverless architecture, encompassing various AWS services and configurations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;S3 Bucket Configuration&lt;/strong&gt;: It includes settings for an S3 bucket, essential for storing deployment packages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lambda Functions and IAM Roles&lt;/strong&gt;: The template details Lambda functions and their associated IAM roles, outlining the permissions and policies necessary for secure and efficient function execution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Gateway&lt;/strong&gt;: It illustrates the setup of the API Gateway, which acts as the entry point for the application's backend, handling requests and routing them to the appropriate Lambda functions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logging and Monitoring&lt;/strong&gt;: The inclusion of log groups and CloudWatch roles highlights the focus on monitoring and logging, crucial for maintaining application health and performance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The CloudFormation Designer template is a testament to the robustness and scalability of the AWS infrastructure utilized in the project. It showcases the intricate setup of serverless components, emphasizing the project's commitment to leveraging AWS services for optimal performance and security.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. GraphQL: Enhancing API Interactions
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;GraphQL: Enhancing API Interactions&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fv2%2Fresize%3Afit%3A4800%2Fformat%3Awebp%2F0%2A1zL-rFFqK9qtOkll" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fv2%2Fresize%3Afit%3A4800%2Fformat%3Awebp%2F0%2A1zL-rFFqK9qtOkll" alt="GraphQL" width="1000" height="350"&gt;&lt;/a&gt;&lt;br&gt;
The heart of this application lies in its use of GraphQL. The custom &lt;code&gt;rickAndMortyAssociations&lt;/code&gt; function within the GraphQL schema highlights the ability to create new relationships in existing APIs. This implementation demonstrates GraphQL's power in crafting flexible and efficient data queries, offering significant enhancements over traditional REST APIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Case Study - The GraphQL Implementation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3anqzrkr6xlexltkzt79.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3anqzrkr6xlexltkzt79.png" alt="GraphQL queries" width="800" height="216"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Crafting the GraphQL Queries
&lt;/h3&gt;

&lt;p&gt;In this project, the GraphQL queries were not just a tool for data retrieval; they were the linchpin for transforming and enriching data from diverse sources. The schema and resolvers were intricately designed to not only fetch data from the Rick and Morty API but to also incorporate data from the Pocket Morties game, demonstrating GraphQL's ability to federate disparate data sources.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Refresher On How GraphQL Works
&lt;/h3&gt;

&lt;p&gt;At its core, GraphQL is more than just a query language; it's a powerful tool for API design and data federation. Unlike REST APIs, which require multiple requests to fetch different types of data, GraphQL allows for fetching all necessary data in a single request. This capability is particularly beneficial in situations like this project, where data from fundamentally different sources needs to be federated and presented in a unified format. This approach significantly improves performance, especially on slow mobile network connections, by reducing the number of required network requests.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;rickAndMortyAssociations&lt;/code&gt; Functionality
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frb4ckpydtpmfyp73ph99.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frb4ckpydtpmfyp73ph99.png" alt="Associated Ricks and Morties" width="800" height="311"&gt;&lt;/a&gt;&lt;br&gt;
The &lt;code&gt;rickAndMortyAssociations&lt;/code&gt; function in the GraphQL schema was a custom implementation addressing the absence of direct associations between Ricks and Morties in the original API. This function showcases GraphQL's flexibility in data manipulation and presentation:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Schema Definition&lt;/strong&gt;: The schema defines the &lt;code&gt;rickAndMortyAssociations&lt;/code&gt; type, specifying the structure and types of the data that can be queried.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resolvers&lt;/strong&gt;: The resolver logic processes these queries, combining data from the Rick and Morty API with the Pocket Morties game. This involves fetching relevant data and then applying custom logic to create meaningful associations between Ricks and their corresponding Morties.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query Execution&lt;/strong&gt;: When a query for &lt;code&gt;rickAndMortyAssociations&lt;/code&gt; is made, the GraphQL server executes the resolver, returning a combined set of data that enhances the original API's capabilities with additional context and relationships.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The implementation of &lt;code&gt;rickAndMortyAssociations&lt;/code&gt; function is a prime example of GraphQL's power in federating and enriching data from multiple sources, creating a more comprehensive and nuanced data set that goes beyond the limitations of traditional APIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Navigating IaC Challenges: Terraform to Lambda Shift
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5sn3h5zpy69e7jug62n8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5sn3h5zpy69e7jug62n8.png" alt="Journey from Fargate via Terraform to Lambda via Serverless" width="800" height="111"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Challenges with Terraform in AWS Fargate and ElastiCache Setup
&lt;/h3&gt;

&lt;p&gt;The initial approach to infrastructure involved using Terraform for configuring AWS Fargate and ElastiCache. While I've been using Terraform since its initial alpha days, I still encounter specific challenges as AWS and HashiCorp add new features. In this case:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Health Checks in ECS and ELB&lt;/strong&gt;: Configuring health checks within Elastic Container Service (ECS) and Elastic Load Balancer (ELB) proved complex, crucial for ensuring service reliability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service Discovery Issues&lt;/strong&gt;: Ensuring effective service discovery of ElastiCache within the same Virtual Private Cloud (VPC) as Fargate was intricate and required precise configuration.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Pivot to AWS Lambda
&lt;/h4&gt;

&lt;p&gt;Given these challenges, a strategic pivot was made to AWS Lambda for its simplicity and speed, because at this time, having something to show interviewers and perspective employers is more important than the technology I leverage.&lt;/p&gt;

&lt;p&gt;This shift was influenced by:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Simplicity and Efficiency&lt;/strong&gt;: Lambda's streamlined approach was better suited for our project's time constraints and requirements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Statelessness and Resource Optimization&lt;/strong&gt;: The stateless nature of Lambda aligned with our needs, offering cost-effectiveness and efficient resource utilization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Project Progression Focus&lt;/strong&gt;: The pivot to Lambda was a pragmatic decision to keep the project moving forward, balancing the complexities of Terraform with the functionalities required.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Future Plans with Terraform
&lt;/h3&gt;

&lt;p&gt;The journey with Terraform will be revisited in future updates, providing an opportunity to explore and document overcoming its initial challenges. This effort underscores a commitment to mastering complex IaC solutions and sharing these experiences.&lt;/p&gt;

&lt;h2&gt;
  
  
  Server vs. Server-Lambda: Dockerfile, Redis, and Lambda Enhancements
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb571cdhonkbenqlxtu2f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb571cdhonkbenqlxtu2f.png" alt="Server-Lambda" width="800" height="304"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Distinct Server Configurations: Local and Lambda
&lt;/h3&gt;

&lt;p&gt;In this project, I utilized two distinct server files to cater to different environments: &lt;code&gt;server.ts&lt;/code&gt; for local development and &lt;code&gt;server-lambda.ts&lt;/code&gt; for AWS Lambda deployment.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;server.ts&lt;/code&gt; for Local Development&lt;/strong&gt;: This file configures a traditional server setup, optimized for local development and testing. It provides a streamlined and efficient process, free from the complexities of a serverless environment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;server-lambda.ts&lt;/code&gt; for AWS Lambda&lt;/strong&gt;: Tailored for deployment in a serverless architecture, this file includes specific adjustments and integrations, like Redis for efficient data caching, ensuring optimal performance and scalability in AWS Lambda.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dockerfile Solution&lt;/strong&gt;: A Dockerfile was used to containerize the application, ensuring consistent environments and simplifying deployment. This approach aids in managing dependencies and environmental configurations across development and production stages.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The dual server file strategy reflects the project's adaptability, ensuring each environment's unique demands are met efficiently. This approach demonstrates the importance of tailoring the architecture to suit different deployment scenarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion and Reflections
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Embracing Challenges and Learning
&lt;/h3&gt;

&lt;p&gt;This journey through building a modern full-stack monorepo application has been as enlightening as it has been challenging. It reaffirmed my passion for digital architecture and the pursuit of innovative solutions in the web development realm.&lt;/p&gt;

&lt;h4&gt;
  
  
  Key takeaways from this project include:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Adaptability in Technology Choices&lt;/strong&gt;: The need to pivot from Bun to Yarn and from Terraform to AWS Lambda highlighted the importance of flexibility in technology choices. It showed that while cutting-edge tools can offer significant advantages, sometimes established technologies provide the necessary stability and reliability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enhancing API Capabilities with GraphQL&lt;/strong&gt;: The use of GraphQL to enrich the Rick and Morty API showcased the power of this query language in creating efficient, flexible data interactions, going beyond the limitations of traditional REST APIs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Balancing Innovation with Practicality&lt;/strong&gt;: The project underlined the balance between embracing new technologies and ensuring practical, stable solutions, especially in a professional setting where reliability and maintainability are paramount.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Infrastructure as Code (IaC) Learning Curve&lt;/strong&gt;: The challenges faced with Terraform, and the subsequent switch to AWS Lambda, provided valuable insights into cloud infrastructure management, emphasizing the need for continuous learning and adaptability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Server Configuration for Different Environments&lt;/strong&gt;: The use of separate server configurations for local development and AWS Lambda deployment highlighted the importance of environment-specific optimizations in software development.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Looking Ahead
&lt;/h2&gt;

&lt;p&gt;As I continue to explore and master various technologies, I plan to revisit some of the initial challenges, like those encountered with Terraform, and document these experiences. This ongoing journey not only contributes to my professional growth but also serves as a resource for others navigating similar paths.&lt;/p&gt;

&lt;p&gt;In summary, this project was a testament to the dynamic nature of web development and cloud infrastructure, where continuous learning, adaptability, and a pragmatic approach are key to success.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>graphql</category>
      <category>nextjs</category>
      <category>aws</category>
    </item>
    <item>
      <title>Building a Fargate API Server with Go, Gin, Docker, and AWS Copilot</title>
      <dc:creator>Drew Schillinger</dc:creator>
      <pubDate>Wed, 25 Oct 2023 16:16:42 +0000</pubDate>
      <link>https://forem.com/doctorew/building-a-fargate-api-server-with-go-gin-docker-and-aws-copilot-3iim</link>
      <guid>https://forem.com/doctorew/building-a-fargate-api-server-with-go-gin-docker-and-aws-copilot-3iim</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiaacyy8y5i76h8md9wxd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiaacyy8y5i76h8md9wxd.png" alt="GPT-Powered Translator with LangChain Hosted on Fargate" width="800" height="1164"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hello fellow tech enthusiasts!&lt;/p&gt;

&lt;p&gt;As a self-taught engineer with over two decades of experience, starting back in the days the browser wars, my journey has been driven by curiosity, innovation, and a passion for understanding the why and how technology does its "magic". &lt;/p&gt;

&lt;p&gt;I chose to use Golang over Python not just because it's fun, but because it presented an opportunity to demystify its "magic" and deepen my understanding (even though I've been using it since it was in beta). This became especially relevant during a conversation with a respected leader who posed a seemingly simple question about Go's struct vs. interface. As a self-taught engineer who's gone toe-to-toe with imposter syndrome, vocabulary questions like this give me sweaty palms. But I realized that this was a great opportunity to break down these concepts and really understand them at a deeper level. &lt;/p&gt;

&lt;p&gt;(PS A struct is a composite data type that groups together variables under a single name, while an interface is a collection of method signatures that a type must implement. Understanding the difference between these two concepts is crucial for writing clean and efficient Go code.) &lt;/p&gt;

&lt;p&gt;Langchain was another exciting venture, and I am thrilled that Harrison Chase figured this one out because chaining GPT-2 and GPT-3 calls in Python in 2021 was a pain the keister! &lt;/p&gt;

&lt;p&gt;And then there's AWS Fargate, a game-changer in serverless container platforms. Having used Fargate at NBA Digital and NBATV to serve content to 50 million concurrent users at scale nightly, its efficiency and scalability are undeniable. &lt;/p&gt;

&lt;p&gt;Through all these experiences, my hope is to inspire fellow self-taught engineers, innovators, and anyone with a thirst for knowledge. Let's explore, learn, and innovate together! &lt;/p&gt;

&lt;p&gt;In this blog post, we'll walk through the process of building an API server using Go and the Gin framework, containerizing it with Docker, and deploying it to AWS Fargate using AWS Copilot. We'll also delve into the importance of environment management and testing. Let's get started.&lt;/p&gt;

&lt;p&gt;Please refer to the code in this git repo: &lt;a href="https://github.com/doctor-ew/go_skippy_lc" rel="noopener noreferrer"&gt;https://github.com/doctor-ew/go_skippy_lc&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Docker: Containerizing the Go Application
&lt;/h2&gt;

&lt;p&gt;Docker allows us to package our application and its dependencies into a container, ensuring consistent behavior across different environments. Let's break down the Dockerfile from the &lt;a href="https://github.com/doctor-ew/go_skippy_lc" rel="noopener noreferrer"&gt;go_skippy_lc repository&lt;/a&gt;:&lt;/p&gt;

&lt;h4&gt;
  
  
  1.1. DockerfileCopy code
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;FROM golang:1.17-alpine&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explanation:&lt;/strong&gt; This line specifies the base image for our Docker container. In this case, you're using the official Go image (&lt;code&gt;golang&lt;/code&gt;) with version &lt;code&gt;1.17&lt;/code&gt; based on the lightweight Alpine Linux distribution (&lt;code&gt;alpine&lt;/code&gt;). This image will have the Go runtime and tools pre-installed.&lt;/p&gt;




&lt;h4&gt;
  
  
  1.2. DockerfileCopy code
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;WORKDIR /app&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explanation:&lt;/strong&gt; This line sets the working directory inside the container to &lt;code&gt;/app&lt;/code&gt;. All subsequent commands in the Dockerfile (like &lt;code&gt;COPY&lt;/code&gt; or &lt;code&gt;RUN&lt;/code&gt;) will be executed in this directory. Essentially, this directory will be the root for our application inside the container.&lt;/p&gt;




&lt;h4&gt;
  
  
  1.3. DockerfileCopy code
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;COPY go.mod . COPY go.sum .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explanation:&lt;/strong&gt; These lines copy the &lt;code&gt;go.mod&lt;/code&gt; and &lt;code&gt;go.sum&lt;/code&gt; files from our local machine (outside the container) to the current directory inside the container (&lt;code&gt;/app&lt;/code&gt;). These files are essential for Go's module system, ensuring that the correct dependencies are used when building our application.&lt;/p&gt;




&lt;h4&gt;
  
  
  1.4. DockerfileCopy code
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;RUN go mod download&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explanation:&lt;/strong&gt; This line runs the &lt;code&gt;go mod download&lt;/code&gt; command inside the container. This command fetches all the dependencies listed in &lt;code&gt;go.mod&lt;/code&gt; and &lt;code&gt;go.sum&lt;/code&gt;, ensuring they're available in the container for the build process.&lt;/p&gt;




&lt;h4&gt;
  
  
  1.5. DockerfileCopy code
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;COPY . .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explanation:&lt;/strong&gt; This line copies everything from our current directory on our local machine (i.e., the root of our Go project) to the current directory inside the container (&lt;code&gt;/app&lt;/code&gt;). This ensures that all our application's source code and other necessary files are available inside the container.&lt;/p&gt;




&lt;h4&gt;
  
  
  1.6. DockerfileCopy code
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;RUN go build -o ./out/myapi .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explanation:&lt;/strong&gt; This line runs the &lt;code&gt;go build&lt;/code&gt; command inside the container to compile our Go application. The &lt;code&gt;-o ./out/myapi&lt;/code&gt; flag specifies the output directory and name for the compiled binary. In this case, the binary will be named &lt;code&gt;myapi&lt;/code&gt; and will be located in the &lt;code&gt;/app/out/&lt;/code&gt; directory inside the container.&lt;/p&gt;




&lt;h4&gt;
  
  
  1.7. DockerfileCopy code
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;CMD ["./out/myapi"]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explanation:&lt;/strong&gt; This line specifies the command that will be executed when the container starts. In this case, it's running the compiled Go application (&lt;code&gt;./out/myapi&lt;/code&gt;). The &lt;code&gt;CMD&lt;/code&gt; instruction allows the container to behave like an executable, meaning when you run the container, it will automatically start our Go application.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Setting Up the Gin Server, Environment Management, and .gitignore
&lt;/h2&gt;

&lt;p&gt;Before diving into the code, it's essential to understand the importance of environment management and the role of &lt;code&gt;.gitignore&lt;/code&gt; in safeguarding sensitive information.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.1. Environment Files and &lt;code&gt;.gitignore&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Before we delve into the code, it's essential to mention the importance of environment files and &lt;code&gt;.gitignore&lt;/code&gt;. Storing sensitive information, like API keys, in environment variables is a best practice. This ensures that these keys are not hard-coded into the application, reducing the risk of accidental exposure. The &lt;code&gt;.gitignore&lt;/code&gt; file ensures that certain files, like the &lt;code&gt;.env&lt;/code&gt; containing these keys, are not committed to version control, further safeguarding them.&lt;/p&gt;




&lt;h3&gt;
  
  
  2.2. Imports
&lt;/h3&gt;

&lt;p&gt;Here's a brief overview of each import:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Standard Library Imports&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;context&lt;/code&gt;: Provides a way to carry deadlines, cancellations, and other request-scoped values across API boundaries.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fmt&lt;/code&gt;: Implements formatted I/O functions.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;log&lt;/code&gt;: Provides logging capabilities.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;net/http&lt;/code&gt;: Provides HTTP client and server implementations.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;os&lt;/code&gt;: Provides a platform-independent interface to operating system functionality.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;os/signal&lt;/code&gt;: Provides a way to intercept and act upon signals sent to the application.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;syscall&lt;/code&gt;: Contains an interface to the low-level operating system primitives.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;time&lt;/code&gt;: Provides functionality for measuring and displaying time.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Third-party Imports&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;github.com/gin-gonic/gin&lt;/code&gt;: Gin is a web framework for building APIs in Go. It's known for its performance and small memory footprint.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;github.com/joho/godotenv&lt;/code&gt;: A package to load environment variables from a &lt;code&gt;.env&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;github.com/tmc/langchaingo/llms&lt;/code&gt;: A library related to the language chain (from the context, it seems to be related to interfacing with OpenAI).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;github.com/tmc/langchaingo/llms/openai&lt;/code&gt;: Specific OpenAI related functionalities for the language chain.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;github.com/tmc/langchaingo/schema&lt;/code&gt;: Defines the schema or structure for the messages and responses with OpenAI.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  2.3. Code Structure
&lt;/h3&gt;

&lt;h4&gt;
  
  
  a. Interface vs. Struct
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Interface&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;goCopy code&lt;/p&gt;

&lt;p&gt;&lt;code&gt;type Chat interface {     Call(ctx context.Context, messages []schema.ChatMessage, options ...llms.CallOption) (*schema.AIChatMessage, error) }&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explanation&lt;/strong&gt;: An interface &lt;code&gt;Chat&lt;/code&gt; is defined, which any type must satisfy if it has a &lt;code&gt;Call&lt;/code&gt; method with the specified signature. This allows for flexibility and can be used to mock the OpenAI chat for testing or to use different implementations.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Struct&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;goCopy code&lt;/p&gt;

&lt;p&gt;&lt;code&gt;type RequestBody struct {     Message string `json:"message"` }&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explanation&lt;/strong&gt;: This struct &lt;code&gt;RequestBody&lt;/code&gt; defines the structure of the request body that the &lt;code&gt;/ask-skippy&lt;/code&gt; endpoint expects. The &lt;code&gt;json:"message"&lt;/code&gt; tag indicates that when this struct is unmarshaled from a JSON object, the &lt;code&gt;Message&lt;/code&gt; field corresponds to the &lt;code&gt;message&lt;/code&gt; key in the JSON.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  2.4. Functions
&lt;/h3&gt;

&lt;h4&gt;
  
  
  a. &lt;code&gt;srv&lt;/code&gt; Function
&lt;/h4&gt;

&lt;p&gt;This function sets up and starts the Gin server. It defines two endpoints: &lt;code&gt;/ask-skippy&lt;/code&gt; for POST requests and &lt;code&gt;/&lt;/code&gt; for GET requests. It also sets up graceful shutdown for the server when it receives an interrupt or termination signal.&lt;/p&gt;

&lt;h4&gt;
  
  
  b. &lt;code&gt;askSkippy&lt;/code&gt; Function
&lt;/h4&gt;

&lt;p&gt;This function interfaces with the OpenAI chat (or any other implementation that satisfies the &lt;code&gt;Chat&lt;/code&gt; interface). It sends a system message to set the context for the AI and then sends the user's message. It then waits for a response from the AI and returns it.&lt;/p&gt;

&lt;h4&gt;
  
  
  c. &lt;code&gt;main&lt;/code&gt; Function
&lt;/h4&gt;

&lt;p&gt;This is the entry point of the application. It loads the environment variables from the &lt;code&gt;.env&lt;/code&gt; file, retrieves the OpenAI API key, initializes the OpenAI chat, and then starts the server.&lt;/p&gt;




&lt;p&gt;This breakdown provides a high-level overview of the code's structure and functionality. Each section and function plays a crucial role in setting up the server, interfacing with OpenAI, and serving responses to the user.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Testing: Ensuring Our Application Works as Expected
&lt;/h2&gt;

&lt;p&gt;Testing is a crucial aspect of software development. It ensures that our application behaves as expected and helps catch issues early in the development process. Let's dive into the testing code for the &lt;code&gt;askSkippy&lt;/code&gt; function:&lt;/p&gt;

&lt;h3&gt;
  
  
  3.1. Imports
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Standard Library Imports&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;context&lt;/code&gt;: As before, this provides a way to carry request-scoped values.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;errors&lt;/code&gt;: Provides functions to manipulate errors.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;testing&lt;/code&gt;: The standard Go testing package.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Third-party Imports&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;github.com/stretchr/testify/mock&lt;/code&gt;: The &lt;code&gt;testify&lt;/code&gt; library's mocking package. It provides utilities to easily mock interfaces for testing.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;github.com/tmc/langchaingo/schema&lt;/code&gt;: Defines the schema or structure for the messages and responses with OpenAI.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  3.2. MockChat Struct
&lt;/h3&gt;

&lt;p&gt;goCopy code&lt;/p&gt;

&lt;p&gt;&lt;code&gt;type MockChat struct {    mock.Mock }&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explanation&lt;/strong&gt;: The &lt;code&gt;MockChat&lt;/code&gt; struct embeds the &lt;code&gt;mock.Mock&lt;/code&gt; type from the testify library. This allows &lt;code&gt;MockChat&lt;/code&gt; to have all the methods and functionalities provided by &lt;code&gt;mock.Mock&lt;/code&gt;, enabling easy setup of expected method calls and their return values.&lt;/p&gt;




&lt;h3&gt;
  
  
  3.3. Test Functions
&lt;/h3&gt;

&lt;h4&gt;
  
  
  a. &lt;code&gt;TestAskSkippy&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;This test function checks the "happy path" scenario where everything works as expected.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Mock Setup&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;goCopy code&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mockChat.On("Call", mock.Anything, mock.Anything, mock.Anything).Return(&amp;amp;schema.AIChatMessage{Content: "Mocked response"}, nil)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here, we're setting up the expectation that the &lt;code&gt;Call&lt;/code&gt; method of &lt;code&gt;mockChat&lt;/code&gt; will be invoked with any arguments (&lt;code&gt;mock.Anything&lt;/code&gt; is a placeholder that matches any value). When invoked, it should return a mocked AI chat message with the content "Mocked response" and no error.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Function Call&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;goCopy code&lt;/p&gt;

&lt;p&gt;&lt;code&gt;response, err := askSkippy(context.Background(), mockChat, "English", "Test message for Skippy")&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We then call the &lt;code&gt;askSkippy&lt;/code&gt; function with our mock chat and check the response.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Assertions&lt;/strong&gt;: The test checks two things:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. That there's no error.

&lt;ol&gt;
&lt;li&gt;That the response matches the expected "Mocked response".
&lt;/li&gt;
&lt;/ol&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;


b. &lt;code&gt;TestAskSkippy_Error&lt;/code&gt;
&lt;/h4&gt;


&lt;p&gt;This test function checks the scenario where the &lt;code&gt;Call&lt;/code&gt; method returns an error.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Mock Setup&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;goCopy code&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mockChat.On("Call", mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.New("Mocked error"))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here, we're setting up the expectation that the &lt;code&gt;Call&lt;/code&gt; method of &lt;code&gt;mockChat&lt;/code&gt; will be invoked and will return an error "Mocked error".&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Function Call&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;goCopy code&lt;/p&gt;

&lt;p&gt;&lt;code&gt;_, err := askSkippy(context.Background(), mockChat, "English", "Test error message for Skippy")&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We then call the &lt;code&gt;askSkippy&lt;/code&gt; function with our mock chat and check for an error.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Assertion&lt;/strong&gt;: The test checks that an error is returned.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Potential Issues and Solutions:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;MockChat Implementation&lt;/strong&gt;: The &lt;code&gt;MockChat&lt;/code&gt; struct is defined, but its methods aren't. For the tests to work, the &lt;code&gt;MockChat&lt;/code&gt; needs to have a &lt;code&gt;Call&lt;/code&gt; method that uses the testify mock's functionalities. This method should look something like:&lt;/p&gt;

&lt;p&gt;goCopy code&lt;/p&gt;

&lt;p&gt;&lt;code&gt;func (m *MockChat) Call(ctx context.Context, messages []schema.ChatMessage, options ...llms.CallOption) (*schema.AIChatMessage, error) {     args := m.Called(ctx, messages, options)     return args.Get(0).(*schema.AIChatMessage), args.Error(1) }&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Dependencies&lt;/strong&gt;: Ensure that the testify library is installed. If not, it can be added using:&lt;/p&gt;

&lt;p&gt;bashCopy code&lt;/p&gt;

&lt;p&gt;&lt;code&gt;go get github.com/stretchr/testify&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Integration with Main Code&lt;/strong&gt;: Ensure that the &lt;code&gt;Chat&lt;/code&gt; interface in the main code and the &lt;code&gt;MockChat&lt;/code&gt; in the test code are in sync. If the interface changes, the mock and tests need to be updated accordingly.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;This breakdown provides an overview of the testing code's structure and functionality. The tests are designed to validate the behavior of the &lt;code&gt;askSkippy&lt;/code&gt; function in both normal and error scenarios.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. AWS Fargate and Copilot: Deploying and Managing the Service
&lt;/h2&gt;

&lt;p&gt;AWS Fargate and Copilot provide a seamless experience for deploying and managing containerized applications on AWS without the need to manage the underlying infrastructure. With AWS Copilot, you can define, release, and manage services using simple CLI commands. Let's dive into the Copilot configuration files from the &lt;a href="https://github.com/doctor-ew/go_skippy_lc/tree/aws-copilot/copilot" rel="noopener noreferrer"&gt;go_skippy_lc/copilot directory&lt;/a&gt; to understand how the service and environment are set up:&lt;/p&gt;

&lt;h2&gt;
  
  
  4.1. Service Configuration: &lt;code&gt;copilot/go-skippy-lc/manifest.yml&lt;/code&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Overview:
&lt;/h3&gt;

&lt;p&gt;This file defines the configuration for the &lt;code&gt;go-skippy-lc&lt;/code&gt; service. It's a Load Balanced Web Service, which means it's a public-facing web service that's behind a load balancer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Breakdown:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;name &amp;amp; type&lt;/strong&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;name: go-skippy-lc&lt;/code&gt; specifies the name of the service.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;type: Load Balanced Web Service&lt;/code&gt; indicates the type of service.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;http&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;path: '/'&lt;/code&gt; specifies the path that the load balancer should forward requests to.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;alias&lt;/code&gt;: This is a list of domain names that should route to this service. This is useful for custom domain routing.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;healthcheck&lt;/code&gt;: (commented out) would specify a custom health check path for the service.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;image&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;build: Dockerfile&lt;/code&gt; specifies the Dockerfile to use for building the container image.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;port: 80&lt;/code&gt; is the port the container listens on.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;cpu, memory, count&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;These fields specify the resources for the ECS task. It uses 256 CPU units, 512 MiB of memory, and there should always be 1 task running.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;exec&lt;/strong&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;exec: true&lt;/code&gt; allows you to run commands in our container.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;network&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;connect: true&lt;/code&gt; enables Service Connect for intra-environment traffic between services.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;storage&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;readonly_fs&lt;/code&gt;: (commented out) would limit the mounted root filesystems to read-only access.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;variables &amp;amp; secrets&lt;/strong&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(Both commented out) would allow us to pass environment variables and secrets to our service.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;environments&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(Commented out) would allow us to override any of the above values for specific environments.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  4.2. Environment Configuration: &lt;code&gt;copilot/environments/test/manifest.yml&lt;/code&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Overview:
&lt;/h3&gt;

&lt;p&gt;This file defines the configuration for the &lt;code&gt;test&lt;/code&gt; environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Breakdown:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;name &amp;amp; type&lt;/strong&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;name: test&lt;/code&gt; specifies the name of the environment.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;type: Environment&lt;/code&gt; indicates the type of configuration.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;network&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(Commented out) would allow us to specify a custom VPC or configure how the VPC should be created.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;http&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;public&lt;/code&gt;: Specifies the configuration for the public load balancer in the environment.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;certificates&lt;/code&gt;: Lists the ARN of the SSL certificate to use with the load balancer.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;observability&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;container_insights: false&lt;/code&gt; specifies that container insights (for monitoring) should not be enabled for this environment.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Manual Step:
&lt;/h3&gt;

&lt;p&gt;I had to manually point the A Record to the ALB. This step is necessary because while AWS Copilot can automate the creation of resources like the ALB, the final step of updating DNS records to point to the ALB often requires manual intervention, especially if you're using a third-party DNS provider or have specific routing requirements.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As an architect or engineer, we need to think through the atoms that compose the thing we're building. In this case, a robust and scalable API server encompasses everything from server setup and environment management to containerization and rigorous testing. I've shared this guide to provide a solid foundation for deploying a Go-based API server to AWS Fargate. &lt;/p&gt;

&lt;p&gt;My hope is that this not only serves as a practical guide but also inspires fellow self-taught engineers, innovators, and all curious minds. Let's continue to explore, learn, and push the boundaries of innovation together. &lt;/p&gt;

&lt;p&gt;Excelsior!&lt;/p&gt;

</description>
      <category>go</category>
      <category>aws</category>
      <category>tutorial</category>
      <category>docker</category>
    </item>
    <item>
      <title>Is it safe to cross the streams (er, cloud providers)?</title>
      <dc:creator>Drew Schillinger</dc:creator>
      <pubDate>Tue, 14 Dec 2021 19:05:52 +0000</pubDate>
      <link>https://forem.com/doctorew/is-it-safe-to-cross-the-streams-er-cloud-providers-4dbo</link>
      <guid>https://forem.com/doctorew/is-it-safe-to-cross-the-streams-er-cloud-providers-4dbo</guid>
      <description>&lt;p&gt;Hello, fellow technophiles!&lt;/p&gt;

&lt;p&gt;I'm tasked with rearchitecting an existing app for a start-up. There are 3 top priorities: &lt;u&gt;&lt;strong&gt;&lt;em&gt;speed&lt;/em&gt;&lt;/strong&gt;&lt;/u&gt; to rebuild a crippled tech stack and created needed functionality, &lt;em&gt;&lt;strong&gt;&lt;u&gt;stability&lt;/u&gt;&lt;/strong&gt;&lt;/em&gt; to said crippled stack as we are currently wooing investors and clients, and &lt;strong&gt;&lt;u&gt;&lt;em&gt;security:&lt;/em&gt;&lt;/u&gt;&lt;/strong&gt; build the new stack right (and right now).&lt;/p&gt;

&lt;p&gt;The former team mismanaged a DotNet stack on Azure (like, think diaper fire mishmash of misused VMs and outdated sdks/packages), and I have a ton of confidence and experience in AWS space. &lt;/p&gt;

&lt;p&gt;If I were to say "let's take a 6-week hiautus), I and the other dev could rebuild what they have now with a pgsql, documentdb, and some lambdas in node or python or go. But the reality is we will be using the current dotnet stack until we've moved over to a new one (and likely using both as new features will be built in new Thing-X).&lt;/p&gt;

&lt;p&gt;All that said, what is y'alls experience in coming in new and rebuilding better? &lt;/p&gt;

&lt;p&gt;My concern in holding steady on Azure and building new on AWS mirror's Egon's warning about crossing the streams: "Try to image all life as you know it stopping instantaneously and every molecule in your body exploding at the speed of light."&lt;/p&gt;

&lt;p&gt;Thank you for any advice, or for at least listening as I get my thoughts out on e-paper.&lt;/p&gt;

&lt;p&gt;Excelsior!&lt;/p&gt;

&lt;p&gt;DoctorEw&lt;/p&gt;

</description>
      <category>azure</category>
      <category>aws</category>
      <category>refactorit</category>
      <category>discuss</category>
    </item>
  </channel>
</rss>
