<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Api-Design on Soldier's 5</title><link>https://4lex.nz/tags/api-design/</link><description>Recent content in Api-Design on Soldier's 5</description><image><title>Soldier's 5</title><url>https://4lex.nz/img/404-bg.jpg</url><link>https://4lex.nz/img/404-bg.jpg</link></image><generator>Hugo</generator><language>en-us</language><lastBuildDate>Mon, 13 Oct 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://4lex.nz/tags/api-design/index.xml" rel="self" type="application/rss+xml"/><item><title>The Helpful Web - How AI will bring the next evolution of accessibility</title><link>https://4lex.nz/posts/the-helpful-web/</link><pubDate>Mon, 13 Oct 2025 00:00:00 +0000</pubDate><guid>https://4lex.nz/posts/the-helpful-web/</guid><description>&lt;p&gt;Better buttons, cleaner HTML markup, stricter adherence to WCAG - we&amp;rsquo;ve been investing in digital accessibility for over twenty years, and that investment has opened doors for millions of people worldwide.&lt;/p&gt;
&lt;p&gt;We are nearing a plateau. I believe that the next order-of-magnitude gain in accessibility won&amp;rsquo;t come from ever-tighter contrast ratios or perfection in semantic HTML.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ve reached the point of diminishing returns. We might build current best practice levels of accessibility faster and more effectively with better technology. Still, we are bound in our current approach to accessibility by the interfaces we ship. The next leap in accessibility cannot come from better execution of traditional interfaces; it can only come from changing the interface. Changing the interfaces means making them adaptive. Making them personal and responsive in ways that statically designed software can never achieve.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Better buttons, cleaner HTML markup, stricter adherence to WCAG - we&rsquo;ve been investing in digital accessibility for over twenty years, and that investment has opened doors for millions of people worldwide.</p>
<p>We are nearing a plateau. I believe that the next order-of-magnitude gain in accessibility won&rsquo;t come from ever-tighter contrast ratios or perfection in semantic HTML.</p>
<p>We&rsquo;ve reached the point of diminishing returns. We might build current best practice levels of accessibility faster and more effectively with better technology. Still, we are bound in our current approach to accessibility by the interfaces we ship. The next leap in accessibility cannot come from better execution of traditional interfaces; it can only come from changing the interface. Changing the interfaces means making them adaptive. Making them personal and responsive in ways that statically designed software can never achieve.</p>
<p>That change will come from agents. Agents are the next step in digital accessibility.</p>
<p>By agents, I mean allies that help you and increasingly act on your behalf. These agents will translate, reshape and personalise every interface an individual might need. In some cases, that agent will be your personal agent; in others, it will be an agent provided for you to use by the company you&rsquo;re interacting with. Either way, these agents will be accountable for ensuring that the things you need to interact with, screens, video, forms and more, will be exquisitely tailored for your unique needs.</p>
<p>At one end of the spectrum, that might mean synthesising the information you&rsquo;re reading with relevant insights from elsewhere on the internet.</p>
<p>On the other hand, it might mean actively interpreting for you, turning information that was previously inaccessible into something you can use instantly.</p>
<p>Imagine a world where anyone with macular degeneration can fill in their Lotus Notes timesheets!</p>
<p>Or where your personal agent spends a day learning your unique colour perception profile, then shares it with Netflix&rsquo;s agent, which re-colours every show you watch to give you the most vivid picture possible.</p>
<p>If agents can reshape interfaces in real time, they don&rsquo;t just make things easier; they change the rules of interface development. The most significant rule they will break is the tradeoff between usability and accessibility.</p>
<h2 id="dissolving-the-accessibility-usability-dilemma">Dissolving the accessibility-usability dilemma</h2>
<p>For years, we have wrestled with a false choice: make a product fully accessible and risk adding friction, or make it frictionless and knowingly exclude users. Agents dissolve that tradeoff. They will adapt to interfaces and needs in real time.</p>
<p>With the right tech and design, agents can deliver rigorous accessibility AND effortless usability simultaneously. The same agent that makes Lotus Notes usable for a user with macular degeneration can also streamline the workflow for a power user by skipping the UI and hitting APIs directly - without forcing either of those users to compromise.</p>
<p>To make agents truly helpful, we need to give them the same usage cues we give humans today, but in a form that agents can read and act on. In design, we call these cues &lsquo;affordances&rsquo;.</p>
<h2 id="what-are-affordances">What are affordances?</h2>
<p>Affordances are the characteristics or properties of an object that suggest how we can use it. They show a user that an object can be interacted with.</p>
<p>As such, an affordance is not a &ldquo;property&rdquo; of an object (like a physical object or a User Interface). Instead, an affordance is defined in the relation between the user and the object: A door affords opening if you can reach the handle. For a toddler, the door does not afford opening if she cannot reach the handle.</p>
<p>An affordance is, in essence, an action possibility in the relation between user and an object.</p>
<p>When your software&rsquo;s user is an agent, the affordances you build must be designed for machine interpretation and action, not just human user perception.</p>
<p>Let&rsquo;s look at three areas where agent-friendly affordances unlock capabilities beyond human limits, starting with precision.</p>
<h2 id="beyond-human-precision">Beyond-Human precision</h2>
<p>Today, surgeons use machines in surgery where human hands lack the precision needed to achieve the work safely. Tomorrow, a world awaits us where NOT using a machine will be considered malpractice.</p>
<p>Imagine that conversation between two surgeons, <em>&ldquo;What!? What do you mean you didn&rsquo;t use the robot to suture that vein back together! You just aren&rsquo;t that accurate! No human can be after three hours of surgery!&rdquo;.</em></p>
<figure class="align-center ">
    <img loading="lazy" src="/img/in-post/medical_droid.webp#center"
         alt="Medical droid assisting surgeon"/> <figcaption>
            <p>Hopefully they aren&rsquo;t as aggressive looking as this one.</p>
        </figcaption>
</figure>

<p>What would the world need to look like for this to be possible?</p>
<p>We would need to have built the affordances necessary for an agent to interact with external tools and the patient. We would need safety and security guarantees, and we would need signs of confidence and doubt so that humans can review and intervene as needed.</p>
<p>In short, we would need equal affordances for the robot and for the human. We might need:</p>
<ul>
<li>Some kind of semantic data mapping of the human body that an agent could understand and apply knowledge to (Agent: &ldquo;the patient&rsquo;s blood pressure is stable, if it drops, I need to check for bleeding and respond with the appropriate tool immediately&rdquo;)</li>
<li>Tools that provide telemetry and other feedback via APIs (Agent: &ldquo;Anaesthetic is being consumed at the expected rate given patient physiology, if rates change up or down, I will pause and escalate for human review&rdquo;)</li>
<li>A state machine for agents (Agent: &ldquo;The state of the cardiopulmonary bypass machine is 12, subcomponents are in state 3, 7, 16 - I have mapped out a response plan if these states change.&rdquo;)</li>
<li>Insight into control states for humans (Human in the loop: I can see that the robot is in a planning state for the following surgical task and is anticipating three scenarios. I can see the plans for those scenarios and have pre-approved those actions only)</li>
</ul>
<p>These examples show that the affordances we need for agents are the same as those for a novice surgeon. We need clear insight into the &ldquo;headspace&rdquo; of the novice, we need the novice to understand the capabilities of the tools they have at hand as well as how they can use those tools to achieve their plan (i.e. the theory knowledge and the applied knowledge), and we need someone with experience who can provide feedback in the moment that improves the performance of the novice. None of these affordances are new; we&rsquo;re just applying them to computers that we use to apply only to humans.</p>
<p>If precision is about moment-to-moment execution, diligence is about never missing a detail, no matter how long you look or how deeply you dig.</p>
<h2 id="beyond-human-diligence">Beyond-Human diligence</h2>
<p>My team is currently building payroll software. It may be the first agentic payroll software in Oceania, if not the world. We&rsquo;re planning and actively investing in a world where we can ensure that you are paid correctly by inspecting every single pay packet you have ever received, every time we calculate your next pay packet. A world where we can review 10 years of your tax history, 10 years of superannuation contributions, and 10 years of deductions and bonuses. Every single number that has ever been associated with you and your pay, for 10 years or more.</p>
<p>Payroll is a highly complex, compliance-heavy domain. Mistakes trigger legal penalties that can run into the millions. In Australia, if a company pays an employee incorrectly, the individual payroll staff member involved in that transaction can be jailed!</p>
<p>The pressure to get it right is massive, and the longer your employee is with you, the more data you have to check and re-check every time you pay them. Many of my customers have been with us for over a decade!</p>
<p>Can you imagine a human reviewing that for ten, a hundred, a thousand, or ten thousand employees? Picture this: It&rsquo;s the end of the financial year. If you are in agriculture, this is your equivalent of moving day. If you&rsquo;re in retail, it&rsquo;s Black Friday, and it&rsquo;s flu season in healthcare.</p>
<p>You&rsquo;re the CFO. Your payroll manager walks into the room and says, &ldquo;We&rsquo;ve reviewed 100% of the payroll transactions we&rsquo;ve made for about five thousand staff employed in the last seven years against every change in tax and holiday law in that period. We found three issues and fixed them. You can sign off on the end-of-year accounts.&rdquo;</p>
<p>Previously, the payroll manager would have sampled the data with the risk of issues slipping through the cracks. In most cases today, your end-of-year accounts process is focused on the yearly period in question, and the amount of reports and data needed is enormous. Most companies (at least in New Zealand) can&rsquo;t afford to hit the depth level they would like, which is why we have auditors routinely come through and do things like Holidays Act reviews and remediation.</p>
<p>The affordances we need for this level of automated compliance audit look very different to the affordances required for surgery.</p>
<p>We need:</p>
<ul>
<li>Immutable event logs (time-ordered records that afford the agent insight into the history of the employee they are checking)</li>
<li>Semantic tagging of transactions (to convey intent and interactions around pay configuration)</li>
<li>Rules versioning (to ensure the agent understands how to reconcile changes in the legislative environment against changes in configuration)</li>
<li>Scalable Audit APIs (to simplify data access for the agent and provide interactions with other services)</li>
</ul>
<p>With this level of diligence, when the auditors come knocking, the CFO is ready and can confidently prove every decision and every cent spent.</p>
<p>Now imagine what happens when this diligence is applied globally across industries. That&rsquo;s how supercycles unlock new markets.</p>
<h2 id="beyond-human-eyesight">Beyond-Human eyesight</h2>
<p>Agents can breathe new life into software you can&rsquo;t use just as well as it can solve for software you hate using - without having to rewrite it from scratch.</p>
<figure class="align-center ">
    <img loading="lazy" src="/img/in-post/macular_degen.jpeg#center"
         alt="A child fishing, seen with and without macular degeneration"/> <figcaption>
            <p>A 2014 study estimated ~10% of New Zealanders 45-85 suffer from macular degeneration.</p>
        </figcaption>
</figure>

<p>Macular Degeneration New Zealand estimates that 10% of the 45-85 age bracket suffers from macular degeneration. That&rsquo;s ~3-4% of the total population of New Zealand. What would it be worth to your company if you could increase the available market for your product by ~3-4%? If you&rsquo;re selling a B2B SaaS product and you&rsquo;re stuck with a system whose accessibility is poor, a 4% increase is massive.</p>
<p>Previously, unlocking that new market would be expensive! You either retrofit accessibility into a system that was never designed for it, using technology that was never built for it (anyone remember Adobe Flash? Good luck making that screen-reader compatible), or you rewrite significant portions or the entirety of that product!</p>
<p>With your own personal agent the story is very different. IBM is never going to update your particular version of lotus notes, and yet every fortnight, with an eye condition like macular degeneration, you&rsquo;ve got to fill in your time sheet. You&rsquo;re a skilled analyst, but this clunky, inaccessible user interface turns a ten-minute job into half an hour or more of struggle, every week, every fortnight, until you die or leave the company.</p>
<p>Not only can agents dissolve the accessibility-usability dilemma, they can give you a usable facade over unusable software. Your agent can consume the underlying APIs that Lotus Notes uses, unlocking a natural language interface to your timesheets. Whether it&rsquo;s text or voice, you ask your agent to fill in your timesheet, you&rsquo;ve worked on these three initiatives this week, and the time split is around 20%/40%/40%, and the agent converts that into the API calls needed to fill in your timesheet. If I were making ANY timesheet software today (#startup-idea), I&rsquo;d bin my UI and create MS Teams, Slack and Discord bots that convert your text or voice into valid timesheets. Not Hipchat or Flowdock though. No nice things for those people.</p>
<p>Flowdock aside, we have a moral imperative to make these systems accessible; it is the right thing to do.</p>
<p>This principle works for any legacy software that can make rapid accessibility gains, to say nothing of software built with accessibility at its core. Eyesight is just one example. Every tech supercycle has expanded access or created new markets, and with agents, we&rsquo;re about to see it happen again.</p>
<h2 id="accessibility-remains-a-moral-and-commercial-imperative">Accessibility remains a moral and commercial imperative</h2>
<p>Consider this: I&rsquo;m a company that today sells inaccessible software as a service. I charge $20 monthly, and New Zealand has about 5 million people. Adding 4% of that population to my serviceable addressable market, I can now sell to 200,000 new customers. If I win 5% of those, I can add 10,000 new subscribers and increase my annual recurring revenues by $2.4m. The total addressable market of New Zealand - that five million - is small fry. In June 2024, Sydney had about 5.5 million residents. Accessibility is money. Pure and simple.</p>
<p>These supercycles - PC, e-commerce, Cloud Computing, Mobile Web, and now AI each unlocked new markets with brand new users and unlocked new interactions that expanded existing markets. They made previously inaccessible systems accessible for those who were previously excluded.</p>
<p>The PC created markets, and e-commerce turned local and regional markets global. Cloud computing unlocked new markets by drastically reducing the barrier to entry for brand-new types of companies. AWS had a five- to seven-year head start with startups that used cloud computing to reach new markets faster than the incumbents could keep up. Mobile Web put a device in the pockets of billions of people who previously might have struggled to buy expensive computer hardware!</p>
<p>Enterprises responded to these market changes by either building new products native to the ideas of that supercycle or retrofitting legacy systems with the tech needed to play in that new market, even if the outcomes weren&rsquo;t as technically pure as building from scratch.</p>
<h2 id="how-to-build-affordances-for-agents">How to build affordances for agents</h2>
<p>Affordances in UI/UX include clear and consistent navigation patterns, breadcrumbs, and semantic markup that conveys intent and relationships. In back-end services, affordances include machine-readable APIs with consistent patterns and discoverable endpoints, semantic metadata, explicit error signalling and recovery protocols, data provenance, and separation of commands from queries. All of these things help humans use and build systems today!</p>
<p>All of them are necessary for agents to use and build those same systems tomorrow.</p>
<p>Consider building a significant integration into a product or system never designed for it. If you treat affordances for agents today, you will feel the same pain tomorrow as you felt building that integration. Maybe more so.</p>
<p>We already strive to build clean interfaces with clear documentation and unambiguous behaviours. We do this for humans and third-party developers who want to integrate with us.</p>
<p>The only difference is that tomorrow&rsquo;s third parties will be agents. Those agents will expect the same affordances we build today, and the customers those agents serve will expect that your software works with their agent (or your own).</p>
<p>So, what can you do today to best prepare? If you don&rsquo;t happen to be rewriting your whole product from scratch, what can you do to ensure that your product meets the prerequisites for agentic success?</p>
<h2 id="concrete-steps-teams-can-take-today">Concrete steps teams can take today</h2>
<h4 id="audit-current-affordances-to-identify-gaps-in-context-or-access">Audit current affordances to identify gaps in context or access.</h4>
<p>In surgery, an agent can only act safely if it knows what tools are available, what states the patient is in, and what the patient&rsquo;s vitals mean. If those affordances are missing, the agent is blind.</p>
<ul>
<li>Start by mapping the interaction surfaces of your products. Any place a human or machine can read, write or otherwise interact. Ask: If the user were an agent, would they have all of the information they need to understand what is possible here?</li>
<li>Look for missing cues; this might mean e.g. unclear navigation, inconsistent APIs or documentation or poorly or uncommunicated state changes.</li>
<li>Treat this like a penetration test, but for usability. You&rsquo;re trying to find where an agent would be blind or blocked because of missing affordances.</li>
</ul>
<h4 id="add-semantic-metadata-ensuring-every-entityevent-is-machine-readable">Add semantic metadata, ensuring every entity/event is machine-readable.</h4>
<p>Agents cannot guess intent. They cannot be aware of the conversations that were had in the room back during design time. They only have access to what you grant them at run time. Provide explicit signals for use that convey intent. Add semantic tags to your data models, events, and UI elements to make their meaning unambiguous.</p>
<p>For example, you might return a response to a UI that looks something like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;content&#34;</span>: {<span style="color:#960050;background-color:#1e0010">...</span>}, <span style="color:#75715e">// omitted for brevity
</span></span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;metadata&#34;</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;workflow_stage&#34;</span>: <span style="color:#ae81ff">3</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>In payroll, an agent can&rsquo;t guess that <code>&quot;workflow_stage&quot;: 3</code> means &ldquo;awaiting approval from a payroll manager&rdquo;. Your UI might store an enum that maps 3 to something a human might understand, but your agent won&rsquo;t know what to make of this. You might resolve this in a few different ways. One option might be to ship a representation of the enum class with every response, but I can hear the purists in the back groaning about extra bytes over the wire, so what if we just did this instead:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;content&#34;</span>: {<span style="color:#960050;background-color:#1e0010">...</span>}, <span style="color:#75715e">// omitted for brevity
</span></span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;metadata&#34;</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;workflow_stage&#34;</span>: <span style="color:#ae81ff">3</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;workflow_description&#34;</span>: <span style="color:#e6db74">&#34;Awaiting approval from a payroll manager&#34;</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>This simple change tells us (and our agents) a lot! This is a payroll application, and we expect a manager to approve this task. An agent can then curry that information into whatever other process is needed. A small change can make a big difference.</p>
<h4 id="separate-commands-and-queries-to-clarify-state-changes-vs-information-retrieval">Separate commands and queries to clarify state changes vs information retrieval.</h4>
<p>In a legacy retrofit, an agent filling in a Lotus Notes timesheet should be able to read current entries without risk of accidentally writing changes. In surgery, separating &ldquo;monitor vitals&rdquo; from &ldquo;adjust anaesthetic&rdquo; presents a clear safety improvement.</p>
<p>Splitting reads from writes benefits modularity and encapsulation, scalability, and keeping interfaces small and clean. It can also substantially de-risk agent use of your software!</p>
<p>Separating reads from writes creates structurally clear and governable ways for agents to interact. Want a read-only agent? Scope its token to your read surface. Want your agent to plan before acting? Give it the context that API 1 is for planning and API 2 is for executing.</p>
<p>CQRS makes it easier for agents to plan, simulate, and validate actions before committing. We want agents to be cautious and measured, like human operators.</p>
<h4 id="expose-intent-surfaces-letting-agents-understand-why-actions-are-taken">Expose intent surfaces, letting agents understand why actions are taken.</h4>
<p>Agents are like my 10-year-old. He craves the &ldquo;why&rdquo; of things. Agents need that &ldquo;why&rdquo; as well, not just the &ldquo;what&rdquo;.</p>
<p>In our JSON example above, you saw that we exposed a metadata block in our API response. That metadata block is a crucial intent surface. Intent surfaces are metadata or API endpoints that explain the rationale behind specific actions we might take, are taking, or have taken in the past.</p>
<p>Consider this API response for a payroll adjustment</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;content&#34;</span>: {<span style="color:#960050;background-color:#1e0010">...</span>}, <span style="color:#75715e">// omitted for brevity
</span></span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;metadata&#34;</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;reason_code&#34;</span>: <span style="color:#e6db74">&#34;overtime&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;policy_reference&#34;</span>: <span style="color:#e6db74">&#34;HR-OT-2024&#34;</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>With a response like this, an agent understands that we&rsquo;ve adjusted pay because a staff member has worked overtime, and to ensure compliance, the agent can cross-reference (via RAG or e.g. an HTTP request to a document store) the overtime payment against the policy. It can do this as a matter of course for all overtime payments or only for anomalous overtime payments (because they are high, or low, or on an unexpected or unusual day of the week or for any other reason). The agent can do this check at audit time, or it can do it asynchronously while the pay run is still being worked on - so we can look back in history and spot issues AND prevent new problems from appearing.</p>
<h4 id="implement-provenance-hooks-to-track-data-origin-and-transformations">Implement provenance hooks to track data origin and transformations.</h4>
<p>Provenance is the audit trail for meaning. Every piece of data should carry its origin, transformation history, and trust level.</p>
<p>When data carries this information, agents can verify accuracy, detect anomalies and explain decisions to humans.</p>
<p>A medical agent deciding on a treatment plan (perhaps after the surgery we discussed earlier is complete) can trace lab results back to a specific machine, calibration date, and technician and flag if some aspect of that calibration might have a material impact on the patient&rsquo;s well-being.</p>
<p>These steps aren&rsquo;t solely about future-proofing in the abstract; they&rsquo;re about making your systems agent-ready now. The teams that start today will be the teams whose products feel inevitable across the next supercycle. Everyone else will be scrambling to retrofit under pressure.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Take yourself back to the year 2000 once more. The iPhone is coming. Android is nearly here. What would you do if you were there again? I believe that we are there today. You might argue about the moral rights and wrongs of AI, or you might think that we are in a massive bubble. You might be right. But the e-commerce supercycle lasted a full decade after the dotcom bubble burst. The bubble was a harbinger of a changing world.</p>
<p>We are at the start of a new supercycle. A supercycle of agents, that I believe will be bigger than cloud computing, bigger than the mobile web, bigger than e-commerce. Maybe even bigger than the PC.</p>
<p>The Helpful Web: humans and AI allies expanding access for everyone.
Accessibility isn&rsquo;t just inclusion — it&rsquo;s growth.
Audit your affordances, design for agents, make AI your company strategy.
In ten years, bypassing your agents will feel like malpractice.</p>
<h4 id="references">References</h4>
<p>[1] <a href="https://www.interaction-design.org/literature/topics/affordances?ep=ug0" target="_blank" rel="noopener noreferrer">What are Affordances?</a>

, IxDF</p>
<p>[2] <a href="https://static1.squarespace.com/static/5dcba244e3fb8952b16c79fd/t/5e9917df060d124f4a403e11/1587091469915/About&#43;Macular&#43;Degeneration&#43;A4.pdf" target="_blank" rel="noopener noreferrer">About Macular Degeneration</a>

, Macular Degeneration New Zealand</p>
]]></content:encoded></item><item><title>Introducing the QUERY HTTP Verb</title><link>https://4lex.nz/posts/the-query-method/</link><pubDate>Thu, 25 Nov 2021 00:00:00 +0000</pubDate><guid>https://4lex.nz/posts/the-query-method/</guid><description>&lt;h2 id="introducing-query"&gt;Introducing QUERY&lt;/h2&gt;
&lt;p&gt;The IETF has published a document detailing the QUERY verb. The Query verb neatly solves the problem of asking APIs for LOTS of data or &lt;em&gt;conditional&lt;/em&gt; data.
In other words, QUERY enables API providers to provide a means for clients to ask the server about data, where the client isn&amp;rsquo;t sure what data is available.&lt;/p&gt;
&lt;h2 id="a-worked-example"&gt;A worked example&lt;/h2&gt;
&lt;p&gt;Working in Agri-tech, I often want to find out information about animals.
Unfortunately, that information can live across many systems, with many identifiers (primary keys or other).
In one context I&amp;rsquo;ve experienced, Dairy Animals can be identified and referenced by five or more different identifiers - so what do you do if you don&amp;rsquo;t know all of them?&lt;/p&gt;</description><content:encoded><![CDATA[<h2 id="introducing-query">Introducing QUERY</h2>
<p>The IETF has published a document detailing the QUERY verb. The Query verb neatly solves the problem of asking APIs for LOTS of data or <em>conditional</em> data.
In other words, QUERY enables API providers to provide a means for clients to ask the server about data, where the client isn&rsquo;t sure what data is available.</p>
<h2 id="a-worked-example">A worked example</h2>
<p>Working in Agri-tech, I often want to find out information about animals.
Unfortunately, that information can live across many systems, with many identifiers (primary keys or other).
In one context I&rsquo;ve experienced, Dairy Animals can be identified and referenced by five or more different identifiers - so what do you do if you don&rsquo;t know all of them?</p>
<p>In my case, I want to provide an API with the identifiers I DO know and ask for the API to return any identifiers it
has that are linked to the ones I submitted. There are a few ways the API could implement such functionality.</p>
<p>For a complete animal:</p>
<blockquote>
<p><code>HTTP GET /animals/${the_identifier_i_know}?identifierType=${the_identifier_type}</code></p>
</blockquote>
<p>Based on this request URL, I would expect to provide an identifier and receive back the entire animal entity.
Animal entities can be of substantial size! Serialising all this data can be time-consuming and wasteful for a busy API,
particularly when we know we&rsquo;re just exploring and want only a subset of that data. We&rsquo;d be discarding 90% of the data returned.</p>
<p>For an animal&rsquo;s identifiers only:</p>
<blockquote>
<p><code>HTTP GET /animal/identifier?identifierType=${the_identifier_i_know}</code></p>
</blockquote>
<p>I interpret this URL as only providing me with identifying details about the animal. Optionally, I can request a certain type of identifier.
If I only care about a singular animal, this is probably all you need. No <code>QUERY</code> verb is necessary.
What If I want to query a collection of animals? There are potentially many thousands of animals in a group for which I require data.
I&rsquo;d encounter a significant HTTP overhead, making that many requests to this endpoint. What we need is an API for a collection of animals!</p>
<p>A collection of dairy cows is a herd. I don&rsquo;t care about herds; I want identifiers for an arbitrary group of animals for my specific use case.
<img alt="Image of man demanding pictures of Spiderman" loading="lazy" src="/img/in-post/get-me-pictures.jpeg"></p>
<p>REST guidelines ask that you model your APIs as</p>
<blockquote>
<p><code>/{collection_one}/{collection_one_identifier}/{collection_two}/{collection_two_identifier}</code> and so on.</p>
</blockquote>
<p>Under this guidance, we cannot submit multiple identifiers for a single collection. So if we had 3000 animals, for example, the request might be:</p>
<p><code>/animals?identifier=id1,id2,id3 ... etc</code> - it doesn&rsquo;t make sense! Putting many identifiers in a URI comes with its work,
but crucially, if you&rsquo;re asking for lots of data and are forced to encode that in the URI,
you could run into length limits preventing you from encoding all of your request. Most servers will typically limit
the length of your encoded URI to 2048 characters or less. Those servers will decline your request if the URI is too long.</p>
<p>Most folks get around this by defining a <code>POST</code> endpoint that breaks RESTful principles. Here&rsquo;s an example of a <code>POST</code> request:</p>
<p><code>HTTP POST /animals/search</code> with a body:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;knownAnimalIdentifier&#34;</span>: [
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;id1&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;id2&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;id3&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;id4&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;id5&#34;</span>
</span></span><span style="display:flex;"><span>  ]
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>You could put all sorts of freaky logic or conditionals in this body; there are far fewer limits and, therefore,
more risk of pushing the concept outside sensible boundaries. For example, this might also be valid:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;knownAnimalIdentifier&#34;</span>:[
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;id1&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;id3&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;id3&#34;</span>
</span></span><span style="display:flex;"><span>  ],
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;where&#34;</span>:{
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;healthTreatment&#34;</span>:{
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">&#34;condition&#34;</span>:<span style="color:#e6db74">&#34;mastitis&#34;</span>,
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">&#34;product&#34;</span>:<span style="color:#e6db74">&#34;amyzin&#34;</span>
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>You could pull all sorts of stunts here. The above looks suspiciously like GraphQL to me - the key message here is that
<code>POST</code>-ing arbitrary search data to an API imposes very few limits on otherwise conscientious and responsible developers.</p>
<p>Further, using a <code>POST</code> doesn&rsquo;t match the intent of the request. REST guideline defines a <code>POST</code> as NOT idempotent - <code>POST</code>
means you&rsquo;re creating a new resource every time you make the request. With our above requests, the intent is to search for data,
not create resources, but we don&rsquo;t have a good way of modelling that! You could argue that when you submit a search via <code>POST</code>
you are asking the server to create a new resource containing your results - the issue with that, is that you&rsquo;re not creating a new resource.
At best you are creating a new projection of resources that already exist. You&rsquo;re not <code>POST</code>-ing a new letter into the letterbox,
you&rsquo;re asking the mailman to pass you some letters that may or may not exist.</p>
<p>To do a search we need to do the <code>HTTP</code> <code>GET</code> <code>POST</code> <code>GET</code> dance. First <code>GET</code> enough data to formulate your search query, then <code>POST</code> to
create a query resource, then optionally <code>GET</code> the resource you just created.</p>
<p>Some folks will implement an API that directly returns the results to you. You&rsquo;d need to code
for latency, dropped connections and retries. For long-lived queries, you&rsquo;d need a solution for the underlying data
changing as the query progresses (similar to pagination where page 3 changes after you retrieve it but before you complete paging).
If the API indirectly returns your data to you (i.e. immediately returns a link to the newly created search result resource), you have to go and <code>GET</code> that resource.</p>
<p>Using <code>POST</code> requests for search functionality solves one problem - lack of flexibility in the <code>GET</code> verb - but introduces another.
Using <code>POST</code> server cannot cache or re-use results, nor can it deal gracefully with common failure modes (retrying ten times
creates ten resources! All those resources might be different!)</p>
<h2 id="the-query-verb">The Query Verb</h2>
<p>Julian Reschke, Ashok Malhotra and James M Snell has authored a draft RFC that describes the <a href="https://www.ietf.org/archive/id/draft-ietf-httpbis-safe-method-w-body-02.html" target="_blank" rel="noopener noreferrer">QUERY verb</a>

.</p>
<p><code>QUERY</code> solves the problems of your typical search workflow.</p>
<p>The draft spec defines a <code>QUERY</code> as a means of making a safe, idempotent request that contains content.
It&rsquo;s worth your time to read the entire article (it&rsquo;s about a five-minute read).</p>
<p>The important parts for me (i.e. order and emphasis mine) as a system designer are:</p>
<blockquote>
<p><code>QUERY</code> requests are both safe and idempotent with regards to the resource identified by the request&rsquo;s URI</p>
</blockquote>
<blockquote>
<p>The response to a <code>QUERY</code> method is cacheable</p>
</blockquote>
<blockquote>
<p>The body payload of the request defines the query. Implementations MAY use a request body of any content type with the <code>QUERY</code> method, provided that it has appropriate query semantics.</p>
</blockquote>
<blockquote>
<p>The payload returned in response to a <code>QUERY</code> cannot be assumed to be a representation of the resource identified by the effective request URI.</p>
</blockquote>
<p>Before, I would have to make a <code>GET</code> to some URL with an enormous query string OR create arbitrary numbers of un-cacheable
new resources; now, I can use the <code>QUERY</code> request. Furthermore, I can put whatever data I need in the body of my request,
safe in the knowledge that implemented to spec; I&rsquo;m going to get a quick response that I can cache in line with the server&rsquo;s guidance.</p>
<p>It&rsquo;s a small and subtle change. Implementation-wise, you could change your existing <code>POST</code> search endpoint to a <code>QUERY</code> and
leave the same body. Migrate current <code>GET</code> endpoints by shifting query/path parameter content into the body and change the verb.</p>
<p>The most significant improvement relates to intent and clarity. Using a <code>QUERY</code> verb signals my intention to request data
based on conditions that I supply. <code>QUERY</code> marks that request as idempotent and indicates the intent of the caller.</p>
<p><code>POST</code> shows intent to create a new resource. <code>GET</code> indicates intent to retrieve a resource for whom the caller already has
an identifier. Neither <code>POST</code> nor <code>GET</code> indicate an intention to request data about which the caller is uncertain.
The semantics of the verb and the request matter because they clarify intent. Computers will do what we tell them to do. Not what we intend for them to do.</p>
<p>Clarity of intent in an API is crucial to the success of that API. When designing that API, we want to make it as easy
as possible to map the intent of the caller to appropriate functionality in the API. Introducing new verbs to clarify
the caller&rsquo;s desires and better match those needs (i.e. &ldquo;What endpoint should I call to do X?&rdquo;) to the correct part of an API brings developers joy.</p>
<h2 id="conclusion">Conclusion</h2>
<p>The <code>QUERY</code> verb is brand new and in draft with the IETF - you can check it out <a href="https://www.ietf.org/archive/id/draft-ietf-httpbis-safe-method-w-body-02.html" target="_blank" rel="noopener noreferrer">here</a>

.
It clarifies the calling system&rsquo;s intent and enables behaviour more suited to interactions where you don&rsquo;t know what specific resources are available,
but you do know something about those resources (e.g. the first and last names of a person, or their phone number,
email address or some combination thereof). QUERY allows for idempotency, caching and is easy to adopt incrementally.</p>
<h2 id="citations-and-further-reading">Citations and Further Reading</h2>
<ul>
<li><a href="https://www.ietf.org/archive/id/draft-ietf-httpbis-safe-method-w-body-02.html" target="_blank" rel="noopener noreferrer">Julian Reschke, Ashok Malhotra, James M Snell: The HTTP QUERY Method</a>

</li>
</ul>
]]></content:encoded></item><item><title>SQL Joins with Sequelize</title><link>https://4lex.nz/posts/sql-joins-with-sequelize/</link><pubDate>Sun, 11 Oct 2020 00:00:00 +0000</pubDate><guid>https://4lex.nz/posts/sql-joins-with-sequelize/</guid><description>&lt;p&gt;While working on an API for my day job last week, I needed to do a SQL Inner Join with Sequelize and Typescript in a
web API. Here&amp;rsquo;s how I achieved it.&lt;/p&gt;
&lt;h4 id="environment"&gt;Environment:&lt;/h4&gt;
&lt;p&gt;Things move quickly in the JS ecosystem. Here are the library versions used in the subject API at the time of writing:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;dependencies&amp;#34;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;@types/express&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;~4.0.39&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;@types/sequelize&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;^4.27.21&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;express&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;~4.16.2&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;sequelize&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;4.38.0&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="context"&gt;Context:&lt;/h4&gt;
&lt;p&gt;I have an identifier in one system that I need to correlate with an identifier in a second system, but I
could only do that via an intermediate identifier, also in the second system. A good case for a SQL Join.&lt;/p&gt;</description><content:encoded><![CDATA[<p>While working on an API for my day job last week, I needed to do a SQL Inner Join with Sequelize and Typescript in a
web API. Here&rsquo;s how I achieved it.</p>
<h4 id="environment">Environment:</h4>
<p>Things move quickly in the JS ecosystem. Here are the library versions used in the subject API at the time of writing:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-json" data-lang="json"><span style="display:flex;"><span><span style="color:#e6db74">&#34;dependencies&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;@types/express&#34;</span>: <span style="color:#e6db74">&#34;~4.0.39&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;@types/sequelize&#34;</span>: <span style="color:#e6db74">&#34;^4.27.21&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;express&#34;</span>: <span style="color:#e6db74">&#34;~4.16.2&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;sequelize&#34;</span>: <span style="color:#e6db74">&#34;4.38.0&#34;</span>,
</span></span><span style="display:flex;"><span>  }
</span></span></code></pre></div><h4 id="context">Context:</h4>
<p>I have an identifier in one system that I need to correlate with an identifier in a second system, but I
could only do that via an intermediate identifier, also in the second system. A good case for a SQL Join.</p>
<table>
  <thead>
      <tr>
          <th>System 1</th>
          <th>System 2</th>
          <th>System 2</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Electronic Identifier</td>
          <td>Animal Identifier</td>
          <td>Legacy Animal Identifier</td>
      </tr>
      <tr>
          <td>ABCD</td>
          <td>555 WXYZ</td>
          <td>1234</td>
      </tr>
  </tbody>
</table>
<p>In System 1, I have enough information to send this request:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;items&#34;</span>: [
</span></span><span style="display:flex;"><span>        <span style="color:#e6db74">&#34;ABC&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#e6db74">&#34;DEF&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#e6db74">&#34;GHI&#34;</span>
</span></span><span style="display:flex;"><span>    ]
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>And in response I want:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;links&#34;</span>: [
</span></span><span style="display:flex;"><span>        {
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&#34;rel&#34;</span>: <span style="color:#e6db74">&#34;self&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&#34;href&#34;</span>: <span style="color:#e6db74">&#34;https://api.com/123-i-am-a-uuid&#34;</span>
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    ],
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;reference&#34;</span>: <span style="color:#e6db74">&#34;123-i-am-a-uuid&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;items&#34;</span>: [
</span></span><span style="display:flex;"><span>        {
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&#34;legacyId&#34;</span>: <span style="color:#ae81ff">123</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&#34;electronicId&#34;</span>: <span style="color:#e6db74">&#34;ABC&#34;</span>
</span></span><span style="display:flex;"><span>        },
</span></span><span style="display:flex;"><span>        {
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&#34;legacyId&#34;</span>: <span style="color:#ae81ff">456</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&#34;electronicId&#34;</span>: <span style="color:#e6db74">&#34;DEF&#34;</span>
</span></span><span style="display:flex;"><span>        },
</span></span><span style="display:flex;"><span>        {
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&#34;legacyId&#34;</span>: <span style="color:#ae81ff">789</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&#34;electronicId&#34;</span>: <span style="color:#e6db74">&#34;GHI&#34;</span>
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    ]
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The initial approach was to make three repository queries to get the data I needed, and then go through three
javascript map operations to splice the data into the above format. Using a series of javascript maps is inefficient, particularly as the data set grows.</p>
<p>A better way is to get SQL to do the grunt work, as it&rsquo;s far more time and memory efficient than the javascript I would have needed to write.</p>
<blockquote>
<p>As an aside, I&rsquo;m not too fond of Javascript on the back end. I don&rsquo;t feel it&rsquo;s performant enough and as your codebase
grows the lack of a robust type system hurts more and more. Typescript helps address the latter (assuming your libraries support it) but does nothing for the former.
A typed language like C# or Java is preferable for web programming in a large enterprise due to better performance, more coherent ecosystem (see: <code>left-pad</code>) and robust type system.</p>
</blockquote>
<p>I need to make a map of identifiers from an <code>electronicIdEvent</code> entity
(that deals with electronic identifiers) and an <code>animal</code> entity that deals with animal information.</p>
<table>
  <thead>
      <tr>
          <th></th>
          <th>electronicId</th>
          <th>animalId</th>
          <th>legacyAnimalId</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>electronicIdEvent</td>
          <td>✓</td>
          <td>✓</td>
          <td></td>
      </tr>
      <tr>
          <td>animal</td>
          <td></td>
          <td>✓</td>
          <td>✓</td>
      </tr>
  </tbody>
</table>
<p>I need the <code>legacyAnimalId</code> field. To find a <code>legacyAnimalId</code> given an <code>electronicIdEvent</code>, I have to:</p>
<ol>
<li>Find all <code>electronicIdEvent</code> rows that match an <code>electronicId</code>.</li>
<li>Find all <code>animal</code> rows that match the <code>animalId</code> of the <code>electronicIdEvent</code> where an <code>electronicId</code> is present.</li>
<li>Return all <code>legacyAnimalId</code> rows that match the <code>animalId</code> of both the <code>animal</code> and the <code>electronicIdEvent</code>.</li>
</ol>
<p>Hopefully, you can see why using javascript maps, and SQL selects for this would be tedious and inefficient.</p>
<p>Here&rsquo;s a SQL query that demonstrates what I want if you&rsquo;re more familiar with SQL then Javascript:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span><span style="color:#66d9ef">select</span> event.eid, event.animalId, animal.id, animal.animalKey
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">from</span> <span style="color:#e6db74">&#34;electronicIdEvent&#34;</span> event
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">inner</span> <span style="color:#66d9ef">join</span> <span style="color:#e6db74">&#34;animal&#34;</span> animal
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">on</span> event.<span style="color:#e6db74">&#34;animalId&#34;</span> <span style="color:#f92672">=</span> animal.id
</span></span></code></pre></div><h3 id="1-create-associations-for-sequzelize-between-the-data-you-need-to-link">1. Create associations for Sequzelize, between the data you need to link.</h3>
<p>For Sequelize to generate the right SQL, it needs to know about the relationships between your data.</p>
<p>Here&rsquo;s the code that creates associations in Sequelize:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-typescript" data-lang="typescript"><span style="display:flex;"><span><span style="color:#66d9ef">this</span>.<span style="color:#a6e22e">animal</span>.<span style="color:#a6e22e">hasMany</span>(<span style="color:#66d9ef">this</span>.<span style="color:#a6e22e">electronicIdEvent</span>, {
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">foreignKeyConstraint</span>: <span style="color:#66d9ef">true</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">foreignKey</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;animalId&#34;</span>,
</span></span><span style="display:flex;"><span>});
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">this</span>.<span style="color:#a6e22e">electronicIdEvent</span>.<span style="color:#a6e22e">belongsTo</span>(<span style="color:#66d9ef">this</span>.<span style="color:#a6e22e">animal</span>, {
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">foreignKeyConstraint</span>: <span style="color:#66d9ef">true</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">foreignKey</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;animalId&#34;</span>,
</span></span><span style="display:flex;"><span>});
</span></span></code></pre></div><p>Associations allow the ORM to understand your relations and map <code>One To One</code>, <code>One To Many</code> and <code>Many To Many</code> relationships to appropriate SQL code. The docs describe this <a href="https://sequelize.org/master/manual/assocs.html" target="_blank" rel="noopener noreferrer">here</a>

</p>
<h3 id="2-create-a-sequelize-repository-method-that-uses-this-association-to-form-a-sql-query-that-returns-the-correct-data">2. Create a Sequelize repository method that uses this association to form a SQL query that returns the correct data:</h3>
<p>There is some stuff in here that&rsquo;s not great, but it works well enough. If I had more time, I&rsquo;d figure out
a way of using typescript&rsquo;s not-null override (<code>!</code>), and ideally find a way of making <code>event</code> a typed response.</p>
<p>The pseudocode I want is:</p>
<ul>
<li>First return all the rows for the <code>electronicId</code> and <code>animalId</code> columns in <code>electronicIdEvent</code>, where the <code>electronicId</code> is present in my <code>electronicIdList</code></li>
<li>Next join the rows for those columns with the rows for the <code>legacyAnimalId</code> column, where the <code>animalId</code> is the same in both the <code>electronicIdEvent</code> and <code>animal</code> entities.</li>
<li>When the data comes back, drop the <code>animalId</code> column. I don&rsquo;t need it once it has done the job of being the glue between the other entities and columns.</li>
</ul>
<p>Or, as Javascript:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-typescript" data-lang="typescript"><span style="display:flex;"><span><span style="color:#75715e">// imports omitted for brevity
</span></span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">export</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">AnimalRepository</span> {
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">constructor</span>(
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#a6e22e">db</span>: <span style="color:#66d9ef">AnimalTimelineDbContext</span>,
</span></span><span style="display:flex;"><span>  ) {}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">getLegacyAnimalIdentifierByElectronicIdentifier</span>(<span style="color:#a6e22e">electronicIdList</span>: <span style="color:#66d9ef">Array</span>&lt;<span style="color:#f92672">string</span>&gt;)<span style="color:#f92672">:</span> <span style="color:#a6e22e">Promise</span>&lt;<span style="color:#f92672">Array</span>&lt;<span style="color:#f92672">IdentifierMap</span>&gt;&gt; {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">this</span>.<span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">electronicIdEvent</span>
</span></span><span style="display:flex;"><span>      .<span style="color:#a6e22e">findAll</span>({
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">attributes</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#34;electronicId&#34;</span>, <span style="color:#e6db74">&#34;animalId&#34;</span>],
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">where</span><span style="color:#f92672">:</span> {
</span></span><span style="display:flex;"><span>          <span style="color:#a6e22e">electronicId</span>: <span style="color:#66d9ef">electronicIdList</span>,
</span></span><span style="display:flex;"><span>        },
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">include</span><span style="color:#f92672">:</span> [ 
</span></span><span style="display:flex;"><span>          {
</span></span><span style="display:flex;"><span>            <span style="color:#a6e22e">model</span>: <span style="color:#66d9ef">this.db.animal</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#a6e22e">required</span>: <span style="color:#66d9ef">true</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#a6e22e">attributes</span><span style="color:#f92672">:</span> [<span style="color:#e6db74">&#34;legacyAnimalId&#34;</span>],
</span></span><span style="display:flex;"><span>          },
</span></span><span style="display:flex;"><span>        ],
</span></span><span style="display:flex;"><span>      })
</span></span><span style="display:flex;"><span>      .<span style="color:#a6e22e">then</span>((<span style="color:#a6e22e">events</span>) <span style="color:#f92672">=&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">events</span>.<span style="color:#a6e22e">map</span>((<span style="color:#a6e22e">event</span>) <span style="color:#f92672">=&gt;</span> ({
</span></span><span style="display:flex;"><span>          <span style="color:#a6e22e">eid</span>: <span style="color:#66d9ef">event.electronicId</span>,
</span></span><span style="display:flex;"><span>          <span style="color:#a6e22e">legacyAnimalId</span>: <span style="color:#66d9ef">event.Animal</span><span style="color:#f92672">!</span>.<span style="color:#a6e22e">legacyAnimalId</span>,
</span></span><span style="display:flex;"><span>        }))
</span></span><span style="display:flex;"><span>      );
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><blockquote>
<p>Note: Setting <code>required: true</code> in the <code>include</code> block forces the query to only return records which have an associated model, this converts the query from an OUTER JOIN to an INNER JOIN.</p>
</blockquote>
<blockquote>
<p>Because we only return complete rows (no partials) <code>event.Animal</code> cannot be null, I can override the typescript hint, i.e. <code>event.Animal!.legacyAnimalId</code>.</p>
</blockquote>
<p>I&rsquo;m done at this point. We&rsquo;ve submitted a list of electronic identifiers and gotten back an <code>Array&lt;IdentifierMap&gt;</code>, which is syntactic sugar for <code>Array&lt;[string, integer]&gt;</code>.</p>
<h3 id="3-convert-the-raw-data-into-my-map-object-and-fire-the-response-back">3. Convert the raw data into my map object, and fire the response back.</h3>
<p>Because Sequelize is doing most of the grunt work in formatting the data, all I need in my web layer is to add the UUID
that the user-submitted and save that map. Once I&rsquo;ve saved the map and returned the reference to the calling system,
the calling system can ask for that map and get the data (this is the most RESTful way of handling the data exchange
and I&rsquo;m omitting that setup for a follow-up post).</p>
]]></content:encoded></item></channel></rss>