<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Anthony Master</title>
    <description>The latest articles on DEV Community by Anthony Master (@amaster507_59).</description>
    <link>https://dev.to/amaster507_59</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%2F832703%2Fe16febe8-363d-4d0a-acdc-66a71a8882b8.jpeg</url>
      <title>DEV Community: Anthony Master</title>
      <link>https://dev.to/amaster507_59</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/amaster507_59"/>
    <language>en</language>
    <item>
      <title>Event-Based Systems vs. State-Based Systems</title>
      <dc:creator>Anthony Master</dc:creator>
      <pubDate>Thu, 02 Apr 2026 21:03:05 +0000</pubDate>
      <link>https://dev.to/amaster507_59/event-based-systems-vs-state-based-systems-210a</link>
      <guid>https://dev.to/amaster507_59/event-based-systems-vs-state-based-systems-210a</guid>
      <description>&lt;h2&gt;
  
  
  &lt;em&gt;Why this distinction matters far beyond healthcare&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;One of the most helpful ways to understand modern software architecture is to distinguish between &lt;strong&gt;state-based systems&lt;/strong&gt; and &lt;strong&gt;event-based systems&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is a concept I have had to explain many times in healthcare interoperability, especially to people trying to understand why certain systems behave so differently from others. It also helps explain why technologies built around live updates and server-driven changes make so much sense once you see the architectural difference underneath them.&lt;/p&gt;

&lt;p&gt;To make it simple, imagine two fictional healthcare platforms: &lt;strong&gt;ChartStone Clinical&lt;/strong&gt; and &lt;strong&gt;PulseTrail Health&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  ChartStone Clinical: a state-based system
&lt;/h2&gt;

&lt;p&gt;ChartStone Clinical is a records-focused application. A user opens a patient chart, the server sends the current data to the client, and from that point forward the user interacts with a local representation of that state until they submit their changes back to the server.&lt;/p&gt;

&lt;p&gt;This is how a large portion of modern applications work, whether they are SPAs, traditional server-rendered apps, thick clients, or older LAMP systems. The client receives a snapshot, works against that snapshot, and eventually sends back an updated version of state for the server to merge into the source of truth.&lt;/p&gt;

&lt;p&gt;That approach is practical and familiar, but it comes with a number of challenges.&lt;/p&gt;

&lt;p&gt;What happens if another user changes the same record before the first user submits their update? What happens if authorization expires mid-edit? What happens if the client loses power, restarts unexpectedly, or drops connection before its local changes are persisted? Suddenly the system has to deal with file locks, merge conflicts, local drafts, recovery mechanisms, and complicated rules about reconciling client-side changes with the authoritative data on the server.&lt;/p&gt;

&lt;p&gt;If the system is mostly read-only, some of this complexity fades into the background. But most business software is not read-only. Most systems support active collaboration against mutable shared data. That means the moment the client owns a working copy of state, the burden of consistency becomes much heavier.&lt;/p&gt;

&lt;h2&gt;
  
  
  PulseTrail Health: an event-based system
&lt;/h2&gt;

&lt;p&gt;Now imagine PulseTrail Health, a monitoring platform used in a critical care environment.&lt;/p&gt;

&lt;p&gt;In this world, devices connected to patients continuously emit events: heart rate updates, oxygen changes, alarm thresholds, patient assignment changes, and other vital signals. Those events flow to a central hub, which aggregates and distributes them to the places that need them, such as bedside displays, nurse stations, and mobile monitors.&lt;/p&gt;

&lt;p&gt;The key difference is that the system is not waiting for someone to ask for the latest snapshot. It is reacting to what is happening as it happens.&lt;/p&gt;

&lt;p&gt;If a patient’s heart rate drops suddenly, the system cannot afford to let that information sit idle until the next poll cycle or page refresh. The event itself is what matters. The architecture is built to push meaningful changes outward immediately.&lt;/p&gt;

&lt;p&gt;This is why event-based systems are often a better fit for highly reactive environments. They reduce the delay between change and response. They also reduce waste. Instead of constant polling across the network just to ask whether anything has changed, a push-based system can remain relatively quiet until something meaningful actually occurs.&lt;/p&gt;

&lt;p&gt;That is a major architectural advantage, especially when timing, visibility, and coordination matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  The difference in plain terms
&lt;/h2&gt;

&lt;p&gt;A state-based system is centered on the question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What does the record look like right now?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;An event-based system is centered on the question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What just happened, and who needs to know?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The state gives you the latest snapshot whereas events give you the flow of change. Both of these matter, most applications still need some current state view. Users need dashboards, forms, lists, reports, and screens that show the latest known truth. But when an application is built only around snapshots, it can become blind to the significance of the transitions that produced them. The events capture those transitions directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters beyond healthcare
&lt;/h2&gt;

&lt;p&gt;Healthcare makes the distinction easy to see because the stakes are high. But the principle applies almost everywhere. Most applications are not merely storing data; they are coordinating change over time.&lt;/p&gt;

&lt;p&gt;Orders are placed. Payments clear. Inventory moves. Messages are sent. Users sign in. Documents are edited. Approvals happen. Sensors report. Notifications fire. Background jobs complete. External systems need to be informed. Audit trails need to be preserved. Failures need to be recoverable.&lt;/p&gt;

&lt;p&gt;A state-based model can tell you where the system ended up while an event-based model can tell you how it got there, what happened along the way, and what other parts of the system should do in response.&lt;/p&gt;

&lt;p&gt;That is why event-based architecture is useful far beyond medical monitoring. It fits CRMs, ERPs, commerce systems, logistics platforms, financial applications, content systems, communications tools, and operational dashboards. Nearly every serious application deals with meaningful change, and meaningful change is where events shine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why almost every application can benefit
&lt;/h2&gt;

&lt;p&gt;This does not mean every application should be purely event-sourced or that state no longer matters. It means that &lt;strong&gt;thinking in events&lt;/strong&gt; often leads to better systems. Event-based architecture can improve real-time responsiveness, integration with other systems, auditability, decoupled workflows, automation, resilience, and visibility into what actually happened. In other words, event-based thinking helps software behave more like the real world it is modeling. Real businesses do not operate as a sequence of static snapshots, they actually operate as a stream of things happening.&lt;/p&gt;

&lt;p&gt;The more an application needs to react, coordinate, notify, synchronize, or explain itself, the more value there is in treating events as first-class citizens.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;State still matters, but events often tell the full story. In practice, that also shapes how I think about the web stack itself. If the goal is to model systems as a flow of meaningful change rather than a sequence of disconnected snapshots, then the transport and UI model should reflect that.&lt;/p&gt;

&lt;p&gt;That is one reason I tend to favor &lt;strong&gt;DataStar over HTMX&lt;/strong&gt; for this kind of architecture. HTMX is excellent at request-driven hypermedia and remains one of the most approachable ways to build server-rendered applications with minimal client complexity. But when an application starts leaning into truly live, server-driven behavior, DataStar’s model feels more aligned with the problem itself. Its philosophy centers the backend as the source of truth and treats the UI as something continuously updated through a unified SSE stream, with only small, intentional client-side signals and event pushes where needed. That creates a cleaner mental model than treating realtime communication as an add-on and reaching for WebSockets as the default transport for everything. WebSockets certainly have their place, but in many business applications they can bring extra operational weight around scaling, connection lifecycle, message handling, and recovery after failure. Even automatic reconnect becomes more complicated once distributed infrastructure, missed messages, retries, and partial client state enter the picture. By contrast, a server-led approach built around downstream SSE and very small upstream pushes can stay simpler, quieter, and easier to reason about both architecturally and operationally.&lt;/p&gt;

&lt;p&gt;Bringing it back to healthcare, this is also part of why many &lt;strong&gt;FHIR-based architectures&lt;/strong&gt; still feel incomplete when compared to the practical event movement that made &lt;strong&gt;HL7-style workflows&lt;/strong&gt; so effective in the real world. FHIR has brought major improvements in structure, readability, and interoperability, but many implementations still lean too heavily on request-response thinking, polling, or subscription models that do not yet fully embrace true event-first communication. Until more FHIR-based ecosystems grow toward genuinely event-based exchange, where systems publish and react to meaningful changes as they occur, they will continue to struggle to replace the practical strengths that older HL7 workflows delivered in high-volume operational environments.&lt;/p&gt;

&lt;p&gt;The future is not just better resource models. It is better system-to-system communication built around events as first-class citizens.&lt;/p&gt;

</description>
      <category>eventdriven</category>
      <category>webdev</category>
      <category>architecture</category>
      <category>software</category>
    </item>
    <item>
      <title>🚨 This isn’t a hit piece. It’s a reality check for anyone building serious systems with GraphQL.</title>
      <dc:creator>Anthony Master</dc:creator>
      <pubDate>Sat, 30 Aug 2025 04:38:00 +0000</pubDate>
      <link>https://dev.to/amaster507_59/this-isnt-a-hit-piece-its-a-reality-check-for-anyone-building-serious-systems-with-graphql-395i</link>
      <guid>https://dev.to/amaster507_59/this-isnt-a-hit-piece-its-a-reality-check-for-anyone-building-serious-systems-with-graphql-395i</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/amaster507_59/when-the-graph-snaps-a-hard-look-at-graphqls-pain-points-4ko1" class="crayons-story__hidden-navigation-link"&gt;When the Graph Snaps: A Hard Look at GraphQL's Pain Points&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/amaster507_59" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F832703%2Fe16febe8-363d-4d0a-acdc-66a71a8882b8.jpeg" alt="amaster507_59 profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/amaster507_59" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Anthony Master
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Anthony Master
                
              
              &lt;div id="story-author-preview-content-2808812" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/amaster507_59" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F832703%2Fe16febe8-363d-4d0a-acdc-66a71a8882b8.jpeg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Anthony Master&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/amaster507_59/when-the-graph-snaps-a-hard-look-at-graphqls-pain-points-4ko1" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Aug 30 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/amaster507_59/when-the-graph-snaps-a-hard-look-at-graphqls-pain-points-4ko1" id="article-link-2808812"&gt;
          When the Graph Snaps: A Hard Look at GraphQL's Pain Points
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/graphql"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;graphql&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/softwareengineering"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;softwareengineering&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/softwaredevelopment"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;softwaredevelopment&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/amaster507_59/when-the-graph-snaps-a-hard-look-at-graphqls-pain-points-4ko1" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;1&lt;span class="hidden s:inline"&gt; reaction&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/amaster507_59/when-the-graph-snaps-a-hard-look-at-graphqls-pain-points-4ko1#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            24 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>graphql</category>
      <category>webdev</category>
      <category>softwareengineering</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>When the Graph Snaps: A Hard Look at GraphQL's Pain Points</title>
      <dc:creator>Anthony Master</dc:creator>
      <pubDate>Sat, 30 Aug 2025 04:31:53 +0000</pubDate>
      <link>https://dev.to/amaster507_59/when-the-graph-snaps-a-hard-look-at-graphqls-pain-points-4ko1</link>
      <guid>https://dev.to/amaster507_59/when-the-graph-snaps-a-hard-look-at-graphqls-pain-points-4ko1</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;TL;DR&lt;/strong&gt; – GraphQL: Beautiful Nightmare
&lt;/h2&gt;

&lt;p&gt;GraphQL looks great on the surface—flexible queries, typed schemas, and the promise of fewer endpoints. But once you move past demo apps and into real-world systems, it reveals serious flaws:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Versioning is a lie&lt;/strong&gt; – No clean way to retire old fields without breaking clients.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relational mapping breaks down&lt;/strong&gt; – N+1 queries everywhere unless you hand-optimize.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pagination is inconsistent&lt;/strong&gt; – Multi-dimensional trees, different needs at different levels, no standard pattern.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deep queries go unchecked&lt;/strong&gt; – Clients can crater performance without guardrails.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filtering gets messy&lt;/strong&gt; – Complex filters require awkward nested input types, often forcing you to restructure your whole query.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repeated nodes + inconsistent shapes&lt;/strong&gt; – No normalization, tons of duplication, and brittle client logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend logic is hidden&lt;/strong&gt; – Seemingly “cheap” fields might hit expensive services or timeouts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Federation = Fragile&lt;/strong&gt; – Stitching systems across domains is complex, slow, and hard to secure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rigid structures&lt;/strong&gt; – Can’t return associative data, groupings, or CTE-style responses without workarounds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Schema generators trap you&lt;/strong&gt; – You inherit someone else's assumptions and can’t escape easily.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solutions fade&lt;/strong&gt; – Tools disappear, hype dies, and you’re left with a brittle graph.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Been there. Done that. Got the T-shirt.
&lt;/h3&gt;

&lt;p&gt;GraphQL is elegant—but only if you're ready to fight for every inch of usability and scalability. Otherwise, fixing it later is nearly impossible.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;GraphQL: Hard to do right. Brutal to fix. Cataclysmic if done wrong.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  It's elegant. Until it isn't.
&lt;/h2&gt;

&lt;p&gt;GraphQL is a beautifully marketed idea. Its promises are alluring: flexible queries, single-endpoint APIs, tight client control, and introspective schemas. For many developers, it feels like the answer to the endless bloat and over-fetching problems of REST. And in some use cases, especially small-to-medium internal tools or greenfield apps, GraphQL can indeed shine.&lt;/p&gt;

&lt;p&gt;But in large-scale, real-world production environments—especially those with relational data, legacy systems, multi-tenant platforms, or federated architectures—GraphQL quickly reveals its cracks. The elegance of the syntax is often a facade hiding a minefield of architectural gotchas. What seems flexible on the surface can become rigid underneath. What appears powerful often comes with steep trade-offs. And what feels like control for the front-end can be chaos for the back-end.&lt;/p&gt;

&lt;p&gt;The challenge isn’t just &lt;em&gt;doing GraphQL&lt;/em&gt;. The challenge is &lt;strong&gt;doing GraphQL right&lt;/strong&gt;—which means anticipating edge cases, managing performance at scale, implementing deep access controls, standardizing pagination, optimizing query resolution, and maintaining schema health over time. Without careful upfront planning, what starts as a clean schema quickly turns into a brittle interface that’s hard to evolve, slow to resolve, and costly to maintain.&lt;/p&gt;

&lt;p&gt;This isn’t a hit piece. It’s a reality check. GraphQL has a role—but it’s not the magic wand it’s often sold as. Let’s walk through the real friction points developers and architects face when they try to use GraphQL seriously—not in tutorials, but in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔁 Versioning: The Invisible Wall
&lt;/h2&gt;

&lt;p&gt;GraphQL claims to solve versioning by encouraging schema evolution over time. In theory, instead of creating &lt;code&gt;/v1/&lt;/code&gt; or &lt;code&gt;/v2/&lt;/code&gt; API endpoints, you simply deprecate old fields and add new ones. But in reality, this approach only works in environments with &lt;strong&gt;tight governance&lt;/strong&gt;, &lt;strong&gt;strict client discipline&lt;/strong&gt;, and a &lt;strong&gt;limited audience&lt;/strong&gt;. Once third-party consumers or mobile clients start hitting your schema, backward compatibility becomes non-negotiable—and deprecation is just a toothless warning.&lt;/p&gt;

&lt;p&gt;The lack of true versioning means deprecated fields must remain indefinitely unless you’re willing to break clients or force updates across all consumers. This can cause a &lt;strong&gt;buildup of technical debt&lt;/strong&gt; that clutters your schema and confuses newer developers trying to understand which fields are safe to use. Over time, your "clean" graph becomes an archaeological dig site of legacy data paths.&lt;/p&gt;

&lt;p&gt;Without clear version boundaries, teams often resort to naming hacks like &lt;code&gt;email_v2&lt;/code&gt; or &lt;code&gt;getUserUpdated&lt;/code&gt; just to introduce functional improvements. These hacks defeat the elegance of GraphQL's self-documenting nature and signal the same kind of decay we see in REST APIs that lack versioning standards. Worse, when fields are duplicated instead of evolved properly, bugs re-emerge due to misunderstood behavior or partial migration.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Versioning isn't just about code—it's about contract&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The reality is, &lt;strong&gt;versioning isn't just about code—it's about contract&lt;/strong&gt;. GraphQL obscures the natural contract boundary that REST made explicit. If you treat your schema as eternal and unchangeable, you lose agility. If you treat it as mutable and ephemeral, you lose stability. You're trapped between the two, with no clean way to reset without massive rewrites. That’s why many GraphQL projects eventually abandon schema purity and revert to namespaced APIs—or just deal with the mess until it's too late.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔗 Relational Data ≠ GraphQL Data
&lt;/h2&gt;

&lt;p&gt;One of the most common implementation strategies for GraphQL—especially in CRUD-style applications—is to place a GraphQL API directly over a relational database. It makes sense at first glance: your data already lives in tables with relationships, and GraphQL seems like a natural way to expose those relationships in a flexible, client-friendly structure. But this surface alignment is deceptive. GraphQL’s conceptual model and the relational model may overlap in terminology, but &lt;strong&gt;they diverge sharply in behavior and performance.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In SQL, relationships are navigated with joins. These joins are optimized by decades of research into query planning, indexing, and cardinality estimation. But GraphQL doesn’t come with an implicit query planner or optimizer. It delegates that responsibility to your resolvers. So when a query requests a list of users and their associated comments, you may accidentally execute &lt;strong&gt;one query to get users and then N additional queries for their comments&lt;/strong&gt;—known as the N+1 problem. Without proper batching (e.g., via Dataloader), GraphQL becomes a &lt;strong&gt;multiplicative query nightmare&lt;/strong&gt; over otherwise efficient relational structures.&lt;/p&gt;

&lt;p&gt;Moreover, SQL is a declarative language, while GraphQL resolvers are imperative. That means logic that would be handled in a single elegant SQL query—such as filtering users based on the count of related orders, or performing a recursive CTE to get a hierarchy—is often &lt;strong&gt;impossible or impractical to express&lt;/strong&gt; through GraphQL without writing deeply custom resolver logic or pushing it into suboptimal app-layer code.&lt;/p&gt;

&lt;p&gt;Then comes the issue of &lt;strong&gt;granular access control&lt;/strong&gt;. In a relational system, you might use row-level security, views, or carefully scoped SQL to control what data is exposed to which user. But in GraphQL, those access patterns must be reimplemented manually at the resolver layer, often leading to inconsistencies or logic duplication across multiple node types. This creates both a &lt;strong&gt;maintenance burden&lt;/strong&gt; and a &lt;strong&gt;security liability&lt;/strong&gt; if not carefully audited.&lt;/p&gt;

&lt;p&gt;In short, mapping GraphQL directly over a relational schema seems like a shortcut, but it often leads to performance bottlenecks, poor data modeling compromises, and a leaky abstraction between what your database can do and what your API is forced to support. A well-structured SQL schema should remain expressive and performant—but shoehorning it into a resolver-per-field model can erode all those gains and leave your team wrestling with custom workarounds that SQL could have handled in a single line.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧨 The N+1 Problem (Yes, Again)
&lt;/h2&gt;

&lt;p&gt;If there’s a single GraphQL pitfall that every developer learns the hard way, it’s the infamous &lt;strong&gt;N+1 problem&lt;/strong&gt;. It’s not a theoretical issue—it’s a practical performance trap that turns what should be a handful of database calls into hundreds or thousands. And worse, it’s often invisible until your app is under real user load or running in production.&lt;/p&gt;

&lt;p&gt;The N+1 issue typically arises when a query asks for a list of entities, along with some nested or related data. For example, a query might ask for a list of posts, and for each post, include the author’s details. Unless you’ve optimized, this will result in one query to fetch all posts, and then &lt;strong&gt;one additional query for each post’s author&lt;/strong&gt;—hence N+1 queries total. If you're fetching 100 posts, that’s 101 queries. Add more nesting, and the problem compounds exponentially.&lt;/p&gt;

&lt;p&gt;While solutions like &lt;strong&gt;Facebook's Dataloader&lt;/strong&gt; or batching resolvers can help, they require discipline, architecture, and explicit implementation. There’s no magical setting to fix N+1 globally. You must design your data-fetching strategy with this in mind from the beginning, or face major rewrites later. For every nested field or related list, you have to ask: “Is this being batched?” And if it’s not, your API is on a ticking time bomb.&lt;/p&gt;

&lt;p&gt;It’s also not just a database issue. And while graph databases claim this problem is resolved (pun intended), it will quickly reappear when you have to add custom lambda resolvers to fill in the gaps of missing functionality and business logic. The N+1 problem happens across &lt;strong&gt;any boundary&lt;/strong&gt;—database, service calls, file systems, or federated endpoints. If your resolvers trigger a microservice call, an external HTTP request, or an internal caching layer, the problem scales across &lt;strong&gt;network latency&lt;/strong&gt;, &lt;strong&gt;rate limits&lt;/strong&gt;, and &lt;strong&gt;third-party bottlenecks&lt;/strong&gt;. What looked like an elegant tree of fields can suddenly become a &lt;strong&gt;forest of RPC swamp&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In REST or RPC-style APIs, you have clear control over what data is returned per request. In GraphQL, the client decides—meaning you must handle &lt;em&gt;every possible shape of query&lt;/em&gt; efficiently, or be vulnerable to accidental (or intentional) query abuse. The N+1 problem isn’t just a quirk—it’s a systemic architectural challenge, and if ignored, it will quietly consume your performance budget one nested field at a time.&lt;/p&gt;

&lt;h2&gt;
  
  
  📦 Pagination: Choose Your Pain
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;In GraphQL, pagination becomes multi-dimensional&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In most APIs, pagination is straightforward: you request a list of items, specify how many you want, and maybe where to start. But in GraphQL, pagination becomes &lt;strong&gt;multi-dimensional&lt;/strong&gt;—because you're not paginating a single list, you're paginating &lt;strong&gt;potentially many lists&lt;/strong&gt;, across multiple levels of a query tree, each with different sizes, shapes, and expectations. And it’s here that the elegant facade starts to crack.&lt;/p&gt;

&lt;p&gt;Say you're querying a list of 1000 users, and for each user, you want to show their 5 most recent orders. In a REST world, you’d probably design this as two endpoints or add an explicit constraint on the nested list. In GraphQL, the client has the freedom to request all 1000 users, and for each of them, all of their orders—unless you enforce limits at every resolver layer. The result? You’ve just built a pagination-unaware N+1 problem… again.&lt;/p&gt;

&lt;p&gt;But it gets more complicated. What if one field in your query—say, &lt;code&gt;friends&lt;/code&gt;—needs deep pagination (500+ results), while another nested field—like &lt;code&gt;roles&lt;/code&gt; or &lt;code&gt;tags&lt;/code&gt;—only ever has 3 or 4 items? The ideology of one page = one GraphQL query no longer plays nice. To paginate through your friends you might send the whole request again to paginate just on the &lt;code&gt;friends&lt;/code&gt; level. And to add even more complication, if there is a nested field on &lt;code&gt;friends&lt;/code&gt; that also needs paginated like their shared &lt;code&gt;interests&lt;/code&gt;, now you are paginating over every friend's interests instead of just one of them. That’s fine in theory, but GraphQL doesn’t give you a simple way to handle &lt;strong&gt;mixed granularity pagination&lt;/strong&gt;. You’re forced to manage independent pagination logic within multiple queries, often duplicating logic across resolvers. Worse, on the client side, merging paginated data from nested fields into a clean UI becomes maddening.&lt;/p&gt;

&lt;p&gt;And because GraphQL has no built-in pagination behavior, every field can—and often does—implement it differently. Some use &lt;code&gt;limit/offset&lt;/code&gt;, others use cursors, some wrap data in Relay-style &lt;code&gt;edges/nodes&lt;/code&gt;, and some don’t paginate at all. This inconsistency is painful for consumers, who must learn not just &lt;em&gt;how&lt;/em&gt; to paginate, but &lt;strong&gt;how to paginate differently&lt;/strong&gt; depending on the field they’re querying.&lt;/p&gt;

&lt;p&gt;Ultimately, GraphQL pagination is hard not because pagination itself is hard, but because the GraphQL model &lt;strong&gt;amplifies the complexity&lt;/strong&gt; of variable nested list sizes, unbounded queries, and client-side flexibility. You're not just paginating a dataset—you're paginating the entire shape of a request tree, &lt;strong&gt;one list at a time&lt;/strong&gt;. And if you skip the upfront work of pagination rules, field limits, and documentation, you'll soon find your server bogged down by bloated queries and confused consumers trying to figure out why some nested item lists return 100 items, while others silently now show none.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧬 Deep Queries, No Limits
&lt;/h2&gt;

&lt;p&gt;One of GraphQL’s most powerful features is that it allows clients to define exactly what data they need—across deeply nested relationships. But that’s also one of its most dangerous features. In REST, each endpoint is fixed—you know what you’re going to get, and how big the response will be. In GraphQL, a client can request not just one entity, but every relationship beneath it, recursively, with no built-in limit on depth or breadth. The result? A query that looks elegant in the IDE but &lt;strong&gt;crushes your back-end under the weight of recursion, joins, and memory usage&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Unless you explicitly control for this, it’s possible for a single GraphQL query to pull data across dozens of nested entities. A user can query all customers, their orders, each order’s items, each item’s manufacturer, every manufacturer’s shipping history, and so on—&lt;em&gt;in one call&lt;/em&gt;. While this may sound empowering for front-end developers, it poses massive threats to stability and performance. Left unchecked, it’s a &lt;strong&gt;self-denial-of-service&lt;/strong&gt; attack vector waiting to happen.&lt;/p&gt;

&lt;p&gt;To make matters worse, GraphQL’s introspective and self-documenting nature encourages exploration. It invites users—especially curious internal teams—to try bigger and deeper queries just to "see what comes back." That’s great in dev tools like GraphiQL or Postman, but in production? Every deep query hits your resolvers, triggers back-end logic, and pulls potentially huge volumes of data across multiple domains. What should have been a few milliseconds of data access becomes a &lt;strong&gt;cascade of latency&lt;/strong&gt;, memory strain, and serialization bloat.&lt;/p&gt;

&lt;p&gt;You can try to mitigate this with query depth limits, query complexity scoring, or third-party libraries like &lt;code&gt;graphql-depth-limit&lt;/code&gt;. But these add configuration overhead, and they often need to be fine-tuned per use case to avoid blocking legitimate queries. And if you use federation or third-party resolvers, it's even harder to know where the back-end work is happening—and how costly that query really is.&lt;/p&gt;

&lt;p&gt;The dream of “ask for exactly what you need” turns into a nightmare when clients start asking for &lt;strong&gt;everything&lt;/strong&gt;. GraphQL empowers deep queries, but without enforced limits, guardrails, or architectural policies, it’s all too easy to build a system where the most enthusiastic users are the ones causing the most performance degradation.&lt;/p&gt;

&lt;h2&gt;
  
  
  🌀 Repeated Children, Inconsistent Structures
&lt;/h2&gt;

&lt;p&gt;One of GraphQL’s hallmark selling points is that it lets clients shape responses to match their exact needs—fetching only the fields they want, in the structure they prefer. It sounds clean, efficient, and liberating compared to bloated REST payloads. But here’s the reality: &lt;strong&gt;most clients need most of the data&lt;/strong&gt;. Whether you’re building tables, forms, or dashboards, your UI will almost always require a complete view of the record—not a pick-and-choose subset.&lt;/p&gt;

&lt;p&gt;In practice, developers end up querying &lt;strong&gt;every field anyway&lt;/strong&gt;—not because they want to over-fetch, but because the UI demands it. And if they don't as soon as they show that one hidden column, then the whole query runs again with the added field. Talk about over-fetching &lt;em&gt;everything&lt;/em&gt;. The flexibility to pick your fields ends up becoming just &lt;strong&gt;another layer of ceremony&lt;/strong&gt;. What was once sold as a lean, client-customizable API becomes a fragile dance: every component defines its own ad hoc query shape, even when 90% of those queries are identical across the app. Instead of encouraging reuse and consistency, GraphQL enables a kind of &lt;strong&gt;fragmented chaos&lt;/strong&gt;, where the same resource is requested in a dozen ever so slightly different structures by different consumers.&lt;/p&gt;

&lt;p&gt;And it gets worse in recursive or parent-child relationships. Fetch a list of items with nested children, and each child might show up again under a different parent or branch. For instance, querying for a &lt;code&gt;person&lt;/code&gt; (yourself—1 record), then your &lt;code&gt;posts&lt;/code&gt; (example 40 posts), and then the &lt;code&gt;author&lt;/code&gt; of each post, now you have your &lt;em&gt;same&lt;/em&gt; person record duplicated 41 times in a single response. GraphQL doesn’t deduplicate these—every instance is returned in full. The same object could appear &lt;strong&gt;verbatim&lt;/strong&gt; multiple times in a single query response. On the backend, you’re re-resolving and re-serializing redundant data. On the frontend, you’re re-rendering and reconciling inconsistent payload shapes. Caching can help somewhat to resolve this, but then you have worry about one of the hardest parts of programming—cache invalidation.&lt;/p&gt;

&lt;p&gt;Previously, APIs offered a hardened, predictable view into your data. REST endpoints were often crafted with specific use cases in mind. A &lt;code&gt;GET /users&lt;/code&gt; endpoint might return a flat, consistent object; a &lt;code&gt;GET /users/:id/details&lt;/code&gt; would return more—but you &lt;em&gt;knew&lt;/em&gt; what to expect. In GraphQL, that consistency vanishes. The structure of the data is now determined by whoever writes the query, resulting in a tangled mess of optional fields, repeated nodes, alias collisions, and partial types that defy predictability.&lt;/p&gt;

&lt;p&gt;So instead of saving effort, GraphQL often forces developers to &lt;strong&gt;reinvent the schema at the point of use&lt;/strong&gt;—adding mental overhead, duplication, and inconsistency across teams. And when it comes time to refactor? Good luck—because every query is shaped differently, there’s no unified contract to update. What started as elegance has, in many cases, devolved into a structural free-for-all.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧭 Filtering Gets Weird
&lt;/h2&gt;

&lt;p&gt;Filtering in GraphQL feels like it should be simple—after all, you're just asking for a subset of data, right? But the moment you step beyond shallow, single-field filters like &lt;code&gt;status: "active"&lt;/code&gt; or &lt;code&gt;name: "Bob"&lt;/code&gt;, things get awkward fast. GraphQL leaves filtering entirely up to the schema designer, which sounds like freedom… until you're the one designing it. There’s no native, standardized way to do filtering, so every API ends up reinventing its own filter input types—often inconsistently across entities and domains.&lt;/p&gt;

&lt;p&gt;Want to filter across a parent-child relationship? Like: “Give me all users who have at least one order over $100”? That’s trivial in SQL—a simple join with a &lt;code&gt;WHERE EXISTS&lt;/code&gt; clause. In GraphQL, it turns into deeply nested input objects, custom logic in your resolvers, and often brittle abstractions that require bespoke code for each case. You might define an &lt;code&gt;orders_some: { total_gt: 100 }&lt;/code&gt; field, or worse, expose a raw JSON filter blob and let the back-end interpret it. Either way, you’re either duplicating SQL semantics manually or leaking internal logic into your schema.&lt;/p&gt;

&lt;p&gt;But here’s where it really falls apart: sometimes you &lt;strong&gt;can’t express the filter at all from your current root&lt;/strong&gt;. You might be querying &lt;code&gt;users&lt;/code&gt;, but the condition you need only exists three levels deep—say, &lt;code&gt;users → organizations → subscriptions → status&lt;/code&gt;. If the schema doesn’t support filtering by those deep relationships (and most don’t), your only option is to &lt;strong&gt;change your root to something like&lt;/strong&gt; &lt;code&gt;subscriptions&lt;/code&gt; just so you can apply the filter at the top. Now your response shape is completely different. The structure your UI was expecting is gone. You’ve lost your pagination context. You’re no longer building a page of users with subscription data—you’re building a page of subscriptions with user data bolted on. &lt;strong&gt;You’ve inverted your entire query&lt;/strong&gt; just to make the back-end work.&lt;/p&gt;

&lt;p&gt;That means every edge case filter becomes not just a filter problem—it’s a &lt;strong&gt;query design and layout problem&lt;/strong&gt;. You start duplicating front-end logic to rebuild the expected structure, or you fragment your UI into separate fetches to work around shape mismatch. GraphQL was supposed to unify data access. Instead, you’re contorting your queries just to satisfy back-end limitations, and losing consistency in how you build and consume data.&lt;/p&gt;

&lt;p&gt;Combine this with the fact that AND/OR logic, range filters, fuzzy matches, and custom operators all require bespoke design, and your filter inputs balloon in complexity. You end up duplicating logic across &lt;code&gt;UserFilterInput&lt;/code&gt;, &lt;code&gt;OrderFilterInput&lt;/code&gt;, &lt;code&gt;GroupFilterInput&lt;/code&gt;, etc., with no cross-schema reuse unless you manually abstract it. It’s verbose, inconsistent, and hard to test. And unless you’re building your schema on top of a query builder library (like Prisma or Hasura), &lt;strong&gt;you’re hand-authoring most of it anyway—and debugging it when it goes wrong&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In short, filtering in GraphQL feels like trying to replicate the expressive power of SQL… but without joins, without context, and without a clear place to start. You either contort your shape, sacrifice your response consistency, or write multiple disjointed queries to get at what should have been one clean answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧱 Federation Across Disparate Systems
&lt;/h2&gt;

&lt;p&gt;At first glance, GraphQL federation seems like the holy grail: multiple teams, services, or domains exposing parts of a unified graph—stitched together seamlessly so clients can query across organizational and infrastructure boundaries. You imagine pulling user data from an internal service, product data from an external vendor, and analytics from a third-party platform—all in one clean query. But the promise of federation quickly fades when it meets the &lt;strong&gt;messiness of real-world systems&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;GraphQL becomes a choreographed dance across networks&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The first challenge is &lt;strong&gt;latency and reliability&lt;/strong&gt;. In a federated setup, each field might hit a different upstream source—one field might query a local Postgres database, another might resolve from a legacy SOAP API, and another might pull from a cloud service over HTTP. A single GraphQL query now becomes a &lt;strong&gt;choreographed dance across networks&lt;/strong&gt;, each leg introducing its own delays, timeouts, retries, and failure modes. One slow service degrades the entire query. One bad link breaks the chain.&lt;/p&gt;

&lt;p&gt;Then there's the issue of &lt;strong&gt;orchestration logic&lt;/strong&gt;. Who handles the joins? Who decides how one service maps a key to another? GraphQL doesn't solve this for you—it simply delegates. You're responsible for writing custom resolvers that know how to resolve keys across services, cache what needs caching, and reconcile differences in naming, data types, or even fundamental models of the world. You’re not just building a unified graph—you’re building a &lt;strong&gt;fragile abstraction layer&lt;/strong&gt; on top of a dozen incompatible systems.&lt;/p&gt;

&lt;p&gt;And don’t forget access control. Each system might have different permission models, audit requirements, or PII sensitivity. When you stitch them into a single graph, you can’t rely on the consumer to “just know” which fields are safe to access. You now need &lt;strong&gt;cross-system authorization rules&lt;/strong&gt;, audit logging, and policy enforcement at every edge. Otherwise, a user with access to a harmless internal entity may gain visibility into sensitive external data, simply by crafting the right GraphQL query.&lt;/p&gt;

&lt;p&gt;Worse still, federation often doesn’t stop at your infrastructure boundary. Teams try to federate GraphQL APIs across &lt;strong&gt;disconnected systems&lt;/strong&gt;—between departments, partner organizations, or even public APIs. But GraphQL wasn’t designed for distributed trust models. There’s no native support for inter-service authentication, query shaping guarantees, rate limits, or cost negotiation across boundaries. You wind up building a bespoke gateway or proxy, &lt;strong&gt;re-implementing REST-like patterns&lt;/strong&gt; just to maintain safety and performance.&lt;/p&gt;

&lt;p&gt;Even within your own org, federation comes at a steep operational cost. Schema stitching, entity ownership boundaries, resolver orchestration, shared standards—it’s all manual, and &lt;strong&gt;fragile without rigorous governance&lt;/strong&gt;. And all the existing tooling (Apollo Federation, GraphQL Mesh, etc.) works well only within certain guardrails. Step outside those, and you’re left duct-taping together services that were never meant to be siblings in a unified graph.&lt;/p&gt;

&lt;p&gt;Federation sounds like distributed elegance. In reality, &lt;strong&gt;it’s a tightrope walk over a pit of legacy systems, contract mismatches, and latency traps&lt;/strong&gt;. It works—but only with discipline, buy-in, and deep architectural investment. And once you're federating across systems you don’t fully control—cloud vendors, external APIs, or legacy black boxes—it becomes nearly impossible to debug, evolve, or optimize the graph holistically.&lt;/p&gt;

&lt;h2&gt;
  
  
  🕳️ Hidden Back-end Design Decisions
&lt;/h2&gt;

&lt;p&gt;One of GraphQL’s promises is transparency: clients can explore the schema, understand what’s available, and query exactly what they need. But that visibility is surface-level. Beneath the schema lies a complex web of back-end logic, micro-services, database calls, and third-party APIs that &lt;strong&gt;aren’t exposed through introspection&lt;/strong&gt;—and that’s where the real problems start. Because in GraphQL, &lt;strong&gt;you never really know what you’re triggering&lt;/strong&gt; with a query.&lt;/p&gt;

&lt;p&gt;On the surface, a field like &lt;code&gt;user.lastLogin&lt;/code&gt; might look harmless—but it could call a logging micro-service, query a slow analytics database, or even make an API call to a vendor’s platform. Meanwhile, a seemingly heavy field like &lt;code&gt;user.permissions&lt;/code&gt; might be fully cached and lightning fast. There’s no way for the client to know. GraphQL treats every field as equal—but performance, stability, and cost are not. As a result, clients write queries based on what they see, but the back-end is reacting to &lt;em&gt;what they don’t know they’re asking for&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This disconnect leads to a serious architectural blind spot. Query A and Query B might look identical in shape, but one causes a massive spike in compute or network calls. And because the schema itself hides this complexity, there’s no way to proactively prevent misuse. You can introduce tooling to estimate query cost or trace resolvers—but these are afterthoughts. &lt;strong&gt;GraphQL gives consumers all the power, with none of the context to use it responsibly&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It also causes problems for collaboration. Back-end teams can update the logic behind a resolver—switching a fast in-memory lookup to a slow database join—and suddenly, a harmless-looking query becomes a bottleneck. There’s no contract, no warning, and no separation of concerns. Every field in the graph is &lt;strong&gt;a tightly coupled handshake between the consumer’s expectations and the back-end's implementation&lt;/strong&gt;, which can (and will) change over time.&lt;/p&gt;

&lt;p&gt;To compensate, teams start layering in rules, limits, and complexity guards—query depth checks, cost analyzers, rate limiting, and even field-level access controls. But these often feel bolted on. The elegance of GraphQL’s query model erodes as you’re forced to defensively wrap it in back-end logic just to make sure clients don’t trigger something catastrophic. It’s like giving someone a beautiful interface to a rocket engine—&lt;strong&gt;without warning them about the fuel system, heat shielding, or launch sequence&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So while GraphQL exposes the schema, it obscures the &lt;strong&gt;consequences&lt;/strong&gt; of querying that schema. And in systems where performance, cost, and reliability matter, that’s not just an inconvenience—it’s a liability.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧰 Lack of Structural Flexibility
&lt;/h2&gt;

&lt;p&gt;GraphQL is often praised for its flexibility—but that flexibility only goes one way: the client gets to shape the query, but the back-end must rigidly conform to the types, fields, and structures defined in the schema. And as soon as your data doesn’t neatly fit into GraphQL’s strict trees of objects and lists, you start running into walls that are surprisingly hard to get around.&lt;/p&gt;

&lt;p&gt;Take a common scenario: You want to return a collection of results, but you want them keyed by a meaningful identifier—something like an object in PHP or a dictionary in Python or JavaScript. GraphQL doesn’t support that. If you try to return an associative array or a map-like object keyed by IDs, GraphQL’s schema validation will reject it unless you wrap it in a custom scalar or convert it into an array of key/value objects—adding &lt;strong&gt;unnecessary complexity&lt;/strong&gt; to both the schema and the client logic. You can alias fields, but you can’t change the structure of a list to suit your data modeling needs.&lt;/p&gt;

&lt;p&gt;You also can’t express “dynamic keys” cleanly. If your data comes in keyed by dynamic values—like locales, timestamps, user IDs, or anything non-static—you’re forced to hack around it with custom types, nested lists, or pre-transformed responses. The end result is awkward and repetitive. Instead of letting the structure adapt to your data, you’re stuck bending your data to fit the rigid schema. And once you do that, you’ve already &lt;strong&gt;sacrificed both readability and usability&lt;/strong&gt; for the sake of staying schema-compliant.&lt;/p&gt;

&lt;p&gt;It becomes especially painful when trying to aggregate or group results. In SQL, it’s trivial to group by a field and return a structured result—say, a map of users grouped by role. In GraphQL, there’s no native mechanism to express that structure. You have to define new custom types and fields for every aggregation you want to support. What would’ve been a one-line SQL CTE now requires five schema types, a specialized resolver, and extra client logic to unroll the array into a usable keyed structure.&lt;/p&gt;

&lt;p&gt;And again, this isn’t just a back-end annoyance—it bleeds into the client. Developers often expect the shape of the data to match their component needs. But since GraphQL only deals in nested objects and flat arrays, they frequently have to &lt;strong&gt;reshape the response manually&lt;/strong&gt;, writing post-processing logic just to turn lists into dictionaries, flatten hierarchies, or collapse duplicates. You’re duplicating work that a database or ORM would have done for you—except now you’re doing it on the client, every time.&lt;/p&gt;

&lt;p&gt;In short: GraphQL &lt;em&gt;pretends&lt;/em&gt; to be flexible, but only if you stay within its object/list worldview. The moment your data has even a hint of structure that deviates from that model—associative maps, grouped records, conditional structures—you’re fighting the graph rather than flowing with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧮 The Limitations of Deep Filters and Joins
&lt;/h2&gt;

&lt;p&gt;One of the most frustrating aspects of GraphQL—especially for anyone coming from a strong relational or SQL background—is how &lt;strong&gt;limited it is when it comes to deep filtering and expressive data queries&lt;/strong&gt;. In SQL, it’s common to chain filters, perform conditional joins, and use Common Table Expressions (CTEs) to build powerful, readable queries across complex relationships. In GraphQL? Good luck.&lt;/p&gt;

&lt;p&gt;Want to get all users who belong to an organization that has at least one paid invoice in the last 30 days and who have never logged in? That’s a single, elegant SQL query with a few joins and conditions. In GraphQL, it becomes a nested monstrosity of filter input types, conditional wrappers, and deeply coupled resolvers. Worse, if your schema wasn't designed to allow filtering across those relationships (and most aren't by default), you can't even express the query—you’d need to restructure your schema or start from a different root entirely.&lt;/p&gt;

&lt;p&gt;This is where the illusion of GraphQL’s power starts to break. You can &lt;em&gt;ask&lt;/em&gt; for anything—&lt;em&gt;yes&lt;/em&gt;—but you can’t necessarily &lt;em&gt;filter&lt;/em&gt; or &lt;em&gt;join&lt;/em&gt; on what matters. Relationships in GraphQL are typically resolved one level at a time. There’s no built-in concept of a “join”—you fake it with nested resolvers. And every time you nest, you lose the ability to apply filters or constraints to the overall result set. This leads to a situation where what you need can’t be described from the root you’re on… so you change roots, reshape your query, and break your UI expectations in the process.&lt;/p&gt;

&lt;p&gt;Even in systems where complex filtering is supported via custom resolver logic or tools like Prisma or Hasura, that expressiveness is usually limited to &lt;strong&gt;one entity at a time&lt;/strong&gt;. Want to join conditions across siblings or cousins in the graph? You're out of luck. You either write an entirely new API entry point for that special case, or you stitch together partial responses in the client. You’re not querying a true graph of data—you’re querying a tree of fragments and &lt;strong&gt;hoping you can merge them later&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This architectural mismatch forces back-end developers to rebuild SQL-like semantics from scratch—AND exposes front-end developers to the limitations of those partial abstractions. Filtering by deep relationships, chaining conditions, or expressing negative logic (e.g., “users who don’t have X”) is &lt;em&gt;possible&lt;/em&gt;… but painful. And as your data model grows more complex, the friction grows with it.&lt;/p&gt;

&lt;p&gt;So while GraphQL claims to be “the graph of your data,” it’s more like a &lt;strong&gt;projection of a graph&lt;/strong&gt;—flattened, rigid, and unwilling to let you dig deeper than one resolver at a time. The deeper and more expressive your queries need to be, the more it becomes clear: you’re not designing the graph—you’re wrestling with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔒 Trapped by Schema Generators
&lt;/h2&gt;

&lt;p&gt;Many teams adopt GraphQL through auto-generators—tools that build a GraphQL schema automatically from an ORM, a database, or a set of models. It feels efficient at first: you get a full-featured API in minutes, complete with types, inputs, queries, and mutations. But what starts as a time-saver often ends in a &lt;strong&gt;rigid trap&lt;/strong&gt;, because you’re now operating entirely within the assumptions of someone else’s system.&lt;/p&gt;

&lt;p&gt;When a tool generates your schema, it decides what relationships look like, how filters behave, how mutations are structured, and what types are exposed. You inherit &lt;strong&gt;their data modeling philosophy&lt;/strong&gt;, which might be close to what you want—but rarely perfect. Want to filter nested children using an advanced condition? You might find it’s unsupported. Need to paginate a list that wasn’t built with pagination in mind? Too bad. Want to restructure a return type for better performance or UI consistency? Not without writing a ton of overrides or custom resolvers.&lt;/p&gt;

&lt;p&gt;The more sophisticated your use case becomes, the more you find yourself &lt;strong&gt;fighting the tool&lt;/strong&gt;, not just extending it. And because the generated schema is often tightly coupled to the internal data model, even small changes—like adding a calculated field or excluding a sensitive column—require deep hacks or break downstream contracts. You lose control over the structure and behavior of your graph, which defeats the entire purpose of adopting GraphQL in the first place.&lt;/p&gt;

&lt;p&gt;Eventually, your only options are to fork the schema, layer on wrappers, or start building custom resolvers beside the generated ones—none of which play nicely together. Worse, if the tool’s underlying assumptions don’t align with your front-end's needs, you may be forced to write &lt;strong&gt;multiple queries or compose data client-side&lt;/strong&gt;, just to reshape what should’ve been a single efficient query. The dream of clean data orchestration becomes a sprawl of fragmented queries and brittle workarounds.&lt;/p&gt;

&lt;p&gt;The tragedy here is that the tool was supposed to help you move faster. But instead, it put you in a box—and that box is made of someone else's opinions, someone else’s edge cases, and someone else's constraints. You didn’t build a custom graph API. You inherited a &lt;strong&gt;prefabricated lattice&lt;/strong&gt;, and now you’re stuck bolting on your actual use cases with duct tape.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧨 Looks Great Until It’s Real
&lt;/h2&gt;

&lt;p&gt;GraphQL is undeniably beautiful on paper. It looks like the elegant middle ground between REST and RPC—flexible, introspective, strongly typed, and customizable. For early-stage apps, internal tools, or prototyping environments, it can even feel magical. You build your schema, light up the playground, and queries just work. But once you scale beyond trivial use cases, the cracks start to show. And if you’re not careful, those cracks become &lt;strong&gt;chasms&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The biggest issue is the false sense of completeness&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The biggest issue isn’t even the technical limitations—it’s the &lt;strong&gt;false sense of completeness&lt;/strong&gt;. GraphQL solves the surface problems. Over-fetching, under-fetching, rigid endpoints? Fixed. But behind that are deeper concerns: inconsistent pagination, broken filtering, leaky abstractions, performance bottlenecks, deeply nested N+1 bombs, unpredictable back-end behavior, rigid schema structures, federation chaos, and client-side cartwheels just to shape the data how you actually need it.&lt;/p&gt;

&lt;p&gt;And here's the kicker—many of the tools that promised to fill those gaps? They're either abandoned, deprecated, or lost momentum after the hype wore off. Schema stitching tools gave way to federation frameworks, which gave way to server-less middle layers, which gave way to cloud providers who offered managed GraphQL back-ends with just enough functionality to impress... until you hit a wall and realized you couldn’t fix what they abstracted away. They sold solutions for &lt;em&gt;problems GraphQL created&lt;/em&gt;, and many of those tools left behind &lt;strong&gt;unmaintainable complexity&lt;/strong&gt; when the maintainers moved on.&lt;/p&gt;

&lt;p&gt;Security? Also an afterthought. Without rate limits, complexity scoring, or access guards on every resolver, you’re one creative query away from exposing too much, doing too much, or costing too much. The shape of a query hides the danger it contains. By the time you realize it, you're chasing down 15 nested fields, 5 unbounded lists, and 12 micro-service calls—all from a single GraphQL request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Been there. Done that. Got the T-shirt&lt;/strong&gt;. Literally. I presented at &lt;a href="https://www.youtube.com/watch?v=Ezy4XkvN2-8" rel="noopener noreferrer"&gt;Dgraph Day 2021&lt;/a&gt; thinking our journey from SQL to GraphQL was almost complete with Dgraph's generative GraphQL API. I hyped myself on the promise, before most of &lt;em&gt;this&lt;/em&gt; surfaced. And while I still believe GraphQL has its place, I now know this: &lt;em&gt;if you’re not prepared to do it right from the start, don’t do it at all&lt;/em&gt;. Fixing it later is almost impossible—because the cost of change rises exponentially with adoption. Once clients depend on your schema, once tooling gets built around it, once your data model calcifies into your graph... every limitation becomes a liability.&lt;/p&gt;

&lt;p&gt;So yes, GraphQL is elegant. But in real-world systems with messy data, competing priorities, multiple consumers, federated ownership, and deep access needs, elegance fades fast. What’s left is a schema-shaped prison—easy to enter, hard to escape, and nearly impossible to remodel without tearing down the walls.&lt;/p&gt;

&lt;p&gt;Use it wisely. Or don’t.&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>webdev</category>
      <category>softwareengineering</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>SOLVING PROBLEMS THAT WE CREATED</title>
      <dc:creator>Anthony Master</dc:creator>
      <pubDate>Sun, 16 Mar 2025 06:33:41 +0000</pubDate>
      <link>https://dev.to/amaster507_59/solving-problems-that-we-created-52l6</link>
      <guid>https://dev.to/amaster507_59/solving-problems-that-we-created-52l6</guid>
      <description>&lt;p&gt;TL;DR; Rethinking Web Dev...&lt;/p&gt;

&lt;p&gt;Everybody has tools that they use, and some tools they acquired to fix problems that someone else caused. I remember when I was the Service Manager for a GM dealership. Every month GM would send us new "special tools." These tools would eventually migrate from the corner of my desk to the "tool room." This tool room was not the place where all mechanics placed the tools they bought with their own money, but these were company tools. It didn't contain any "common" tools as you might call them for the average mechanic like a socket set, pullers, pliers, etc. No, this room contained the sockets, pullers, pliers and tools that didn't even resemble a typical tool that were specially designed for a very specific application. Then would come in the cars of that year and the mechanic would look up the repair guide and it would mention special tool GM-####, in order to complete the repair, the technician would need to locate the special tool to diagnose or repair the vehicle. More than once we would have the parts necessary to repair the vehicle, but could not for lacking of a special tool and we had to order or borrow it. If you are interested, the special tool website is actually public web: gmglobaltools.com. What I want to call out though is that many of these tools only existed because the engineers designed something that could only be diagnosed or repaired with a specially designed tool. I want to use this story to step into a deeper subject of web development, and our use of "special tools".&lt;/p&gt;

&lt;p&gt;I've been doing research recently into some new, yet old, tech. If you want to peek into my world and get deep into web development (there is a reason why I call it "development" and not "design"), then check out a few of the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;NATS.io&lt;/li&gt;
&lt;li&gt;data-star.dev&lt;/li&gt;
&lt;li&gt;protobuf.dev&lt;/li&gt;
&lt;li&gt;htmx.org&lt;/li&gt;
&lt;li&gt;go.dev&lt;/li&gt;
&lt;li&gt;html&lt;/li&gt;
&lt;li&gt;css&lt;/li&gt;
&lt;li&gt;js&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I say new, because some of these are really new like D* (data-star) isn't even out of beta v1 yet (really close though), but I say really old, because it takes roots back to the fundamental of how the web works, like html that was used on the first website (info.cern.ch) in 1993.&lt;/p&gt;

&lt;p&gt;I have been "burned" so many times lately, well in my whole IT career of 18+ years, because I have chosen elements in my tech stacks because they were popular, maintained, recommended, or just to sum it up, the fad. Many times it even looks like the solved the problem I was facing, when sometimes years later I resolved that they only solved a problem I created and yielded to creating more problems.&lt;/p&gt;

&lt;p&gt;It's the same truth, "if you don't learn from the past you are doomed to repeat it." It makes me look at what we have been doing with the recent fads of Web Dev, and makes me ask the question...&lt;/p&gt;

&lt;p&gt;ARE WE SOLVING PROBLEMS THAT WE CREATED?&lt;/p&gt;

&lt;p&gt;Ok, so I use the "we" very generally to include all the master minds of web development and not just the few of us that might ever read this post.&lt;/p&gt;

&lt;p&gt;While doing some research I was watching a few tech talks while washing the dishes tonight and since my hands were wet the player continued to a video I had not anticipated watching: "Building the Hundred-Year Web Service with html" by Alexander Petros [&lt;a href="https://youtu.be/lASLZ9TgXyc?si=2QA7NT_50-wtprEw" rel="noopener noreferrer"&gt;https://youtu.be/lASLZ9TgXyc?si=2QA7NT_50-wtprEw&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;Alex's opening introduction really caught my attention because I studied bridge architecture in high school in my first research project (thank you Mrs. Debbie Taylor. Readers please don't blame her for my bad grammar and run on sentences, she tried harder than I listened, haha!) Anyways, the intro brought to light some poor decision patterns I held as I try to be a web developer that builds something that lasts for generations. I usually think about problems as they exist today without taking into consideration what the problem might look like in 100 years. Now if I do solve the problem of today and do it well enough, it very well may stand the test of time. However, if I think fundamentally at what problem I am trying to solve and if that problem will exist and how it might exist in 100 years then I might solve it differently.&lt;/p&gt;

&lt;p&gt;I use to do quite a bit of what I call "traditional web work" and that involves things like basic template driven website development. These usually always end up with the same problems and similar solutions but they don't usually include much in terms of future proofing. "How easily can a different template or theme be changed out?" while that is usually considered "easy" when you actually attempt it at a deeper level, you quickly find all the oddities you did to "fix" the old theme that now have to be refactored to work for the new theme or template. And that doesn't even include staying up to date with the changing SaaS solutions that most web sites deeply depend upon whether that be WordPress, WIX, Laravel, React, or whatever. I look back now and see much of this work (while being beneficial and producing results) to have been done in a way that caused more problems in the future than what it solved for the current state.&lt;/p&gt;

&lt;p&gt;I look at a different project IFBMT, and I see that from a deeper level I approached some things wrong, but on a higher level I did some things well and that leads to its seeming success. The attempt to recevelop IFBMT into MissionBase with a modern framework and a state-of-the-art database platform should have worked by comparison of the fads of the trendy web. But that is just the problem, we set out to fix problems that I created, and while fixing those problems we only created additional problems up to the point that we had to make the hard decision to abandon the 2.0 project that visually was a success, but was a failure to launch. I have attempted a few times since to restart a new version of IFBMT, but each time seem to run into similar problems. The success of IFBMT was not just because it solved a niche problem that was unresolved and closed the three-way gap between donor management systems, contact relationship management systems, and independent baptists, but because it did it in such a way that it has been practically hands off running for the most part since 2018. Compared to other web apps, IFBMT (v1) is close to end of life. I say that not because it is planning to shut down any time soon, just because LTS usually ends for a version after 5 years, with most version 1 being replaced in only 2 years. So what is it that has helped it stand up so long with so relatively little maintenance and support? (a standing rhetorical question, I am continuing to answer - thoughts on using very LTS versioned tech stack?)&lt;/p&gt;

&lt;p&gt;I now venture down a different brain pathway of where my professional career has taken me and I found another diamond (howbeit dull) in the rough with HL7 v2. It amazes me that HL7 v2 is almost the same age as I am, released in 1989! Literally the reasoning for my job is because hospitals and 3rd party applications are still utilizing a technology standard that is widely supported and hailed as the superior (arguably, it is not) mechanism for exchanging healthcare data. HL7 is a strange animal because there have been attempts and even whole new architectures released and pushed to replace v2, yet it persists forward nonetheless. Version 3 was not widely adopted due to it's complexity, lack of backwards compatibility with the widely used v2, and the steep learning curve associated with its implementation. The latest version of HL7 (commonly referred to as FHIR) is not even meant as a replacement for HL7 v2, but rather as a way to compliment it and offer a more modern approach to healthcare data exchange using RESTful web services. Just some interesting thoughts here...&lt;/p&gt;

&lt;p&gt;REST is seen all across web dev today, but I wonder how many actually know what problems it solved and how well it still does at solving that problem. This takes us back from healthcare data exchange back into Web Dev. REST stands for REpresentational State Transfer, and is a software architectural style first defined in 2000 (a quarter century ago now). in my honest opinion, modern frameworks don't rely on REST as much as they should. The standard's purpose was to establish a standard for how servers could communicate and exchange data, leading to a simpler and more flexible approach to API design. REST fundamentally solves many of the SOLID principals and approach to development if the rest (no pun intended) would just be done correctly as well. REST if coupled with the correct architecture has been proven to solve scalability issues as well that has plagued many a startup (mine included). Now let's rethink the FE of the FullStack web developer...&lt;/p&gt;

&lt;p&gt;Web Dev is divided into two lands, the Front End (FE) development, and the Back End (BE) development. The FE is the end user's device and what they see, do, and control. The BE is the server (think organization's controlled computer providing the web page.) What modern reactive frameworks have mostly done is pulled most of the load off from the BE and offload it onto the FE with tools like React. The naming of React with Reactive development is almost as amusing to me as the term Relate in correspondence to Relational Databases, but that is a tangent for a different post. While reactive websites handle asynchronous data streams and event-driven scenarios, they usually fault in the part of making the FE do all of the logic to make that happen. Let the FE do best what the FE does, and let the BE do best what the BE does. That is a novel concept, but one that we (web developers) keep trying to break and misconstrue. And why do we keep trying to break this concept, because we are attempting to solve problems that we created. The fads say to go "server-less" for scalability, but is that really the best approach? Maybe for static web content, but why attempt to completely absolve something that isn't the answer to every problem. And by using this solution, we simply create a world of others.&lt;/p&gt;

&lt;p&gt;If you are a Web Dev, or anyone still reading this post: first, thank you; secondly, we probably disagree on many technical things and that is ok, but more importantly; thirdly, can I challenge you to rethink how you develop for the web? Why do you use the web stack you are using? How long can your project stand without being touched and it still solve the problem. Will the problem you are solving be a long-lasting problem (what might it look like in 100 years)? What would you do if you had to drastically simplify your project to just the bare necessities to solve the problem?&lt;/p&gt;

&lt;p&gt;More thoughts later, but it is getting late for tonight/this morning.&lt;/p&gt;

&lt;p&gt;[graphic from churchcanvas.ai which I HIGHLY recommend!]&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Since When Did APIs Become Databases?</title>
      <dc:creator>Anthony Master</dc:creator>
      <pubDate>Tue, 16 Jan 2024 05:15:00 +0000</pubDate>
      <link>https://dev.to/amaster507_59/since-when-did-apis-become-databases-37j5</link>
      <guid>https://dev.to/amaster507_59/since-when-did-apis-become-databases-37j5</guid>
      <description>&lt;p&gt;While researching a database to use in a project, the team I am working with came upon yet another graph database. Every time I turn around there is a new graph/NoSQL database. How can anyone possibly keep up with these is beyond me, but I try. (Insert shameless plug for my GraphDev Discord server).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Maybe we should make our own database, lol.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Interestingly while theorizing testing and implementation to even begin comparing performance, we decided that we might take an un-traditional approach and fork the open source database written over yet another triple-store, and insert our business logic directly into the database. This was after I jokingly said that maybe we should make our own database.&lt;/p&gt;

&lt;p&gt;But we don't want to make a database, we only need an API layer for our application. We already have an API being used in production. We just need to replace the database this API is using to store our data.&lt;/p&gt;

&lt;p&gt;So, we went back to discussing how this new database handles API connection and end-user authentication. The API needs a connection to the database to be able to authenticate users, but an authenticated user needs to be able to use an individual connection through the API to the database. But why? One of the deciding factors in using this database is its advanced auditing which is directly attached to the client. We don't need to just audit at our API database connection level but at the end-user/client level.&lt;/p&gt;

&lt;p&gt;So what if we instead send additional context through our API of the end-user/client making the mutation and query audit trails based upon this additional information? That might work, but would require again forking the database to change how the audit function runs. If we are then going to fork the database already, then why not just move the other logic from our API into the database too? But would that mean we have built (or forked and extended) a database and no longer have an API?&lt;/p&gt;

&lt;p&gt;What is it exactly that distinguishes databases from APIs? According to ChatGPT:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The term "database" generally refers to a structured collection of data that is organized and can be easily accessed, managed, and updated. Qualifications for a project to be termed a database often include the ability to store, retrieve, and manipulate data in a systematic way.&lt;/p&gt;

&lt;p&gt;If your project uses a datastore underneath and meets the criteria of a structured collection of data with organized access and management capabilities, you can likely refer to it as a database. However, it's important to consider specific features and functionalities associated with traditional databases, such as support for querying, indexing, transaction management, and data integrity.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Wait, is our API already classified as a database? Our API contains a structured collection of data with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Organized access and&lt;/li&gt;
&lt;li&gt;✅ Management Capabilities.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our API also has support on some levels for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Querying,&lt;/li&gt;
&lt;li&gt;✅ Indexing,&lt;/li&gt;
&lt;li&gt;✅ Transaction Management, and&lt;/li&gt;
&lt;li&gt;✅ Data Integrity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, as any intelligent person would do, I asked ChatGPT for help again, "Can an API layer be called a database?"&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No, an API layer typically cannot be called a database. An API (Application Programming Interface) is a set of rules and protocols that allows different software applications to communicate with each other. It facilitates the exchange of data and functionality between different systems.&lt;/p&gt;

&lt;p&gt;On the other hand, a database is a structured collection of data that is organized for easy retrieval, update, and management. It provides a mechanism for storing, querying, and manipulating data. While an API can be used to interact with a database, the API itself is not a database.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Umm, so then if this is correct, an API is only a set of rules and protocols to communicate between the layers. Some of these rules entail layer 7 authorization presumably. Reading into this a little deeper, the API exchanges data, while the database stores, queries, and manipulates the data. Ok, then by what right, is the database we are using hold its claim that it &lt;strong&gt;is&lt;/strong&gt; a "database"? The same could be said of most of the "databases" released over the last decade.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The API exchanges data, while the database stores, queries, and manipulates the data.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This was enough circular reasoning to hurt my brain, so after I finished working for the evening and signed off, I checked LinkedIn and for sure they overheard our conversation because there it was again...&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://www.linkedin.com/feed/update/urn:li:activity:7152707393741615104?updateEntityUrn=urn%3Ali%3Afs_updateV2%3A%28urn%3Ali%3Aactivity%3A7152707393741615104%2CFEED_DETAIL%2CEMPTY%2CDEFAULT%2Cfalse%29&amp;amp;lipi=urn%3Ali%3Apage%3Ad_flagship3_profile_view_base%3BvHG84OkUTdGrFN2ASX5NdA%3D%3D"&gt;...FHIR servers can act like "databases", even though they are not... While normal databases had tools like Database Visualizers, FHIR had nothing but Postman. So Darren built the Vanya FHIR utility... Are FHIR servers acting more and more like databases? Is there a need to build tooling similar to what we have with SQL databases, but for the FHIR API?&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So I must ask, and hence the reason for this short article,&lt;/p&gt;

&lt;h1&gt;
  
  
  When did APIs become databases?
&lt;/h1&gt;

&lt;p&gt;Some added context on what is FHIR: for my day job, I am the Interface Specialist for a Hospital. Interoperability in a Hospital setting is connecting independent systems with application programming interfaces (APIs). The most widely adopted interfacing format is HL7 version 2 the precursor to FHIR, aka HL7 version 4. For a very brief explanation besides the change in message formats, version 2 is 80's technology with TCP event emitters while v4 is trying to bring healthcare to the somewhat closer present with RESTful APIs and even a proposal for a GraphQL API. This is shaking up healthcare interoperability by providing means to query health data when you need it from remote systems instead of filtering, storing, and aggregating data received that may never be needed. And already before it is even widely implemented, there is this conversation comparing an FHIR API to that of an FHIR "database". 🤦‍♂️&lt;/p&gt;

</description>
      <category>database</category>
      <category>api</category>
      <category>dataengineering</category>
    </item>
    <item>
      <title>How to Apply SOLID with Testing JS/TS Class Methods</title>
      <dc:creator>Anthony Master</dc:creator>
      <pubDate>Sat, 13 Jan 2024 07:55:08 +0000</pubDate>
      <link>https://dev.to/amaster507_59/how-to-apply-solid-with-testing-jsts-class-methods-5f4k</link>
      <guid>https://dev.to/amaster507_59/how-to-apply-solid-with-testing-jsts-class-methods-5f4k</guid>
      <description>&lt;p&gt;Are your class test files growing out of control? Are you struggling with writing tests for class methods because there are too many variables to control? I was in the same situation recently and found a way out using &lt;a href="https://stackoverflow.blog/2021/11/01/why-solid-principles-are-still-the-foundation-for-modern-software-architecture/"&gt;SOLID&lt;/a&gt; principles.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyClass&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;IMyClass&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;multiInject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;IDENTIFIERS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FOO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nx"&gt;foos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IFoo&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;IDENTIFIERS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BAR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nx"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IBar&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="nx"&gt;someMethod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Baz&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;baz&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Baz&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;foos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;baz&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;baz&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;baz&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;baz&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Take a class for which we are tasked to write a unit test. This class may have a dozen methods and a dozen more attributes. In my environment we were already using &lt;a href="https://inversify.io/"&gt;inversify&lt;/a&gt; to dependency inject into this class, and using container snapshot and restore as setup and teardown operators, in our jest test file. But it began getting out of control even after refactoring into test cases and test runners.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;
&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bind&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IBar&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;IDENTIFIERS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BAR&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;BarMock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bind&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IMyClass&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;IDENTIFIER&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MY_CLASS&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nf"&gt;afterEach&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;restore&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;someMethodTests&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IFoo&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Baz&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;
&lt;span class="p"&gt;}[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;without foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
    &lt;span class="na"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MyClass&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;someMethod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;someMethodTests&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$description returns: $expected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;foos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expected&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;foos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;IDENTIFIERS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FOO&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;IDENTIFIER&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MY_CLASS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;someMethod&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Our unit test files became more complex than the actual classes we were testing. The comment was even made that we need tests for our test files. As funny as that was, it was partially correct because of the complexity of the unit test files.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;we need tests for our test files&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While researching to find a better method to jest test JavaScript classes, I came upon &lt;a href="https://dev.to/dstrekelj/how-to-test-classes-with-jest-jif"&gt;How to test classes with jest&lt;/a&gt; which provided insight into using spies with &lt;code&gt;jest.spyOn&lt;/code&gt; methods. While this did provide a little bit of help, it just added again even more complexity, and as we were already using Inversify dependency injection spies offered little to no help.&lt;/p&gt;

&lt;p&gt;While learning from Uncle Bob's design principles, I feel like I have strengthened myself in writing quality function tests. I wasn't however applying the SOLID principle one layer deeper into our class methods. What would it look like if we:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;S&lt;/strong&gt;ingled the responsibility of the method into an external function?&lt;/li&gt;
&lt;li&gt;Converted methods into &lt;strong&gt;O&lt;/strong&gt;pen-closed functions?&lt;/li&gt;
&lt;li&gt;Made it possible to later &lt;strong&gt;L&lt;/strong&gt;iskov substitute class methods?&lt;/li&gt;
&lt;li&gt;Applied &lt;strong&gt;I&lt;/strong&gt;nterface segregation?&lt;/li&gt;
&lt;li&gt;And took another step in &lt;strong&gt;D&lt;/strong&gt;ependency inversion?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I took a step back and looked at another project I had been working on that also used classes and jest. I had written a parsing method that became so convoluted I had little choice but to separate it into an external function. My unit tests then covered this function separately from the rest of the class. That was it! I could separate class methods into external functions and thereby easily do unit testing on the external functions irrelevant to the class as a whole.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// types.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;SomeMethod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;foos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IFoo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Baz&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// someMethod.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SomeMethod&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./types&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;someMethod&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SomeMethod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;foos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;baz&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Baz&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;foos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;baz&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;baz&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;baz&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;baz&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// MyClass.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SomeMethod&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./types&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;someMethod&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./someMethod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyClass&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;IMyClass&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;multiInject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;IDENTIFIERS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FOO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nx"&gt;foos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IFoo&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;IDENTIFIERS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BAR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nx"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IBar&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="nl"&gt;someMethod&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;SomeMethod&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;someMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;foos&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The unit tests for the method then become much easier to write as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// someMethod.spec.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;someMethod&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./someMethod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;someMethodTests&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IFoo&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Baz&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;
&lt;span class="p"&gt;}[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;without foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
    &lt;span class="na"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;someMethod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;someMethodTests&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$description returns: $expected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;foos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expected&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;someMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;foos&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;We end up with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A unit test that has the &lt;strong&gt;S&lt;/strong&gt;ingle responsibility of testing a single function.&lt;/li&gt;
&lt;li&gt;A class that is still &lt;strong&gt;O&lt;/strong&gt;pen for extension, while the function is &lt;em&gt;closed&lt;/em&gt; for modification.&lt;/li&gt;
&lt;li&gt;A function that can follow the &lt;strong&gt;L&lt;/strong&gt;iskov substitution principle by using an argument referencing the property of the class without knowing the class itself.&lt;/li&gt;
&lt;li&gt;Another implementation of the class does not have to use the same function if not needed, and can still make their implementation of the &lt;strong&gt;I&lt;/strong&gt;nterface.&lt;/li&gt;
&lt;li&gt;Also the class is &lt;strong&gt;D&lt;/strong&gt;ependent upon the type of the function and &lt;em&gt;not&lt;/em&gt; the inline function itself. This allows for easier replacements when a better function may be found later that follows the same type or similar abstraction of such.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I would love to hear your feedback on this SOLID principle application and learn how you might better jest test classes in your JavaScript/TypeScript application. (If you have feedback on my horrible example code, yes I know... I wrote almost all of it without the help of an IDE to cross-check/correct my work).&lt;/p&gt;

</description>
      <category>jest</category>
      <category>testing</category>
      <category>solidprinciples</category>
      <category>typescript</category>
    </item>
    <item>
      <title>What is HL7</title>
      <dc:creator>Anthony Master</dc:creator>
      <pubDate>Sun, 21 May 2023 02:30:39 +0000</pubDate>
      <link>https://dev.to/amaster507_59/what-is-hl7-4c9f</link>
      <guid>https://dev.to/amaster507_59/what-is-hl7-4c9f</guid>
      <description>&lt;p&gt;I posted recently on LinkedIn starting a topic on how to enable integration in your healthcare application using HL7 and becoming an HL7 interoperability expert. The basis of using HL7 is first understanding exactly what HL7 is and how it works. By the end of this post, you will be able to look at an HL7 v2 message and be able to parse it without any fancy encoding tools.&lt;/p&gt;

&lt;p&gt;If you are interested in my referenced LinkedIn post, you can find it here:&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://www.linkedin.com/embed/feed/update/urn:li:share:7065693622960095232" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--JPv3GsrI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://static.licdn.com/aero-v1/sc/h/c45fy346jw096z9pbphyyhdz7" height="457" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://www.linkedin.com/embed/feed/update/urn:li:share:7065693622960095232" rel="noopener noreferrer" class="c-link"&gt;
          Anthony Master on LinkedIn: So you have an healthcare application, and are trying to integrate with…
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          So you have an healthcare application, and are trying to integrate with healthcare facility data. You could request data extract files and reports from the…
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--aGQ1YUtN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://static.licdn.com/aero-v1/sc/h/al2o9zrvru7aqj8e1x2rzsrca" width="64" height="64"&gt;
        linkedin.com
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Most explanations of HL7 start with the big picture and then dive into the smaller pieces. I like to work backward when I explain new technologies. This is the same way I put puzzles together. I will study a small piece individually to figure out where it goes in the bigger picture.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you can understand the smallest pieces, then you will be able to compile them into the big picture.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;HL7 v.2 is comprised of 5 concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Subcomponents&lt;/li&gt;
&lt;li&gt;Components&lt;/li&gt;
&lt;li&gt;Fields&lt;/li&gt;
&lt;li&gt;Segments&lt;/li&gt;
&lt;li&gt;Repetitions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By the way, if you want to read the official standards, you can find them at: &lt;a href="https://www.hl7.org/implement/standards/product_brief.cfm?product_id=185"&gt;www.hl7.org&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each of these concepts is associated with an encoding character. You can override these encoding characters, but for now, we'll keep with the defaults.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Subcomponents are separated by the ampersand symbol &lt;code&gt;&amp;amp;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Components are separated by the caret symbol &lt;code&gt;^&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Fields are separated by the pipe symbol &lt;code&gt;|&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Segments are separated by the return sequence &lt;code&gt;\r&lt;/code&gt; seen in most text editors as a line break&lt;/li&gt;
&lt;li&gt;Repeating Fields are separated by the tilde symbol &lt;code&gt;~&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Subcomponents
&lt;/h2&gt;

&lt;p&gt;The subcomponent is the smallest data concept of an HL7 message and in its most basic format is simply a string. An example might be something like &lt;code&gt;Oklahoma&lt;/code&gt;. There is nothing in HL7 that signifies the difference of a subcomponent out of context as anything other than a string. The location of the subcomponent within the message is what assigns it a more specific data type. For example, given the subcomponent value of &lt;code&gt;20230527&lt;/code&gt;, we have no idea by itself what it is other than a string. We might want to assume it is a date, but without knowing its position in the message, it can only be known to be a string. If we assume it was a date, we might later be proven incorrect when it was a unit of measurement. Later in this post, we will discuss how to identify data types given the position, or path, to the data.&lt;/p&gt;

&lt;p&gt;Given the default subcomponent separator, we can join multiple subcomponents together which might look like &lt;code&gt;OK&amp;amp;Oklahoma&lt;/code&gt;. Indexing in HL7 usually uses a 1-based index. This means that the first item in the separated list of items is assigned the path &lt;code&gt;1&lt;/code&gt;, the second item &lt;code&gt;2&lt;/code&gt;, etc. So given this list of subcomponents &lt;code&gt;OK&amp;amp;Oklahoma&lt;/code&gt; we can separate them as the list:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;OK&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Oklahoma&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We might assume that this is a list of a US state abbreviation in position &lt;code&gt;1&lt;/code&gt;, and a state name in position &lt;code&gt;2&lt;/code&gt;, but we don't know at this point exactly what this data represents.&lt;/p&gt;

&lt;h2&gt;
  
  
  Components
&lt;/h2&gt;

&lt;p&gt;Components are simply defined as groups of subcomponents. You have already seen two subcomponents, without really knowing it. &lt;code&gt;20230527&lt;/code&gt; and &lt;code&gt;OK^Oklahoma&lt;/code&gt; are both components. The first one, is only a single subcomponent, while the second one is a list of two subcomponents.&lt;/p&gt;

&lt;p&gt;With the default component separator of the caret (&lt;code&gt;^&lt;/code&gt;), we can start to join together subcomponent groups into lists of components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;T123456789^^^OK^DL^^20230527^20280531^OK&amp;amp;Oklohoma^DMV
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Components follow similar indexing patterns as subcomponents using a 1-based index scale. We can represent this list of components above into the following structure:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;T123456789&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OK&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DL&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;20230527&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;20280531&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;OK&amp;amp;Oklohoma&lt;/code&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;OK&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Oklahoma&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DMV&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Notice how positions &lt;code&gt;2&lt;/code&gt;, &lt;code&gt;3&lt;/code&gt;, and &lt;code&gt;6&lt;/code&gt; are empty. With just being empty, we cannot be confident whether the values were empty, or if the message sender just didn't include values in those positions. To signify that the value is indeed empty and not just &lt;em&gt;not included&lt;/em&gt;, the syntax is to use an empty quoted string (&lt;code&gt;""&lt;/code&gt;), which could look something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...^""^^...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this, we know that position two was included and that it was indeed an empty value.&lt;/p&gt;

&lt;p&gt;Let's start putting together paths for the component in the ordered list above. We can combine a component and subcomponent path with either a dash (&lt;code&gt;-&lt;/code&gt;) or a period (&lt;code&gt;.&lt;/code&gt;) like &lt;code&gt;9-2&lt;/code&gt; or &lt;code&gt;9.2&lt;/code&gt;. So &lt;code&gt;9.2&lt;/code&gt; equals the data &lt;code&gt;Oklahoma&lt;/code&gt;. And the data &lt;code&gt;OK&lt;/code&gt; is found in two paths, &lt;code&gt;9.1&lt;/code&gt; and &lt;code&gt;4&lt;/code&gt;. When a component only has a single subcomponent, then it is common practice to leave off the subcomponent path. In our example though, both &lt;code&gt;4.1&lt;/code&gt; and &lt;code&gt;4&lt;/code&gt; would reference the same value &lt;code&gt;OK&lt;/code&gt;. We can also reference things that don't exist in our component such as &lt;code&gt;9.3&lt;/code&gt; or &lt;code&gt;12&lt;/code&gt;. If something is referenced but does not exist in the component, then depending upon the handling of your environment, it may be returned as either &lt;code&gt;null&lt;/code&gt;, &lt;code&gt;undefined&lt;/code&gt;, an empty string (&lt;code&gt;""&lt;/code&gt;), or even a reference error.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: You will find other resources mix and match these separators of a dash &lt;code&gt;-&lt;/code&gt; and a period &lt;code&gt;.&lt;/code&gt; interchangeably. It is my practice to use a period &lt;code&gt;.&lt;/code&gt; when writing the path between components and subcomponents.&lt;/p&gt;

&lt;h1&gt;
  
  
  Fields
&lt;/h1&gt;

&lt;p&gt;You might have already come to the logical conclusion, that a field, is the combination of multiple component groups, and if so, then you are correct. So to say it similarly again, you have already seen a field, even though you didn't know it. The component list above forms a field.&lt;/p&gt;

&lt;p&gt;Knowing from above that the field separating character is the pipe symbol (&lt;code&gt;|&lt;/code&gt;), you might have already figured out what a field set would look like. But to make it clear, here is an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;STF|amaster507^^L|T123456789^^^OK^DL^^20230527^20280531^OK&amp;amp;Oklohoma^DMV|
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let me throw a curveball at you, this example, is a list of 3 fields. You might be wondering why that is a curveball. And that is for a few reasons. First of all, when a list of items ends with a separator, it is declaring an additional item in the list. Sort of like how some programming languages for an array, set, or map. If an array was presented as &lt;code&gt;[1, 2, 3, ]&lt;/code&gt; we would say that there are 4 elements in the array, the 4th element was undefined. Because the comma was given, we knew that there was something else there, even though it was not defined. Seeing then that this list of fields ends with the field separator &lt;code&gt;|&lt;/code&gt;, you might think that this list has 4 fields. But that is not correct either, because a list of fields together form the next higher concept of a segment, and Segments can be considered 0-based indexed. See Segments below for additional explanation. For now, just know that if we reference field &lt;code&gt;2&lt;/code&gt;, component &lt;code&gt;9&lt;/code&gt;, and subcomponent &lt;code&gt;2&lt;/code&gt;, such as &lt;code&gt;2.9.2&lt;/code&gt; then we would have the value &lt;code&gt;Oklahoma&lt;/code&gt;. This is because the 2nd field starts with the value &lt;code&gt;T123...&lt;/code&gt;. If we put together a list of this data so far, we get:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;amaster507^^L&lt;/code&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;amaster507&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;L&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;T123456789^^^OK^DL^^20230527^20280531^OK&amp;amp;Oklohoma^DMV&lt;/code&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;T123456789&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OK&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DL&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;20230527&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;20280531&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OK&amp;amp;Oklohoma&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OK&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Oklahoma&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DMV&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Segments
&lt;/h2&gt;

&lt;p&gt;A Segment is a named list of fields. We hinted earlier that a segment can be considered 0-based indexed meaning that the first element's index path is &lt;code&gt;0&lt;/code&gt;, which we said we would explain later, so here we are now. While you cannot usually reference field &lt;code&gt;0&lt;/code&gt; in a segment, you do reference a segment by name directly. Given our field example, which we will show again below, you can see that this segment has the name &lt;code&gt;STF&lt;/code&gt;. The name of a segment &lt;em&gt;must be&lt;/em&gt; 3 uppercase alphanumeric characters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;STF|amaster507^^L|T123456789^^^OK^DL^^20230527^20280531^OK&amp;amp;Oklohoma^DMV|
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Building upon our path to data, we can put together the segment name &lt;code&gt;STF&lt;/code&gt; combined with our field-component-subcomponent path &lt;code&gt;2.9.2&lt;/code&gt; and get &lt;code&gt;STF-2.9.2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: Again, just like with path joins between fields, components, and subcomponents, the separator can be either a dash (&lt;code&gt;-&lt;/code&gt;) or a period (&lt;code&gt;.&lt;/code&gt;). I find it common practice to use a dash after the segment name, and then a period for the other path separators.&lt;/p&gt;

&lt;p&gt;The name of the segment begins to give us context to the data we have. With just a single segment, and assuming a few things such as the message version, and default encoding characters, we can derive data types.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: Because no one is expected to remember everything, I still use a reference to look up data types often. My go-to reference of choice is &lt;a href="https://hl7-definition.caristix.com/v2/"&gt;Caristix.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If we look up the segment &lt;code&gt;STF&lt;/code&gt; we will get the "Staff Identification" from the "Personnel Management" from chapter 15 of the HL7 v2.5 standard. We furthermore can see that field &lt;code&gt;2&lt;/code&gt; is the "Staff Identifier List" conforming to data type "CX". If we continue to look up the datatype &lt;code&gt;CX&lt;/code&gt; (aka "Extended Composite ID with Check Digit") we will find position &lt;code&gt;9&lt;/code&gt; to be the "Assigning Jurisdiction" conforming to datatype &lt;code&gt;CWE&lt;/code&gt;. I know it seems tedious, but keep going down the trail, and you will find that data type &lt;code&gt;CWE&lt;/code&gt; (aka "Coded with Exceptions") 2nd position is the "Text" and conforms to just the &lt;code&gt;ST&lt;/code&gt; (aka "String") data type. So this means that &lt;code&gt;STF-2.9.2&lt;/code&gt; is the &lt;strong&gt;Staff Identification&lt;/strong&gt; &amp;gt; &lt;strong&gt;Staff Identifier List&lt;/strong&gt; &amp;gt; &lt;strong&gt;Assigning Jurisdiction&lt;/strong&gt; &amp;gt; &lt;strong&gt;Text&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You might think that doesn't make much sense, but let's decode one more path, &lt;code&gt;STF-2.5&lt;/code&gt;. This will lead you to table &lt;a href="https://hl7-definition.caristix.com/v2/HL7v2.5/Tables/0203"&gt;0203&lt;/a&gt; which tells you the value &lt;code&gt;DL&lt;/code&gt; maps to the &lt;strong&gt;Driver's License Number&lt;/strong&gt;. Now for security's sake, I would not post my actual driver's license number, but as you now can put together, my driver's license was assigned under the jurisdiction of Oklahoma.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IMPORTANT&lt;/strong&gt;: Since Segment names must be 3 characters followed by a field separating character, it can be determined that field &lt;code&gt;1&lt;/code&gt; of a segment begins with the 5th character. However, there is &lt;strong&gt;one exception to the rule&lt;/strong&gt;! The &lt;code&gt;MSH&lt;/code&gt; (aka "Message Header") segment defines the encoding characters with fields &lt;code&gt;MSH-1&lt;/code&gt; and &lt;code&gt;MSH-2&lt;/code&gt;. &lt;strong&gt;And &lt;code&gt;MSH-1&lt;/code&gt; (aka "Field Separator") is the literal first field separator found at &lt;em&gt;character&lt;/em&gt; 4 of the &lt;code&gt;MSH&lt;/code&gt; segment&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: As you peruse HL7 dictionary resource specifications, you will find a thing called "OPTIONALITY". Some fields are always &lt;strong&gt;&lt;u&gt;R&lt;/u&gt;&lt;/strong&gt;equired, but many others are &lt;strong&gt;&lt;u&gt;O&lt;/u&gt;&lt;/strong&gt;ptional. When you start using HL7 with vendors, you will find vendor specifications. These specifications usually can override the standard specification in terms of what they require and allow it to be optional. This can help alleviate situations with seemingly overlapping data. For instance, &lt;code&gt;STF-2.4 and STF-2.9&lt;/code&gt; might be overlapping data depending on the exact use case specifics, and one or even both of these fields might be completely omitted if the vendor does not find it necessary data to send and/or receive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Repetitions
&lt;/h2&gt;

&lt;p&gt;In HL7 v2.x, fields and segments can repeat depending upon the allowable datatype. In Caristix, the repeatability of fields are denoted with &lt;code&gt;-&lt;/code&gt; meaning no repeats allowed, a number indicating how many repetitions are allowed, or the infinity symbol &lt;code&gt;∞&lt;/code&gt; indicating unlimited repetitions are permitted. Segments are repeated without any special repeating indicators. For example, the &lt;code&gt;NK1&lt;/code&gt; (Next of Kin/Associated Parties) segment, can usually depending upon the vendor, allow for repeating segments. This could be exemplified to show both my wife and my mother:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NK1|1|Master^Amanda|SPO
NK1|2|Master^^^^Mrs|MTH
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depending upon your environment and configuration, you may now get an error when trying to reference my "Next of Kin"s family name with &lt;code&gt;NK1-2.1&lt;/code&gt;. This would be because there is ambiguity as to which &lt;code&gt;NK1&lt;/code&gt; segment you are requesting. To clear this up, you would add an iterator index to the repeating segment's name. The syntax and indexing base vary by your environment, but it is commonly 1-based indexed and syntax with the iteration surrounded by brackets. So to reference my first next of kin's relationship, we would use &lt;code&gt;STF[1]-3&lt;/code&gt; which finds us &lt;code&gt;SPO&lt;/code&gt; (aka "Spouse").&lt;/p&gt;

&lt;p&gt;Field repetitions take a slightly different form. When a field repeats, each iteration is separated with the field separating encoding character (&lt;code&gt;MSH.2&lt;/code&gt; 2nd character) which is by default the tilde (&lt;code&gt;~&lt;/code&gt;). Let's show an example and then explain it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;STF|amaster507|T123456789|MASTER^ANTHONY^LEE^^^^L^A~^TONY^^^^^N~MASTER^ANTHONY^^^BRO^BATh^REL|C^CANDIDATE|M
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looking at &lt;code&gt;STF-3&lt;/code&gt; (aka "Staff Name") you will see a repetition character followed by another field, and then once again. This shows that there are three names given for this person. Looking a little deeper at &lt;code&gt;STF-3[*].7&lt;/code&gt; you will find the values &lt;code&gt;L&lt;/code&gt;, &lt;code&gt;N&lt;/code&gt;, and &lt;code&gt;REL&lt;/code&gt;. Using Table "0200" with version v2.7, you can map these to the &lt;code&gt;Official Registry Name&lt;/code&gt;, &lt;code&gt;Nickname&lt;/code&gt;, and &lt;code&gt;Religous&lt;/code&gt; name types. You were also just introduced to a new syntax, the field follows by brackets (&lt;code&gt;[]&lt;/code&gt;) wrapping an iteration index. From my experience, field iterations are always 1-based indexed. If we know that the second name is the nickname, then we can extract my nickname with &lt;code&gt;STF-3[2].2&lt;/code&gt; which would be &lt;code&gt;TONY&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: Most of the time, repeating fields are not typed in the same order. Meaning that given two separate messages with different staff, one could have an &lt;code&gt;STF-3[2]&lt;/code&gt; referencing a nickname, while another is either missing that iteration altogether or it is a completely different name type such as maiden name. It is important then to check for contextual indicators such as the &lt;code&gt;STF-3[*].7&lt;/code&gt; to ensure the correct field is being referenced.&lt;/p&gt;

&lt;h2&gt;
  
  
  Messages
&lt;/h2&gt;

&lt;p&gt;An HL7 message is the composition of one or more segments. The first segment in a message will be the &lt;code&gt;MSH&lt;/code&gt; (ak "Message Header") segment.&lt;/p&gt;

&lt;p&gt;This wraps up the main concepts of the syntax of an HL7 v2.x message. Before wrapping up this article though, I want to briefly cover three more important factoids and a fourth for your own, personal research:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Escaping Encoding Characters&lt;/li&gt;
&lt;li&gt;Message Trigger Events&lt;/li&gt;
&lt;li&gt;Message Versions&lt;/li&gt;
&lt;li&gt;Message Batching—Handling a batch of HL7 messages in a single stream or file.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Escaping Encoding Characters.
&lt;/h2&gt;

&lt;p&gt;You might be wondering, what if one of the special encoding characters is used inside of a textual data element? For instance if "Little Bobby Tables" shows up in your message?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yqLVYt8G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imgs.xkcd.com/comics/exploits_of_a_mom.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yqLVYt8G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imgs.xkcd.com/comics/exploits_of_a_mom.png" alt="xkcd—Exploits of a Mom" width="666" height="205"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To cover these scenarios, there is another encoding character called the "Escape Character". The default escape character is the backslash (&lt;code&gt;\&lt;/code&gt;) which can undoubtedly be cumbersome to work with in some editors and environments. This encoding character can be customized using the &lt;code&gt;MSH-2&lt;/code&gt; field's 3rd character. With this escape character, you can now safely include "Little Bobby Tables" and all other correctly escaped free text input into your messages as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Message Trigger Events
&lt;/h2&gt;

&lt;p&gt;Without getting into all of the specifics and differences between HL7 v2.x and FHIR (v4), I will at least introduce the idea that v2 varies from FHIR in that v2 uses the concept of a messaging event system whereas FHIR uses the equivalence of a RESTful API. If you are not familiar with the terms "messaging event system" and "RESTful API", I highly encourage some additional research into those terms.&lt;/p&gt;

&lt;p&gt;In HL7 2.x it is common for "Interfaces" to contain similarly typed messages. A common interface is the ADT interface that transmits and/or receives messages concerning &lt;strong&gt;&lt;u&gt;A&lt;/u&gt;&lt;/strong&gt;dmits, &lt;strong&gt;&lt;u&gt;D&lt;/u&gt;&lt;/strong&gt;ischarges, and &lt;strong&gt;&lt;u&gt;T&lt;/u&gt;&lt;/strong&gt;ransfers of patients within a healthcare organization. Each message indicates its code in field &lt;code&gt;MSH-9.1&lt;/code&gt;. And then another layer into these coded interface types are the trigger events. A trigger event describes what event happened that triggered the message to send. For a quick example, here are just 4 of the many &lt;code&gt;ADT&lt;/code&gt; trigger events:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;A01&lt;/code&gt;: Admit/visit notification&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;A02&lt;/code&gt;: Transfer a patient&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;A03&lt;/code&gt;: Discharge/end visit&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;A08&lt;/code&gt;: Update patient information&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Message Versions
&lt;/h2&gt;

&lt;p&gt;The message version can be found for each message in the &lt;code&gt;MSH-12&lt;/code&gt; field. Depending upon this message version, data types, optionality, repeatability, tables, and dictionaries will vary. It is common practice to conform an interface to a specific message version. Some vendors may mix versions depending upon supported specifications within each version. Consult your vendor's HL7 specification guides for more details regarding which versions are supported within which interfaces/events.&lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;Thank you for taking the time for me to explain to you the main concepts and fundamentals of understanding HL7 v2.x messages. You should now be able to put your skills to use. I'd love to hear your feedback and continue the discussions.&lt;/p&gt;

</description>
      <category>healthcare</category>
      <category>interoperability</category>
      <category>interfacing</category>
    </item>
  </channel>
</rss>
