<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Orbital Blog</title>
        <link>https://orbitalhq.com/blog</link>
        <description>Everything Orbital.  From our keyboards straight to your eyeballs.</description>
        <lastBuildDate>Fri, 17 Jul 2026 07:13:07 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <image>
            <title>Orbital Blog</title>
            <url>https://orbitalhq.com/favicons/favicon-32x32.png?v=3</url>
            <link>https://orbitalhq.com/blog</link>
        </image>
        <copyright>All rights reserved 2026, Orbital API Ltd</copyright>
        <atom:link href="https://orbitalhq.com/feeds/feed.xml" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Benchmarking LLM Accuracy in Real-World API Orchestration]]></title>
            <link>https://orbitalhq.com/blog/2026-01-20-agentic-orchestration-research-paper</link>
            <guid>Benchmarking LLM Accuracy in Real-World API Orchestration</guid>
            <pubDate>Tue, 20 Jan 2026 19:00:00 GMT</pubDate>
            <description><![CDATA[We tested how well LLMs handle real-world API orchestration with up to 600 endpoints. Planning accuracy dropped to 30-49% with plain OpenAPI specs, but improved 73-142% using semantic metadata and TaxiQL. Full research results included.]]></description>
            <content:encoded><![CDATA[<h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="introduction"><a href="#introduction" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Introduction</span></h2><p>AI agents are becoming a core part of enterprise integration - not just for pre-built flows like ETL and API aggregation, but for ad-hoc, on-demand orchestration inside real-time agent workflows.</p><p>As adoption accelerates, a key question is whether LLMs can reliably navigate the complexity of real-world API estates.</p><p>So we set out to answer:</p><div class="my-6 p-4 bg-slate-800/30 border-l-4 border-sky-500 rounded-r-lg"><p class="text-xl text-slate-200 font-bold leading-relaxed m-0">How well can LLMs plan workflows which orchestrate multiple APIs together, under real-world conditions?</p></div><p>We recently completed a detailed study into exactly this - measuring LLM accuracy when planning API orchestration tasks under increasingly realistic conditions.</p><p>We gave the agents a task (in the form of an “email from my boss”), and an (ever increasing) collection of OpenAPI specs, and asked
them to design a solution.</p><p>We then scored them against <a href="#what-we-measured-and-why">scoring criteria</a>, running each test 30 times, and averaged the results.</p><p>If you’re in a hurry, here’s a link to the results.</p><div class="text-2xl text-white pb-4">Download the results:</div><ul><li><a target="_blank" href="/content/Improving-LLM-Accuracy-in-API-Orchestration-Exec-Summary.pdf">An executive summary (5 pages)</a></li><li><a target="_blank" href="/content/Impact-of-Semantic-Layer-in-LLM-Accuracy.pdf">The full research results (40 pages)</a></li></ul><hr/><h1 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="key-findings"><a href="#key-findings" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Key findings</span></h1><p>We found four key facts:</p><ul role="list"><li><a href="#planning-accuracy-falls-to-unusable-levels-somewhere-between-60-and-300-endpoints">Planning accuracy falls to unusable levels somewhere between 60 and 300 endpoints</a></li><li><a href="#adding-even-minimal-semantic-metadata-improves-planning-accuracy">Adding even minimal semantic metadata improves planning accuracy</a></li><li><a href="#adopting-a-declarative-query-language-improves-llm-planning-accuracy-by-between-73-142">A declarative query language improved planning accuracy by between 73% to 142%</a></li><li><a href="#using-taxi-for-ap-is-instead-of-open-api-reduced-token-usage-by-80">Using Taxi for APIs (instead of OpenAPI) reduced token usage by 80%</a></li></ul><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="planning-accuracy-falls-to-unusable-levels-somewhere-between-60-and-300-endpoints"><a href="#planning-accuracy-falls-to-unusable-levels-somewhere-between-60-and-300-endpoints" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Planning accuracy falls to unusable levels somewhere between 60 and 300 endpoints</span></h2><p>Planning accuracy (more on how we measured this <a href="#how-we-measured">below</a>) fell to <strong>~30%</strong> and <strong>~49%</strong> once we increased the population of endpoints to 300. </p><p>Interestingly, the degradation didn’t continue at 600 endpoints. We were surprised by this and don’t have a clear answer as to why. </p><p>Note: An “endpoint” is a Path and a Verb (eg: <code>GET /customers/123</code>)</p><div class="flex flex-col  "><div class="flex flex-col md:flex-row gap-8 items-start"><div class="flex-1"><div class="styles_pageStyles__EjGvP"><table><thead><tr><th># of endpoints</th><th>Sonnet 4.5</th><th>ChatGPT 5.1</th></tr></thead><tbody><tr><td>60 endpoints</td><td>51.3%</td><td>62.7%</td></tr><tr><td>300 endpoints</td><td>30.1%</td><td>49.4%</td></tr><tr><td>600 endpoints</td><td>30.9%</td><td>46.4%</td></tr></tbody></table></div></div><div><img src="/_next/static/media/accuracy-of-ai-orchestration-60-vs-300-two-models.40ee660c.png" alt="" class="rounded-lg lg:h-[510px] lg:w-auto h-auto w-full" style="margin:0;padding:0"/></div></div></div><div class="styles_breakout__jYY_L"><button class="w-full flex items-center gap-2 text-slate-300 hover:text-slate-100 bg-slate-800/50 hover:bg-slate-700/50 px-4 py-2 rounded-lg border border-slate-700 transition-colors mb-4"><svg class="w-5 h-5 transform transition-transform " fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path></svg><span class="font-medium">Show detailed charts</span></button></div><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="adding-even-minimal-semantic-metadata-improves-planning-accuracy"><a href="#adding-even-minimal-semantic-metadata-improves-planning-accuracy" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Adding even minimal semantic metadata improves planning accuracy</span></h2><ul role="list"><li>We added <a href="#example-of-semantic-metadata">semantic metadata</a> to the OpenAPI specs on fields and input parameters.</li><li>We updated our prompts to “consider semantic metadata (expressed via OpenAPI <code>x-taxi-type</code> annotations), which explicitly describe the semantic meaning of data contained within each field.”</li><li>We didn’t provide any additional information about “Taxi”, ”<code>x-taxi-type</code>” or “Semantic Metadata” beyond what’s already present in standard base models</li></ul><p>The impact was a meaningful increase in accuracy compared to baseline:</p><div class="flex flex-col  "><div class="flex flex-col md:flex-row gap-8 items-start"><div class="flex-1"><div class="styles_pageStyles__EjGvP"><table><thead><tr><th></th><th>Sonnet 4.5</th><th>ChatGPT 5.1</th></tr></thead><tbody><tr><td>600 endpoints with plain OpenAPI</td><td>30.9%</td><td>46.1%</td></tr><tr><td>600 endpoints with OpenAPI using Taxi annotations</td><td>46.4%</td><td>58.8%</td></tr></tbody></table></div></div><div><img src="/_next/static/media/summary-adding-semantic-metadata.e91b98a3.png" class="rounded-lg lg:h-[510px] lg:w-auto h-auto w-full" style="margin:0;padding:0"/></div></div></div><div class="styles_breakout__jYY_L"><button class="w-full flex items-center gap-2 text-slate-300 hover:text-slate-100 bg-slate-800/50 hover:bg-slate-700/50 px-4 py-2 rounded-lg border border-slate-700 transition-colors mb-4"><svg class="w-5 h-5 transform transition-transform " fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path></svg><span class="font-medium">Show detailed charts</span></button></div><p>Importantly, this improvement came purely from base model knowledge of semantic metadata - we didn’t provide specialized prompts, examples, or training about how to use these annotations.</p><h3 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="example-of-semantic-metadata"><a href="#example-of-semantic-metadata" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Example of semantic metadata</span></h3><p>We added <code>x-taxi-type</code> annotations to the OpenAPI specs. To reiterate - we didn’t tell the LLMs anything more about what this was. In practice, both models appeared to be familiar
with <a href="https://taxilang.org">Taxi</a> and <a href="https://taxilang.org/docs/taxiql/querying">TaxiQL</a> from their training data.</p><pre class="language-yaml"><code class="language-yaml"><span class="token block"><span class="token plain">/quotes/</span><span class="token punctuation">{</span><span class="token plain">symbol</span><span class="token punctuation">}</span><span class="token punctuation">:</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">  </span><span class="token key atrule">get</span><span class="token punctuation">:</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">    </span><span class="token key atrule">summary</span><span class="token punctuation">:</span><span class="token plain"> Get single quote</span>
</span><span class="token block"><span class="token plain">    </span><span class="token key atrule">operationId</span><span class="token punctuation">:</span><span class="token plain"> getQuote</span>
</span><span class="token block"><span class="token plain">    </span><span class="token key atrule">parameters</span><span class="token punctuation">:</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">      </span><span class="token punctuation">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation">:</span><span class="token plain"> symbol</span>
</span><span class="token block"><span class="token plain">        </span><span class="token key atrule">in</span><span class="token punctuation">:</span><span class="token plain"> path</span>
</span><span class="token block"><span class="token plain">        </span><span class="token key atrule">required</span><span class="token punctuation">:</span><span class="token plain"> </span><span class="token boolean important">true</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">        </span><span class="token key atrule">schema</span><span class="token punctuation">:</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">          </span><span class="token key atrule">type</span><span class="token punctuation">:</span><span class="token plain"> string</span>
</span><span class="token block -mx-5 pl-4 pr-5 border-l-4 border-sky-400 bg-sky-300/[0.15]"><span class="token plain">          </span><span class="token key atrule">x-taxi-type</span><span class="token punctuation">:</span><span class="token plain"> com.bank.trading.Ticker</span>
</span><span class="token block"><span class="token plain">    </span><span class="token key atrule">responses</span><span class="token punctuation">:</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">      </span><span class="token key atrule">&#x27;200&#x27;</span><span class="token punctuation">:</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">        </span><span class="token key atrule">description</span><span class="token punctuation">:</span><span class="token plain"> OK</span>
</span><span class="token block"><span class="token plain">        </span><span class="token key atrule">content</span><span class="token punctuation">:</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">          </span><span class="token key atrule">application/json</span><span class="token punctuation">:</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">            </span><span class="token key atrule">schema</span><span class="token punctuation">:</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">              </span><span class="token key atrule">$ref</span><span class="token punctuation">:</span><span class="token plain"> </span><span class="token string">&#x27;#/components/schemas/Quote&#x27;</span>
</span></code></pre><p>And to response schemas:</p><pre class="language-yaml"><code class="language-yaml"><span class="token block"><span class="token key atrule">components</span><span class="token punctuation">:</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">  </span><span class="token key atrule">schemas</span><span class="token punctuation">:</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">    </span><span class="token key atrule">Quote</span><span class="token punctuation">:</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">      </span><span class="token key atrule">type</span><span class="token punctuation">:</span><span class="token plain"> object</span>
</span><span class="token block"><span class="token plain">      </span><span class="token key atrule">properties</span><span class="token punctuation">:</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">        </span><span class="token key atrule">symbol</span><span class="token punctuation">:</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">          </span><span class="token key atrule">type</span><span class="token punctuation">:</span><span class="token plain"> string</span>
</span><span class="token block -mx-5 pl-4 pr-5 border-l-4 border-sky-400 bg-sky-300/[0.15]"><span class="token plain">          </span><span class="token key atrule">x-taxi-type</span><span class="token punctuation">:</span><span class="token plain"> com.bank.trading.Ticker</span>
</span><span class="token block"><span class="token plain">        </span><span class="token key atrule">bid</span><span class="token punctuation">:</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">          </span><span class="token key atrule">type</span><span class="token punctuation">:</span><span class="token plain"> number</span>
</span><span class="token block -mx-5 pl-4 pr-5 border-l-4 border-sky-400 bg-sky-300/[0.15]"><span class="token plain">          </span><span class="token key atrule">x-taxi-type</span><span class="token punctuation">:</span><span class="token plain"> com.bank.trading.BidPrice</span>
</span><span class="token block"><span class="token plain">        </span><span class="token key atrule">ask</span><span class="token punctuation">:</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">          </span><span class="token key atrule">type</span><span class="token punctuation">:</span><span class="token plain"> number</span>
</span><span class="token block -mx-5 pl-4 pr-5 border-l-4 border-sky-400 bg-sky-300/[0.15]"><span class="token plain">          </span><span class="token key atrule">x-taxi-type</span><span class="token punctuation">:</span><span class="token plain"> com.bank.trading.AskPrice</span>
</span></code></pre><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="adopting-a-declarative-query-language-improves-llm-planning-accuracy-by-between-73-142"><a href="#adopting-a-declarative-query-language-improves-llm-planning-accuracy-by-between-73-142" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Adopting a declarative query language improves LLM planning accuracy by between 73% - 142%</span></h2><p>We asked the agents to express data requirements using TaxiQL queries.</p><p>The result was a significant improvement in planning accuracy.</p><div class="flex flex-col  "><div class="flex flex-col md:flex-row gap-8 items-start"><div class="flex-1"><div class="styles_pageStyles__EjGvP"><table><thead><tr><th></th><th>Sonnet 4.5</th><th>ChatGPT 5.1</th></tr></thead><tbody><tr><td>600 endpoints with plain OpenAPI</td><td>30.9%</td><td>46.1%</td></tr><tr><td>600 endpoints with OpenAPI using Taxi + TaxiQL</td><td>74.7%</td><td>85.5%</td></tr></tbody></table></div></div><div><img src="/_next/static/media/adopting-taxiql-summary.87c3b0a5.png" class="rounded-lg lg:h-[510px] lg:w-auto h-auto w-full" style="margin:0;padding:0"/></div></div></div><div class="styles_breakout__jYY_L"><button class="w-full flex items-center gap-2 text-slate-300 hover:text-slate-100 bg-slate-800/50 hover:bg-slate-700/50 px-4 py-2 rounded-lg border border-slate-700 transition-colors mb-4"><svg class="w-5 h-5 transform transition-transform " fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path></svg><span class="font-medium">Show detailed charts</span></button></div><p>There’s some important caveats here:</p><ul role="list"><li>For this test run, we provided Taxi schemas, not OpenAPI.</li><li>Critically, this reduced token usage by 80%, which meant much smaller context windows.</li><li>LLMs were told to “outline the API calls as TaxiQL queries”</li><li>We didn’t provide specific information about TaxiQL to the LLMs beyond what’s already in their base training</li></ul><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="using-taxi-for-ap-is-instead-of-open-api-reduced-token-usage-by-80"><a href="#using-taxi-for-ap-is-instead-of-open-api-reduced-token-usage-by-80" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Using Taxi for APIs (instead of OpenAPI) reduced token usage by 80%</span></h2><p>In the final tests (TaxiQL focussed) we sent API specs to LLMs in <a href="https://taxilang.org">Taxi</a>, rather than OpenAPI.</p><p>This dramatically reduced the consumed tokens (and therefore token size). As teams become sensitive to token spend, this
is a quick win for budgets.</p><div class="flex flex-col  "><div class="flex flex-col md:flex-row gap-8 items-start"><div class="flex-1"><div class="styles_pageStyles__EjGvP"><table><thead><tr><th></th><th>Tokens consumed</th></tr></thead><tbody><tr><td>OpenAPI</td><td>62,337</td></tr><tr><td>Taxi</td><td>12,542</td></tr></tbody></table></div></div><div><img src="/_next/static/media/taxi-token-usage.ee5d458c.png" class="rounded-lg lg:h-[510px] lg:w-auto h-auto w-full" style="margin:0;padding:0"/></div></div></div><p>For reference, here’s the same example from above, expressed in Taxi:</p><pre class="language-taxi"><code class="language-taxi"><span class="token keyword">service</span> <span class="token class-name"></span>QuotesApi <span class="token punctuation">{</span>
   <span class="token decorator"><span class="token at operator">@</span><span class="token function">HttpOperation</span></span><span class="token punctuation">(</span>method <span class="token operator">=</span> <span class="token string">&quot;GET&quot;</span><span class="token punctuation">,</span> path <span class="token operator">=</span> <span class="token string">&quot;/quotes/{symbol}&quot;</span><span class="token punctuation">)</span>
   <span class="token keyword">operation</span> <span class="token class-name"></span><span class="token function">getQuote</span><span class="token punctuation">(</span>symbol<span class="token class-name"><span class="token punctuation">:</span>Ticker</span><span class="token punctuation">)</span><span class="token punctuation">:</span>Quote
<span class="token punctuation">}</span>
<span class="token keyword">model</span> <span class="token class-name"></span>Quote <span class="token punctuation">{</span>
   ticker<span class="token punctuation">:</span> com<span class="token punctuation">.</span>bank<span class="token punctuation">.</span>trading<span class="token punctuation">.</span>Ticker
   bid<span class="token punctuation">:</span> com<span class="token punctuation">.</span>bank<span class="token punctuation">.</span>trading<span class="token punctuation">.</span>BidPrice
   ask<span class="token punctuation">:</span> com<span class="token punctuation">.</span>bank<span class="token punctuation">.</span>trading<span class="token punctuation">.</span>AskPrice
<span class="token punctuation">}</span></code></pre><p>However, because we deferred orchestration to TaxiQL, the LLM doesn’t actually need to know about the service definitions,
only the models and types, so the <em>ACTUAL</em> Taxi schemas ended up looking more like this:</p><pre class="language-taxi"><code class="language-taxi"><span class="token keyword">model</span> <span class="token class-name"></span>Quote <span class="token punctuation">{</span>
   ticker<span class="token punctuation">:</span> com<span class="token punctuation">.</span>bank<span class="token punctuation">.</span>trading<span class="token punctuation">.</span>Ticker
   bid<span class="token punctuation">:</span> com<span class="token punctuation">.</span>bank<span class="token punctuation">.</span>trading<span class="token punctuation">.</span>BidPrice
   ask<span class="token punctuation">:</span> com<span class="token punctuation">.</span>bank<span class="token punctuation">.</span>trading<span class="token punctuation">.</span>AskPrice
<span class="token punctuation">}</span></code></pre><p>(That’s 36 tokens vs 177 in the OpenAPI definition)  </p><hr/><h1 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="scoring"><a href="#scoring" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Scoring</span></h1><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="what-we-measured-and-why"><a href="#what-we-measured-and-why" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>What we measured - and why</span></h2><p>We did this research to ask the question:</p><div class="my-6 p-4 bg-slate-800/30 border-l-4 border-sky-500 rounded-r-lg"><p class="text-xl text-slate-200 font-bold leading-relaxed m-0">How good are LLMs at building an orchestration plan that spans multiple APIs?</p></div><p>More specifically - we wanted to ask three questions:</p><ol role="list"><li>How well do LLMs perform at API orchestration when facing real-world complexity (hundreds of endpoints)?</li><li>Does adding semantic metadata improve their accuracy?</li><li>Does the adoption of a declarative orchestration language (specifically TaxiQL) make a difference?</li></ol><h3 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="disclosures"><a href="#disclosures" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Disclosures</span></h3><p>It’s important to be transparent about motivations - we did this research specifically because we’re investing in building in this area,
and want to be sure that we’re both:</p><ol type="a"><li>addressing a problem that actually exists, and</li><li>proposing a solution that works</li></ol><p>However, we took care to test in a balanced way.</p><p>We didn’t give specialized training or prompting for the alternative approaches we were testing
(which were adding a semantic layer, and using a declarative orchestration language — specifically TaxiQL).</p><p>Independently of the main research, we also tested how well the LLMs could produce real compiling TaxiQL queries. For this we <em>did</em> use specialized prompts (and we’re
continuing to iterate them), but we’ve called these out separately in the research results.</p><h3 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="how-we-measured"><a href="#how-we-measured" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>How we measured</span></h3><p>The agents were measured against 4 criteria:</p><ul role="list"><li><strong>API Flow</strong> - The agents had to pick the correct 5 endpoints (path and verb), and sequence them in the correct order</li><li><strong>Correct Identifier</strong> - Multiple ID schemes were used. The agents had to recognize this, and call an API endpoint to swap IDs, passing in and reading out the correct fields</li><li><strong>Business logic</strong> - Agents needed to describe (but not implement) how data from API responses would be used to implement business logic checks, or to pass to the next API call</li><li><strong>Robustness</strong> - Data is messy - nulls and partial records exist — agents needed to describe how they’d handle this</li></ul><p>Importantly:</p><ul role="list"><li><strong>Agents only had to build an accurate plan.</strong> If they produced code, they weren’t penalized if the code didn’t compile.</li></ul><p>To score:</p><ul role="list"><li>A scoring sheet defined the key elements agents needed to articulate</li><li>We used multiple LLMs as judges in a multi-stage review process: <ul role="list"><li>Two separate LLMs scored the output against the scoring sheet (GPT-5.1 and Gemini-2.5 Pro)</li><li>Both scoring results were sent back to an LLM to critique and refine the scores (Gemini-2.5-Pro)</li></ul></li><li>The first LLM reviewed critiques and had the opportunity to adjust its scores (GPT-5.1)</li></ul><p>Each scenario was run and scored 30 times, and the scores were averaged</p><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="summary"><a href="#summary" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Summary</span></h2><p>Our research shows that AI agents need a semantic layer to operate reliably in enterprise environments. </p><p>Without it, accuracy degrades to unusable levels as API complexity grows - exactly the conditions agents will face in production.</p><p>The encouraging result is that even minimal semantic metadata improves outcomes, and moving orchestration into a declarative layer (TaxiQL) improved planning accuracy substantially while reducing token consumption.</p><p>Both Taxi and TaxiQL are open source, making this approach accessible to any organization.
Taxi is designed to be interoperable with existing schema languages, so you can start adding semantic metadata to your <a href="/docs/describing-data-sources/open-api">OpenAPI</a>, <a href="/docs/data-formats/avro">Avro</a>, <a href="/docs/describing-data-sources/soap">SOAP</a>, or <a href="/docs/describing-data-sources/protobuf">Protobuf</a> specs now - without retooling.</p><p>If you’d like to discuss applying this approach in your environment, join us on <a href="https://join.slack.com/t/orbitalapi/shared_invite/zt-697laanr-DHGXXak5slqsY9DqwrkzHg">Slack</a> or reach out by <a href="mailto:hello@orbitalhq.com">Email</a>. Or you can simply <a href="/docs">try Orbital</a> now.</p><p><em>(The post <a href="https://orbitalhq.com/blog/2026-01-20-agentic-orchestration-research-paper">Benchmarking LLM Accuracy in Real-World API Orchestration</a> appeared first on <a href="https://orbitalhq.com/blog">Orbital Blog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/api/og?path=/blog/2026-01-20-agentic-orchestration-research-paper" length="0" type="image//api/og"/>
        </item>
        <item>
            <title><![CDATA[Is Orbital a Data Mesh?]]></title>
            <link>https://orbitalhq.com/blog/2025-06-16-is-orbital-a-data-mesh</link>
            <guid>Is Orbital a Data Mesh?</guid>
            <pubDate>Tue, 17 Jun 2025 19:00:00 GMT</pubDate>
            <description><![CDATA[We're often asked if Orbital is a Data Mesh - and the answer is "kinda." It depends on what you consider a data mesh. Let's dive in.]]></description>
            <content:encoded><![CDATA[<p><em>We’re often asked if Orbital implements a data mesh. It’s a fair question - and the answer depends on how you define “data mesh.”</em></p><p>Depending on how you found this blog post, there’s a strong chance you know what a Data mesh is, but may be less familiar with Orbital.</p><p>Orbital is a data integration platform that works across your entire stack - APIs, databases, and streams.</p><p>However, Orbital is a wee bit different from yer average iPAAS - it’s built around semantic metadata instead of complex pipelines. </p><p>Teams define what they need using plain business terms; Orbital handles the wiring and policy enforcement automatically.</p><p>Think of Orbital as:</p><ul role="list"><li><strong>dbt, for APIs and streams (and DBs too)</strong> - transforming data across operational systems, not just SQL warehouses</li><li><strong>MuleSoft without the laborious manual orchestration</strong> - automated API orchestration and integration</li><li><strong>GraphQL Federation across all data sources</strong> - without resolvers to maintain, or a single uber-graph that breaks</li></ul><p>Unlike traditional integration tools that help you <em>write</em> integration code, Orbital <em>eliminates</em> the need for it entirely.</p><p>Teams work independently, defining data contracts in Git using standard workflows. Orbital discovers and connects these distributed sources automatically.</p><p>Given this automated, decentralized approach, we often get asked: <em>“Is Orbital a data mesh?”</em></p><p>Let’s unpack that question with a little architectural honesty.</p><hr/><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="shared-goals"><a href="#shared-goals" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Shared Goals</span></h2><p>Orbital and data mesh share the same aspirations:</p><ul role="list"><li><strong>Treat data as a product</strong></li><li><strong>Decentralize ownership</strong> to the teams closest to the data</li><li><strong>Enable self-service discovery and delivery</strong></li><li><strong>Ensure governance, quality, and interoperability</strong></li></ul><p>However, we didn’t set out to build a data mesh platform - so even though we share a bunch of the same goals, Orbital’s ended up a slightly different take.</p><hr/><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="where-orbital-delivers-against-data-mesh"><a href="#where-orbital-delivers-against-data-mesh" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Where Orbital delivers against Data Mesh</span></h2><h3 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="decentralized-ownership-through-git"><a href="#decentralized-ownership-through-git" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Decentralized ownership through Git</span></h3><p>In many mesh architectures, decentralization is achieved by handing infrastructure, pipelines, and release cycles to individual teams - often with lots of tooling variation.</p><p>In Orbital, decentralization happens through <strong>standard GitOps workflows</strong>:</p><ul role="list"><li>Each team owns their repo</li><li>They define data products using <strong>TaxiQL</strong> and metadata annotations</li><li>They decide when to publish by merging to their nominated “production” branch</li></ul><p><strong>No central bottleneck. No handoff to a data engineering team.</strong></p><p><strong>Example:</strong> A sales team defines a <code>CustomerRevenue</code> product in their Git repo.
They specify that only finance can access raw salary fields. Once merged, Orbital enforces those access rules automatically - across SQL views, APIs, and Kafka streams.</p><h3 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="favor-declarative-shared-semantic-definitions-over-custom-code"><a href="#favor-declarative-shared-semantic-definitions-over-custom-code" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Favor declarative, shared semantic definitions over custom code</span></h3><p>Orbital replaces pipelines with metadata. Data products are defined declaratively and generated automatically.</p><p>This enables:</p><ul role="list"><li><strong>Business ownership</strong> of what a product is</li><li><strong>Engineering alignment</strong> through GitOps, versioning, and reviews</li></ul><p>Teams don’t wire up Flink jobs or Spark DAGs. They define what they need in plain terms. Orbital figures out how to deliver it.</p><p>Getting into the detail is beyond this post, so if this part piqued you’re interest, here’s a few videos that you can douse your eyeballs with:</p><ul role="list"><li><a href="/blog/2025-05-01-avoiding-breaking-changes-using-semantic-metadata">Avoiding breaking changes using semantic metadata</a></li><li><a href="https://www.youtube.com/watch?v=4bO2O999q44&amp;t=13s">YOW Conference 2024 - Building API layers that build themselves</a></li><li><a href="https://www.youtube.com/watch?v=VjaM0l55Inc">Adaptive Architectures</a></li></ul><hr/><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="governance-designed-decentralized-enforced-globally"><a href="#governance-designed-decentralized-enforced-globally" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Governance: Designed decentralized, enforced globally</span></h2><h3 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="what-does-federated-governance-actually-mean-in-data-mesh"><a href="#what-does-federated-governance-actually-mean-in-data-mesh" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>What does &quot;federated governance&quot; actually mean in data mesh?</span></h3><p>In theory, “Federated Governance” means domain teams define their own governance rules - such as data access, quality checks, and naming conventions - while a platform team provides shared tools and support.</p><p>In practice, that often leads to fragmentation:</p><ul role="list"><li>Teams define policies inconsistently</li><li>Rules are duplicated or conflict across domains</li><li>Enforcement is brittle or absent</li></ul><h3 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="orbital-s-federated-governance-strong-in-some-areas-gaps-in-others"><a href="#orbital-s-federated-governance-strong-in-some-areas-gaps-in-others" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Orbital&#x27;s federated governance: strong in some areas, gaps in others</span></h3><p><strong>Where Orbital excels:</strong></p><p><strong>Data authorization</strong>: Teams define access policies using semantic annotations in Git. These rules are enforced automatically and globally - across APIs, queries, and streams.</p><blockquote><p> <strong>Example:</strong> A team declares that only HR can view <code>Salary</code>. That rule applies automatically anywhere salary appears - no matter who published the product.</p></blockquote><p><strong>GitOps workflows</strong>: Teams use standard Git practices (PRs, reviews, branching) to federate governance around schema changes, policy updates, and data product definitions.</p><p><strong>Lineage tracking</strong>: Traditional data mesh implementations require teams to manually document lineage as part of their data product pipelines - a process that’s error-prone and quickly becomes stale.</p><p>Orbital captures lineage automatically at runtime as queries execute and data flows between services. This ensures lineage always reflects what actually happened, not what was designed on paper. Teams get accurate, up-to-date lineage without the maintenance overhead.</p><blockquote><p>This is computational governance at its best: federated by design (each team’s data products contribute to the overall lineage graph), but captured and enforced automatically by the platform.</p></blockquote><p><strong>Where Orbital has gaps today:</strong></p><ul role="list"><li><strong>Data quality enforcement</strong>: No built-in framework for teams to define and enforce quality rules (planned for future releases)</li><li><strong>SLA monitoring</strong>: No federated approach to defining or enforcing performance guarantees across data products</li><li><strong>Schema governance</strong>: Limited tooling for teams to define domain-specific naming conventions or structural standards</li></ul><p>The result? Orbital delivers strong federated governance for access control, development workflows and lineage - but still requires external tools or manual processes for other governance concerns.</p><hr/><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="self-serve-infrastructure"><a href="#self-serve-infrastructure" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Self-serve infrastructure</span></h2><p>One of the core principles of data mesh is <strong>self-serve infrastructure as a platform</strong> - enabling teams to build and publish data products without relying on central data engineering.</p><p>Orbital strongly supports this:</p><p><strong>Teams can:</strong></p><ul role="list"><li>Define products in Git using simple metadata</li><li>Deploy those products over API (or as pipelines) simply by committing to Git</li><li>Use Orbital’s browser-based editor to browse, author and deploy data products</li><li>Discover and explore available products in a self-updating catalog</li></ul><p><strong>Orbital automates:</strong></p><ul role="list"><li>API, SQL, and stream integration</li><li>Catalog population and lineage tracking</li><li>Access policy enforcement</li></ul><p>Data integration happens automatically, without requiring coordination between teams.</p><blockquote><p>This is infrastructure as a platform - without having to learn Airflow or build DAGs.</p></blockquote><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="where-orbital-differs-from-traditional-mesh-tooling"><a href="#where-orbital-differs-from-traditional-mesh-tooling" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Where Orbital differs from traditional mesh tooling</span></h2><p>Orbital doesn’t expose low-level orchestration tooling directly. Teams don’t:</p><ul role="list"><li>Write Airflow DAGs</li><li>Build Spark jobs</li><li>Manually configure Kafka pipelines</li></ul><p>Instead, they define what the product should look like, and Orbital handles how it’s delivered -
automating integration and orchestration beneath the surface.</p><p>To be clear: this doesn’t actually contradict data mesh principles at all - it simply diverges from the tools people commonly reach for.</p><p>Zhamak has been vocal that data mesh isn’t about pipelines - it’s about intent, ownership, and interoperability.</p><p>While many teams have implemented mesh with Airflow or Spark,
Orbital takes a different path. We deliver the same outcomes with less complexity, by
raising the level of abstraction.</p><p>That’s a simplification - and a strength. It avoids the complexity and
inconsistency of DIY mesh implementations while still giving teams ownership
over semantics, policy, and product lifecycles.</p><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="open-source-and-technology-agnostic"><a href="#open-source-and-technology-agnostic" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Open Source and Technology Agnostic</span></h2><p>Taxi, the data product language that powers Orbital, serves dual purposes:
it’s both a <strong>query language</strong> for discovering data products and a <strong>metadata language</strong> for publishing
semantic information about APIs and data sources.</p><p>Taxi works alongside - not in place of - your existing definitions:</p><ul role="list"><li>Extend OpenAPI, Protobuf, Avro, and even legacy SOAP contracts</li><li>Add semantic meaning to your existing data without a full rewrite</li><li>Focus on <strong>what data means</strong>, not just how it’s structured</li></ul><p>This schema-agnostic approach enables true <strong>semantic interoperability</strong> - the loose coupling that’s essential for Data Mesh success.</p><p><strong>The core engine is Apache 2 licensed</strong>: The Taxi language, query engine, and execution engine are all open source and available on GitHub. </p><p>Orbital itself is <strong>Fair Source</strong> and also available on GitHub. Teams can work in whatever stack they prefer while Orbital provides the unifying layer.</p><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="analytics-vs-operational-data-where-data-mesh-draws-unnecessary-lines"><a href="#analytics-vs-operational-data-where-data-mesh-draws-unnecessary-lines" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Analytics vs. operational data: where data mesh draws unnecessary lines</span></h2><p>The early Data Mesh literature made the somewhat puzzling decision to limit its principles exclusively to analytical data.</p><p>This artificial boundary creates unnecessary silos between operational and analytical systems - exactly the kind of fragmentation that data mesh supposedly aims to solve.</p><p>Orbital takes no such stance. We’re used by both analytics and operations teams across the same organizations:</p><ul role="list"><li><strong>Analytics teams</strong> use Orbital to power batch data jobs for ML pipelines and data science workflows</li><li><strong>Operations teams</strong> use Orbital to federate APIs and databases into real-time services powering some of the largest banks in the world</li></ul><p>The underlying challenges - data discovery, semantic alignment, governance, and integration complexity - are identical whether you’re building a quarterly sales report or a real-time fraud detection system. Why artificially limit solutions to only half the problem?</p><p>While the Data Mesh community has chosen this hill to die on, we see it as a false dichotomy. </p><p>Good data architecture principles should work across the entire data spectrum.</p><hr/><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="tl-dr"><a href="#tl-dr" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>TL;DR</span></h2><p>Orbital isn’t a data mesh by the book. But it aligns closely with its four foundational principles:</p><ul role="list"><li><strong>Domain-oriented ownership</strong> - Teams manage their own products via Git, with full lifecycle control</li><li><strong>Data as a product</strong> - Products have contracts, owners, and real consumers</li><li><strong>Self-serve infrastructure</strong> - No pipeline authoring needed - Orbital automates delivery</li><li><strong>Federated governance</strong> - Policies are defined decentrally, and enforced globally</li></ul><p>And one bonus principle:</p><ul role="list"><li><strong>Technology-agnostic</strong> - Taxi integrates with your existing schemas, rather than replacing them</li></ul><blockquote><p>You get the <strong>outcomes of data mesh</strong> - without the overhead of implementing one.</p></blockquote><p>So is Orbital a data mesh?</p><p><strong>Kinda.</strong></p><p>Orbital delivers the goals of data mesh - but in a way that’s actually usable, scalable, and maintainable.</p><p><em>(The post <a href="https://orbitalhq.com/blog/2025-06-16-is-orbital-a-data-mesh">Is Orbital a Data Mesh?</a> appeared first on <a href="https://orbitalhq.com/blog">Orbital Blog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/api/og?path=/blog/2025-06-16-is-orbital-a-data-mesh" length="0" type="image//api/og"/>
        </item>
        <item>
            <title><![CDATA[Avoiding breaking changes using Semantic Metadata]]></title>
            <link>https://orbitalhq.com/blog/2025-05-01-avoiding-breaking-changes-using-semantic-metadata</link>
            <guid>Avoiding breaking changes using Semantic Metadata</guid>
            <pubDate>Thu, 01 May 2025 19:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>Let’s explore how semantic metadata (like Taxi) lets you decouple producers &amp; consumers, so changes made to APIs don’t have to be breaking.</p><iframe width="560" height="315" src="https://www.youtube.com/embed/aCp1WBuR5E8?si=BsSAxleONxyJWwQj" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin"></iframe><p><em>(The post <a href="https://orbitalhq.com/blog/2025-05-01-avoiding-breaking-changes-using-semantic-metadata">Avoiding breaking changes using Semantic Metadata</a> appeared first on <a href="https://orbitalhq.com/blog">Orbital Blog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/_next/static/media/title-card.b44ffc5b.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Orbital partners with Ultumus to redefine market data integration]]></title>
            <link>https://orbitalhq.com/blog/2023-11-30-ultumus-partnership</link>
            <guid>Orbital partners with Ultumus to redefine market data integration</guid>
            <pubDate>Thu, 30 Nov 2023 19:00:00 GMT</pubDate>
            <description><![CDATA[We're excited to announce Orbital's partnership with Ultumus, a leader in the benchmark mastering space, with a reputation for rethinking and modernizing market data distribution]]></description>
            <content:encoded><![CDATA[<div class=""><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full mx-auto"><div class=""><img loading="lazy" width="1334" height="738" decoding="async" data-nimg="1" class="rounded-md" style="color:transparent" sizes="(max-width: 1280px) 100vw, 65vw" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fultumus-orbital-light.0c54dd6d.png&amp;w=640&amp;q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fultumus-orbital-light.0c54dd6d.png&amp;w=750&amp;q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fultumus-orbital-light.0c54dd6d.png&amp;w=828&amp;q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fultumus-orbital-light.0c54dd6d.png&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fultumus-orbital-light.0c54dd6d.png&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fultumus-orbital-light.0c54dd6d.png&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fultumus-orbital-light.0c54dd6d.png&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fultumus-orbital-light.0c54dd6d.png&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fultumus-orbital-light.0c54dd6d.png&amp;w=3840&amp;q=75"/><div class="text-center text-slate-500 mt-[1rem]"></div></div></div></div><p>We’re excited to announce Orbital’s partnership with Ultumus, a leader in the benchmark mastering space, with a reputation for rethinking and modernizing market data distribution.
Our collaboration is set to shake up the traditional market data landscape, making it more accessible,
and fair for all.</p><p>Ultumus is on a mission to revolutionize benchmark data service
by providing fair and cost-effective access to
industry leading market data. Orbital is delighted to
support this mission, by using our advanced integration
platform to eliminate the project costs that customers
often face when switching data providers,
leaving them locked into legacy vendors.</p><p>Orbital enables lightning-fast creation of API and data
feed adaptors, backed by comprehensive observability,
lineage, and traceability. Through our partnership, Ultumus
customers now have access to drop-in replacements for
data feeds that emulate existing formats, eliminating the
need for expensive and lengthy migration projects typically
associated with switching vendors.</p><p>Together with Ultumus, we’re paving the way for a more
equitable and efficient market data environment,
ensuring that customers have the freedom to choose
without being burdened by prohibitive costs and complexities.</p><p>Click to learn more about <a href="https://news.ultumus.com/orbital-partnership">Ultumus benchmark data</a> or how <a href="https://orbitalhq.com">Orbital can help with your data integration</a></p><p><em>(The post <a href="https://orbitalhq.com/blog/2023-11-30-ultumus-partnership">Orbital partners with Ultumus to redefine market data integration</a> appeared first on <a href="https://orbitalhq.com/blog">Orbital Blog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/api/og?path=/blog/2023-11-30-ultumus-partnership" length="0" type="image//api/og"/>
        </item>
        <item>
            <title><![CDATA[Quickly modernizing SOAP APIs]]></title>
            <link>https://orbitalhq.com/blog/2023-09-04-modernizing-soap-apis</link>
            <guid>Quickly modernizing SOAP APIs</guid>
            <pubDate>Mon, 04 Sep 2023 19:00:00 GMT</pubDate>
            <description><![CDATA[Using Taxi and Orbital to recompose SOAP APIs to something a little cleaner]]></description>
            <content:encoded><![CDATA[<div class=""><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full mx-auto"><div class=""><img loading="lazy" width="1456" height="816" decoding="async" data-nimg="1" class="rounded-md" style="color:transparent" sizes="(max-width: 1280px) 100vw, 65vw" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fsoap-robot.160459fb.png&amp;w=640&amp;q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fsoap-robot.160459fb.png&amp;w=750&amp;q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fsoap-robot.160459fb.png&amp;w=828&amp;q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fsoap-robot.160459fb.png&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fsoap-robot.160459fb.png&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fsoap-robot.160459fb.png&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fsoap-robot.160459fb.png&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fsoap-robot.160459fb.png&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fsoap-robot.160459fb.png&amp;w=3840&amp;q=75"/><div class="text-center text-slate-500 mt-[1rem]"></div></div></div></div><p>If you’ve ever had to work with SOAP APIs, you know how unpleasant they can be.</p><p>They’re cumbersome to call, have heavy amounts of code-gen required, and if you’re not using Java or C#… you’re already kinda screwed.</p><p>We’re gonna to take an old SOAP APIs (which, lets face it, aren’t fun to play with), and repackage it, combining multiple calls into a single REST API.</p><p>Instead of writing piles of boilerplate plumbing code, we’ll automate all the integration work with Orbital and <a href="https://taxilang.org">Taxi</a> to annotate the SOAP APIs.</p><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="taxi-a-quick-intro"><a href="#taxi-a-quick-intro" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Taxi - A quick intro</span></h2><p><a href="https://taxilang.org">Taxi</a> is a relatively new entrant in the API space.  It’s goal is to let developers add simple, (but type-safe) <a href="https://orbitalhq.com/blog/2023-05-22-semantic-metadata-101">tags</a> into their APIs, so software can understand how different APIs relate to one another.</p><p>It’s a simple way of saying “This field is the same as that field”, while keeping systems decoupled.</p><p>And the same tags we add into our APIs, we can use to query for data using TaxiQL - Taxi’s query language - which replaces all the integration plubming code we’d normally have to write.</p><p>Let’s go a little deeper, and break that down into three steps:</p><ol role="list"><li>Adding Taxi metadata to the SOAP WSDL (<a href="/docs/describing-data-sources/soap">here’s</a> the relevant docs)</li><li>Using <a href="/docs/querying/writing-queries">Taxi queries</a> to build the responses we want to return</li><li>Publishing those queries as REST APIs</li></ol><p>The code for this blog is available on <a href="https://github.com/orbitalapi/demos/tree/main/soap-demo">Github</a></p><div class="my-12 flex rounded-lg p-px bg-gradient-to-b from-sky-400 to-sky-700"><div class="bg-slate-800 rounded-lg p-4 w-full h-full"><div class="flex-auto"><div class="prose text-sky-800 [--tw-prose-background:theme(colors.sky.50)] prose-a:text-sky-900 prose-code:text-sky-900 dark:text-slate-300 dark:prose-code:text-slate-300">If you find this tutorial useful, why not give us a star on <a href="https://github.com/orbitalapi/orbital" target="_blank">Github</a></div></div></div></div><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="background"><a href="#background" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Background</span></h2><p>We’re working with a public webservice at <a href="http://webservices.oorsprong.org/websamples.countryinfo/CountryInfoService.wso">Oorsprong.org</a> that provides Country Information.</p><p>There’s lots of different services, which return small slices of information about countries, given an ISO code.</p><p>We’d like to grab the data of a few of these services, but without having to write a bunch of SOAP code.</p><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="adding-taxi-metadata-to-soap"><a href="#adding-taxi-metadata-to-soap" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Adding Taxi Metadata to SOAP</span></h2><p>Taxi metadata allows us to sprinkle a few additional tags into our WSDL which let mark data attributes that are the same.</p><p>For example, our CountryInfo wsdl has a section dedicated to request / response payloads.</p><div class="mt-5 mb-8 first:mt-0 last:mb-0 pt-2 bg-slate-800 rounded-xl shadow-lg overflow-hidden dark:ring-1 dark:ring-white/10 dark:ring-inset"><div class="flex text-slate-400 text-xs leading-6"><div class="flex-none text-sky-300 border-t border-b border-t-transparent border-b-sky-300 px-4 py-1 flex items-center">Countries.wsdl</div><div class="flex-auto flex items-center bg-slate-700/50 border border-slate-500/30 rounded-tl"></div></div><div class="children:my-0 children:!shadow-none children:bg-transparent"><pre class="language-xml"><code class="language-xml"><span class="token block"><span class="token comment">&lt;!-- Snippet from our WSDL - Request / Response messages for getting a Country Name --&gt;</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag namespace">xs:</span><span class="token tag">element</span><span class="token tag"> </span><span class="token tag attr-name">name</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag attr-value">CountryName</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">    </span><span class="token tag punctuation">&lt;</span><span class="token tag namespace">xs:</span><span class="token tag">complexType</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">       </span><span class="token tag punctuation">&lt;</span><span class="token tag namespace">xs:</span><span class="token tag">sequence</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">          </span><span class="token tag punctuation">&lt;</span><span class="token tag namespace">xs:</span><span class="token tag">element</span><span class="token tag"> </span><span class="token tag attr-name">name</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag attr-value">sCountryISOCode</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag"></span>
</span><span class="token tag block">                 <span class="token attr-name">type</span><span class="token attr-value punctuation attr-equals">=</span><span class="token attr-value punctuation">&quot;</span><span class="token attr-value">xs:string</span><span class="token attr-value punctuation">&quot;</span> 
</span><span class="token block -mx-5 pl-4 pr-5 border-l-4 border-sky-400 bg-sky-300/[0.15]"><span class="token tag">                 </span><span class="token tag attr-name namespace">taxi:</span><span class="token tag attr-name">type</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag attr-value">com.demo.IsoCountryCode</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag punctuation">/&gt;</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">       </span><span class="token tag punctuation">&lt;/</span><span class="token tag namespace">xs:</span><span class="token tag">sequence</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">    </span><span class="token tag punctuation">&lt;/</span><span class="token tag namespace">xs:</span><span class="token tag">complexType</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain"> </span><span class="token tag punctuation">&lt;/</span><span class="token tag namespace">xs:</span><span class="token tag">element</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag namespace">xs:</span><span class="token tag">element</span><span class="token tag"> </span><span class="token tag attr-name">name</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag attr-value">CountryNameResponse</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">    </span><span class="token tag punctuation">&lt;</span><span class="token tag namespace">xs:</span><span class="token tag">complexType</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">       </span><span class="token tag punctuation">&lt;</span><span class="token tag namespace">xs:</span><span class="token tag">sequence</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">         </span><span class="token tag punctuation">&lt;</span><span class="token tag namespace">xs:</span><span class="token tag">element</span><span class="token tag"> </span><span class="token tag attr-name">name</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag attr-value">CountryNameResult</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag"> </span>
</span><span class="token tag block">             <span class="token attr-name">type</span><span class="token attr-value punctuation attr-equals">=</span><span class="token attr-value punctuation">&quot;</span><span class="token attr-value">xs:string</span><span class="token attr-value punctuation">&quot;</span> 
</span><span class="token block -mx-5 pl-4 pr-5 border-l-4 border-sky-400 bg-sky-300/[0.15]"><span class="token tag">             </span><span class="token tag attr-name namespace">taxi:</span><span class="token tag attr-name">type</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag attr-value">com.demo.CountryName</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag punctuation">/&gt;</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">       </span><span class="token tag punctuation">&lt;/</span><span class="token tag namespace">xs:</span><span class="token tag">sequence</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">    </span><span class="token tag punctuation">&lt;/</span><span class="token tag namespace">xs:</span><span class="token tag">complexType</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain"> </span><span class="token tag punctuation">&lt;/</span><span class="token tag namespace">xs:</span><span class="token tag">element</span><span class="token tag punctuation">&gt;</span>
</span></code></pre></div></div><p>You can summarize this by saying:</p><blockquote><p>I can send a <code>CountryName</code> request containing a <code>com.demo.IsoCountryCode</code>, and I’ll get back a message
containing a <code>com.demo.CountryName</code></p></blockquote><p>Elsewhere, we can also use a <code>IsoCountryCode</code> to get more information, like a CountryFlagUrl:</p><div class="mt-5 mb-8 first:mt-0 last:mb-0 pt-2 bg-slate-800 rounded-xl shadow-lg overflow-hidden dark:ring-1 dark:ring-white/10 dark:ring-inset"><div class="flex text-slate-400 text-xs leading-6"><div class="flex-none text-sky-300 border-t border-b border-t-transparent border-b-sky-300 px-4 py-1 flex items-center">Countries.wsdl</div><div class="flex-auto flex items-center bg-slate-700/50 border border-slate-500/30 rounded-tl"></div></div><div class="children:my-0 children:!shadow-none children:bg-transparent"><pre class="language-xml"><code class="language-xml"><span class="token block"><span class="token tag punctuation">&lt;</span><span class="token tag namespace">xs:</span><span class="token tag">element</span><span class="token tag"> </span><span class="token tag attr-name">name</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag attr-value">CountryFlag</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">    </span><span class="token tag punctuation">&lt;</span><span class="token tag namespace">xs:</span><span class="token tag">complexType</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">       </span><span class="token tag punctuation">&lt;</span><span class="token tag namespace">xs:</span><span class="token tag">sequence</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">          </span><span class="token tag punctuation">&lt;</span><span class="token tag namespace">xs:</span><span class="token tag">element</span><span class="token tag"> </span><span class="token tag attr-name">name</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag attr-value">sCountryISOCode</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag"> </span>
</span><span class="token tag block">              <span class="token attr-name">type</span><span class="token attr-value punctuation attr-equals">=</span><span class="token attr-value punctuation">&quot;</span><span class="token attr-value">xs:string</span><span class="token attr-value punctuation">&quot;</span> 
</span><span class="token block -mx-5 pl-4 pr-5 border-l-4 border-sky-400 bg-sky-300/[0.15]"><span class="token tag">              </span><span class="token tag attr-name namespace">taxi:</span><span class="token tag attr-name">type</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag attr-value">com.demo.IsoCountryCode</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag punctuation">/&gt;</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">       </span><span class="token tag punctuation">&lt;/</span><span class="token tag namespace">xs:</span><span class="token tag">sequence</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">    </span><span class="token tag punctuation">&lt;/</span><span class="token tag namespace">xs:</span><span class="token tag">complexType</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain"> </span><span class="token tag punctuation">&lt;/</span><span class="token tag namespace">xs:</span><span class="token tag">element</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag namespace">xs:</span><span class="token tag">element</span><span class="token tag"> </span><span class="token tag attr-name">name</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag attr-value">CountryFlagResponse</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">    </span><span class="token tag punctuation">&lt;</span><span class="token tag namespace">xs:</span><span class="token tag">complexType</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">       </span><span class="token tag punctuation">&lt;</span><span class="token tag namespace">xs:</span><span class="token tag">sequence</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">          </span><span class="token tag punctuation">&lt;</span><span class="token tag namespace">xs:</span><span class="token tag">element</span><span class="token tag"> </span><span class="token tag attr-name">name</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag attr-value">CountryFlagResult</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag"> </span>
</span><span class="token tag block">                  <span class="token attr-name">type</span><span class="token attr-value punctuation attr-equals">=</span><span class="token attr-value punctuation">&quot;</span><span class="token attr-value">xs:string</span><span class="token attr-value punctuation">&quot;</span>  
</span><span class="token block -mx-5 pl-4 pr-5 border-l-4 border-sky-400 bg-sky-300/[0.15]"><span class="token tag">                  </span><span class="token tag attr-name namespace">taxi:</span><span class="token tag attr-name">type</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag attr-value">com.demo.CountryFlagUrl</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag punctuation">/&gt;</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">       </span><span class="token tag punctuation">&lt;/</span><span class="token tag namespace">xs:</span><span class="token tag">sequence</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain">    </span><span class="token tag punctuation">&lt;/</span><span class="token tag namespace">xs:</span><span class="token tag">complexType</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span>
</span><span class="token block"><span class="token plain"> </span><span class="token tag punctuation">&lt;/</span><span class="token tag namespace">xs:</span><span class="token tag">element</span><span class="token tag punctuation">&gt;</span>
</span></code></pre></div></div><p>That’s a whole lotta XML, for not much info - which is one of the problems with SOAP - it’s just too darn noisy.</p><div class=""><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full mx-auto"><div class=""><img loading="lazy" width="498" height="286" decoding="async" data-nimg="1" class="rounded-md" style="color:transparent" sizes="(max-width: 1280px) 100vw, 65vw" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fthats-too-much-man-sarah-lynn.e95e3c1c.gif&amp;w=640&amp;q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fthats-too-much-man-sarah-lynn.e95e3c1c.gif&amp;w=750&amp;q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fthats-too-much-man-sarah-lynn.e95e3c1c.gif&amp;w=828&amp;q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fthats-too-much-man-sarah-lynn.e95e3c1c.gif&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fthats-too-much-man-sarah-lynn.e95e3c1c.gif&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fthats-too-much-man-sarah-lynn.e95e3c1c.gif&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fthats-too-much-man-sarah-lynn.e95e3c1c.gif&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fthats-too-much-man-sarah-lynn.e95e3c1c.gif&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fthats-too-much-man-sarah-lynn.e95e3c1c.gif&amp;w=3840&amp;q=75"/><div class="text-center text-slate-500 mt-[1rem]"></div></div></div></div><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="using-taxi-queries-to-get-the-data-we-want"><a href="#using-taxi-queries-to-get-the-data-we-want" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Using Taxi queries to get the data we want</span></h2><p>Now that our WSDL is annotated with Taxi, we can get Orbital to do all the heavy lifting for us.</p><p>Rather than generating a bunch of Java classes from the WSDL, we can simply write a taxi query:</p><pre class="language-taxi"><code class="language-taxi"><span class="token keyword">given</span> <span class="token punctuation">{</span> iso<span class="token class-name"><span class="token punctuation">:</span> IsoCountryCode</span> <span class="token operator">=</span> <span class="token string">&quot;NZ&quot;</span><span class="token punctuation">}</span>
<span class="token keyword">find</span> <span class="token punctuation">{</span> 
    <span class="token comment">// Each field comes from a different SOAP service.</span>
    <span class="token comment">// But taxi keeps this nice and succinct, composing the services</span>
    <span class="token comment">// together we need on demand</span>
    name<span class="token class-name"><span class="token punctuation">:</span> CountryName</span>
    flag<span class="token class-name"><span class="token punctuation">:</span> CountryFlagUrl</span>
    currency<span class="token class-name"><span class="token punctuation">:</span> CurrencyName</span>
 <span class="token punctuation">}</span></code></pre><p>We can send that query to Orbital, and Orbital calls all the SOAP services we need on our behalf, giving us back the data we’re looking for:</p><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
   <span class="token property">&quot;name&quot;</span><span class="token operator">:</span> <span class="token string">&quot;New Zealand&quot;</span><span class="token punctuation">,</span>
   <span class="token property">&quot;flag&quot;</span><span class="token operator">:</span> <span class="token string">&quot;http://www.oorsprong.org/WebSamples.CountryInfo/Flags/New_Zealand.jpg&quot;</span><span class="token punctuation">,</span>
   <span class="token property">&quot;currency&quot;</span><span class="token operator">:</span> <span class="token string">&quot;New Zealand Dollars&quot;</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span></code></pre><p>Orbital’s profiler shows us exactly what happened:</p><div class=""><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full mx-auto"><div class=""><img alt="Orbital&#x27;s profiler shows the sequence of calls issued to load the data we needed" loading="lazy" width="1190" height="652" decoding="async" data-nimg="1" class="rounded-md" style="color:transparent" sizes="(max-width: 1280px) 100vw, 65vw" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fsequence.cf5e3f9b.png&amp;w=640&amp;q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fsequence.cf5e3f9b.png&amp;w=750&amp;q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fsequence.cf5e3f9b.png&amp;w=828&amp;q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fsequence.cf5e3f9b.png&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fsequence.cf5e3f9b.png&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fsequence.cf5e3f9b.png&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fsequence.cf5e3f9b.png&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fsequence.cf5e3f9b.png&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fsequence.cf5e3f9b.png&amp;w=3840&amp;q=75"/><div class="text-center text-slate-500 mt-[1rem]">Orbital&#x27;s profiler shows the sequence of calls issued to load the data we needed</div></div></div></div><p>And we can drill into the details of each call too:</p><div class=""><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full mx-auto"><div class=""><img alt="Drilling into each call shows the request and response" loading="lazy" width="1350" height="1070" decoding="async" data-nimg="1" class="rounded-md" style="color:transparent" sizes="(max-width: 1280px) 100vw, 65vw" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fcall-details.a2adcc43.png&amp;w=640&amp;q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fcall-details.a2adcc43.png&amp;w=750&amp;q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fcall-details.a2adcc43.png&amp;w=828&amp;q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fcall-details.a2adcc43.png&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fcall-details.a2adcc43.png&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fcall-details.a2adcc43.png&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fcall-details.a2adcc43.png&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fcall-details.a2adcc43.png&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fcall-details.a2adcc43.png&amp;w=3840&amp;q=75"/><div class="text-center text-slate-500 mt-[1rem]">Drilling into each call shows the request and response</div></div></div></div><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="instant-rest-api"><a href="#instant-rest-api" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Instant REST API</span></h2><p>Now that we’re happy with the content of our payload, we can quickly turn it into a REST API.</p><p>Simply by checking a query into our project’s git repo, and adding an annotation, Orbital gives us a fully working REST API:</p><div class="mt-5 mb-8 first:mt-0 last:mb-0 pt-2 bg-slate-800 rounded-xl shadow-lg overflow-hidden dark:ring-1 dark:ring-white/10 dark:ring-inset"><div class="flex text-slate-400 text-xs leading-6"><div class="flex-none text-sky-300 border-t border-b border-t-transparent border-b-sky-300 px-4 py-1 flex items-center">CountryData.query.taxi</div><div class="flex-auto flex items-center bg-slate-700/50 border border-slate-500/30 rounded-tl"></div></div><div class="children:my-0 children:!shadow-none children:bg-transparent"><pre class="language-taxi"><code class="language-taxi"><span class="token decorator"><span class="token at operator">@</span><span class="token function">HttpOperation</span></span><span class="token punctuation">(</span>url <span class="token operator">=</span> <span class="token string">&#x27;/api/q/countrydata/{countryCode}&#x27;</span><span class="token punctuation">,</span> method <span class="token operator">=</span> <span class="token string">&#x27;GET&#x27;</span><span class="token punctuation">)</span>
<span class="token keyword">query</span> <span class="token class-name"></span><span class="token function">countrydata</span><span class="token punctuation">(</span><span class="token decorator"><span class="token at operator">@</span><span class="token function">PathVariable</span></span><span class="token punctuation">(</span><span class="token string">&quot;countryCode&quot;</span><span class="token punctuation">)</span> countryCode<span class="token class-name"> <span class="token punctuation">:</span>  IsoCountryCode</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
   <span class="token keyword">given</span> <span class="token punctuation">{</span> countryCode <span class="token punctuation">}</span>
   <span class="token class-name"><span class="token keyword">find</span> <span class="token punctuation">{</span>
       name</span><span class="token class-name"> <span class="token punctuation">:</span> CountryName</span>
       flag<span class="token class-name"><span class="token punctuation">:</span> CountryFlagUrl</span>
       currency<span class="token class-name"><span class="token punctuation">:</span> CurrencyName</span>
       capital<span class="token class-name"><span class="token punctuation">:</span> CapitalCityName</span>
   <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre></div></div><p>By adding a <code>@HttpOperation</code> annotation to our query, and saving it our local Taxi project, Orbital instantly exposes a REST API for us.
Rather than hard-coding our query to information about New Zealand, we’ve put the country code as a part of the path.</p><pre><code>@HttpOperation(url = &#x27;/api/q/countrydata/{countryCode}&#x27;, method = &#x27;GET&#x27;)
</code></pre><p>So, if we call:</p><pre class="language-bash"><code class="language-bash"><span class="token function">curl</span> http://localhost:9022/api/q/countrydata/NZ </code></pre><p>Gives us:</p><pre class="language-json"><code class="language-json"><span class="token punctuation">[</span>
  <span class="token punctuation">{</span>
    <span class="token property">&quot;name&quot;</span><span class="token operator">:</span> <span class="token string">&quot;New Zealand&quot;</span><span class="token punctuation">,</span>
    <span class="token property">&quot;flag&quot;</span><span class="token operator">:</span> <span class="token string">&quot;http://www.oorsprong.org/WebSamples.CountryInfo/Flags/New_Zealand.jpg&quot;</span><span class="token punctuation">,</span>
    <span class="token property">&quot;currency&quot;</span><span class="token operator">:</span> <span class="token string">&quot;New Zealand Dollars&quot;</span><span class="token punctuation">,</span>
    <span class="token property">&quot;capital&quot;</span><span class="token operator">:</span> <span class="token string">&quot;Wellington&quot;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">]</span></code></pre><h3 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="live-reload-for-the-win"><a href="#live-reload-for-the-win" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Live reload for the win</span></h3><div class=""><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full mx-auto"><div class=""><img alt="Instant REST API, that live reloads" loading="lazy" width="500" height="281" decoding="async" data-nimg="1" class="rounded-md" style="color:transparent" sizes="(max-width: 1280px) 100vw, 65vw" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fits-alive.66764a3d.gif&amp;w=640&amp;q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fits-alive.66764a3d.gif&amp;w=750&amp;q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fits-alive.66764a3d.gif&amp;w=828&amp;q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fits-alive.66764a3d.gif&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fits-alive.66764a3d.gif&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fits-alive.66764a3d.gif&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fits-alive.66764a3d.gif&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fits-alive.66764a3d.gif&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fits-alive.66764a3d.gif&amp;w=3840&amp;q=75"/><div class="text-center text-slate-500 mt-[1rem]">Instant REST API, that live reloads</div></div></div></div><p>Orbital is live reloading this query, so while we’re working locally and making changes to our query, changes are instantly deployed!
Once deployed, making changes is as simple as pushing to a git repository.</p><p>Check it out:</p><div class=""><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full mx-auto"><div class=""><img alt="Live reloads" loading="lazy" width="639" height="674" decoding="async" data-nimg="1" class="rounded-md" style="color:transparent" sizes="(max-width: 1280px) 100vw, 65vw" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Flive-reload.f8322c87.gif&amp;w=640&amp;q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Flive-reload.f8322c87.gif&amp;w=750&amp;q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Flive-reload.f8322c87.gif&amp;w=828&amp;q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Flive-reload.f8322c87.gif&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Flive-reload.f8322c87.gif&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Flive-reload.f8322c87.gif&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Flive-reload.f8322c87.gif&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Flive-reload.f8322c87.gif&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Flive-reload.f8322c87.gif&amp;w=3840&amp;q=75"/><div class="text-center text-slate-500 mt-[1rem]">Live reloads</div></div></div></div><p>Adding the <code>CapitalCityName</code> into our request actually added a whole new SOAP request and integration into our query, which Orbital instantly reloaded behind the scenes.</p><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="conclusion"><a href="#conclusion" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Conclusion</span></h2><p>In this blog, we’ve quickly repackaged a SOAP API into the exact API we wanted, without having to deal with any of the nastiness that
normally comes from dealing with SOAP requests.</p><p>In the process, we’ve touched on a few of Orbital’s handy features:</p><ul role="list"><li>Using Taxi metadata in SOAP WSDLs</li><li>Composing together multiple SOAP calls</li><li>Instant REST APIs with live reload</li><li>Viewing profiling data </li></ul><p>The full code to run this demo locally is available on <a href="https://github.com/orbitalapi/demos/tree/main/soap-demo">Github</a></p><p>This is only scratching the surface of what we can do.  Orbital can also stitch this data together with other APIs (such as <a href="https://orbitalhq.com/docs/describing-data-sources/open-api">REST</a> / <a href="https://orbitalhq.com/docs/describing-data-sources/protobuf">gRPC</a>), call <a href="https://orbitalhq.com/docs/describing-data-sources/aws-services#lambda">serverless functions</a>, query our <a href="https://orbitalhq.com/docs/describing-data-sources/databases">Databases</a>, or <a href="https://orbitalhq.com/docs/describing-data-sources/connect-kafka-topic">Kafka queues</a>.</p><p>Remember, if you found this useful, please give our <a href="https://github.com/orbitalapi/orbital">Github repo</a> a star!</p><p><em>(The post <a href="https://orbitalhq.com/blog/2023-09-04-modernizing-soap-apis">Quickly modernizing SOAP APIs</a> appeared first on <a href="https://orbitalhq.com/blog">Orbital Blog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/_next/static/media/soap-robot.160459fb.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Semantic Metadata 101]]></title>
            <link>https://orbitalhq.com/blog/2023-05-22-semantic-metadata-101</link>
            <guid>Semantic Metadata 101</guid>
            <pubDate>Tue, 23 May 2023 19:00:00 GMT</pubDate>
            <description><![CDATA[A lightweight look into Semantic Metadata.]]></description>
            <content:encoded><![CDATA[<p>This post is a lightweight introduction to the concept of Semantic Metadata, and how it makes our enterprise services
automatically composable.</p><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="what-is-semantic-metadata"><a href="#what-is-semantic-metadata" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>What is Semantic Metadata?</span></h2><p>Semantic Metadata is a way of defining a contract around the meaning of data.  It lets teams create terms and definitions they agree on, and use those terms to better describe their APIs and analytics, and make software interoperable.</p><p>Teams can use Semantic metadata to define formal definitions for fields in APIs:</p><ul role="list"><li>“This is what a first name means”,</li><li>“This is what a company name means”</li></ul><p>Analytical platforms such as <a href="https://cube.dev">cube.dev</a> tend to expand this to include shared definitions of aggregates.</p><ul role="list"><li>“This is what a customer is”</li><li>“This is what we mean by ‘Active Customers’”, etc.</li></ul><p>The core idea is that Semantic Metadata is a way for teams to create a shared understanding of what data means, independent of a single specific system.</p><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="building-a-taxonomy"><a href="#building-a-taxonomy" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Building a Taxonomy</span></h2><p>Semantic metadata is really just a collection of terms that describe our business.</p><p>When grouped together, this is called a Taxonomy.</p><div class=""><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full mx-auto bg-slate-800 dark:bg-transparent"><div class=""><img loading="lazy" width="733" height="452" decoding="async" data-nimg="1" class="rounded-md" style="color:transparent" sizes="(max-width: 1280px) 100vw, 65vw" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftaxonomy.7e4947c4.png&amp;w=640&amp;q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftaxonomy.7e4947c4.png&amp;w=750&amp;q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftaxonomy.7e4947c4.png&amp;w=828&amp;q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftaxonomy.7e4947c4.png&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftaxonomy.7e4947c4.png&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftaxonomy.7e4947c4.png&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftaxonomy.7e4947c4.png&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftaxonomy.7e4947c4.png&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftaxonomy.7e4947c4.png&amp;w=3840&amp;q=75"/><div class="text-center text-slate-500 mt-[1rem]"></div></div></div></div><p><a href="https://taxilang.org">Taxi</a> is a language-agnostic tool for building semantic taxonomies:</p><pre class="language-taxi"><code class="language-taxi"><span class="token keyword">type</span> <span class="token class-name"></span>AccountNumber <span class="token keyword">inherits</span> <span class="token class-name"></span>Int
<span class="token keyword">type</span> <span class="token class-name"></span>CreditScore <span class="token keyword">inherits</span> <span class="token class-name"></span><span class="token builtin">Decimal</span>
<span class="token keyword">type</span> <span class="token class-name"></span>FirstName <span class="token keyword">inherits</span> <span class="token class-name"></span><span class="token builtin">String</span>
<span class="token comment">// etc...</span></code></pre><p>Semantic Metadata is designed to be shared across multiple teams.  So, just like with API technologies like OpenAPI, Protobuf, etc - it’s best to have Semantic Metadata designed in a platform agnostic language.</p><p>Generators can then generate bindings / SDKs / tools as required in whichever technology consuming teams are working with.</p><div class=""><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full mx-auto bg-slate-800 dark:bg-transparent"><div class=""><img loading="lazy" width="1133" height="762" decoding="async" data-nimg="1" class="rounded-md" style="color:transparent" sizes="(max-width: 1280px) 100vw, 65vw" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftaxonomy-tooling.40fef68e.png&amp;w=640&amp;q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftaxonomy-tooling.40fef68e.png&amp;w=750&amp;q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftaxonomy-tooling.40fef68e.png&amp;w=828&amp;q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftaxonomy-tooling.40fef68e.png&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftaxonomy-tooling.40fef68e.png&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftaxonomy-tooling.40fef68e.png&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftaxonomy-tooling.40fef68e.png&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftaxonomy-tooling.40fef68e.png&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ftaxonomy-tooling.40fef68e.png&amp;w=3840&amp;q=75"/><div class="text-center text-slate-500 mt-[1rem]"></div></div></div></div><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="embedding-semantic-metadata"><a href="#embedding-semantic-metadata" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Embedding semantic metadata</span></h2><p>On it’s own, semantic metadata isn’t very helpful - it’s just a set of tags and definitions.</p><p>However, embedded in API specs, it becomes much more powerful.</p><p>Here’s an example in OpenAPI:</p><div class="mt-5 mb-8 first:mt-0 last:mb-0 pt-2 bg-slate-800 rounded-xl shadow-lg overflow-hidden dark:ring-1 dark:ring-white/10 dark:ring-inset"><div class="flex text-slate-400 text-xs leading-6"><div class="flex-none text-sky-300 border-t border-b border-t-transparent border-b-sky-300 px-4 py-1 flex items-center">reviews.openapi.yml</div><div class="flex-auto flex items-center bg-slate-700/50 border border-slate-500/30 rounded-tl"></div></div><div class="children:my-0 children:!shadow-none children:bg-transparent"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">openapi</span><span class="token punctuation">:</span> 3.0.1
<span class="token key atrule">info</span><span class="token punctuation">:</span>
  <span class="token key atrule">title</span><span class="token punctuation">:</span> ReviewsApi
  <span class="token key atrule">version</span><span class="token punctuation">:</span> 1.0.0
<span class="token key atrule">paths</span><span class="token punctuation">:</span>
  https<span class="token punctuation">:</span>//reviews/<span class="token punctuation">{</span>id<span class="token punctuation">}</span><span class="token punctuation">:</span>
    <span class="token key atrule">get</span><span class="token punctuation">:</span>
      <span class="token key atrule">parameters</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> id
        <span class="token key atrule">in</span><span class="token punctuation">:</span> path
        <span class="token key atrule">required</span><span class="token punctuation">:</span> <span class="token boolean important">true</span>
        <span class="token key atrule">schema</span><span class="token punctuation">:</span>
          <span class="token key atrule">type</span><span class="token punctuation">:</span> string
          <span class="token key atrule">x-taxi-type</span><span class="token punctuation">:</span>
            <span class="token key atrule">name</span><span class="token punctuation">:</span> FilmId  <span class="token comment"># &lt;-- Semantic metadata</span>
      <span class="token key atrule">responses</span><span class="token punctuation">:</span>
        <span class="token key atrule">&quot;200&quot;</span><span class="token punctuation">:</span>
          <span class="token key atrule">content</span><span class="token punctuation">:</span>
            <span class="token key atrule">application/json</span><span class="token punctuation">:</span>
              <span class="token key atrule">schema</span><span class="token punctuation">:</span>
                <span class="token key atrule">type</span><span class="token punctuation">:</span> array
                <span class="token key atrule">items</span><span class="token punctuation">:</span>
                  <span class="token key atrule">$ref</span><span class="token punctuation">:</span> <span class="token string">&#x27;#/components/schemas/FilmReview&#x27;</span>
<span class="token key atrule">components</span><span class="token punctuation">:</span>
  <span class="token key atrule">schemas</span><span class="token punctuation">:</span>
    <span class="token key atrule">FilmReview</span><span class="token punctuation">:</span>
      <span class="token key atrule">type</span><span class="token punctuation">:</span> object
      <span class="token key atrule">properties</span><span class="token punctuation">:</span>
        <span class="token key atrule">id</span><span class="token punctuation">:</span>
          <span class="token key atrule">type</span><span class="token punctuation">:</span> string
          <span class="token key atrule">x-taxi-type</span><span class="token punctuation">:</span>
            <span class="token key atrule">name</span><span class="token punctuation">:</span> ReviewId  <span class="token comment"># &lt;-- Semantic metadata</span>
        <span class="token key atrule">filmId</span><span class="token punctuation">:</span>
          <span class="token key atrule">type</span><span class="token punctuation">:</span> string
          <span class="token key atrule">x-taxi-type</span><span class="token punctuation">:</span>
            <span class="token key atrule">name</span><span class="token punctuation">:</span> FilmId  <span class="token comment"># &lt;-- Semantic metadata</span>
        <span class="token key atrule">score</span><span class="token punctuation">:</span>
          <span class="token key atrule">type</span><span class="token punctuation">:</span> integer
          <span class="token key atrule">format</span><span class="token punctuation">:</span> int32
          <span class="token key atrule">x-taxi-type</span><span class="token punctuation">:</span>
            <span class="token key atrule">name</span><span class="token punctuation">:</span> ReviewScore <span class="token comment"># &lt;-- Semantic metadata</span></code></pre></div></div><p>As teams enrich their exisitng API specs with semantic metadata, tooling can start inferring relationships between APIs and data sources.</p><p>Let’s look at a (very) simplifed API for an insurance company that provides quotes:</p><div class=""><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full mx-auto bg-slate-800 dark:bg-transparent"><div class=""><img loading="lazy" width="1292" height="265" decoding="async" data-nimg="1" class="rounded-md" style="color:transparent" sizes="(max-width: 1280px) 100vw, 65vw" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fget-quote-function.ec7f12c9.png&amp;w=640&amp;q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fget-quote-function.ec7f12c9.png&amp;w=750&amp;q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fget-quote-function.ec7f12c9.png&amp;w=828&amp;q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fget-quote-function.ec7f12c9.png&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fget-quote-function.ec7f12c9.png&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fget-quote-function.ec7f12c9.png&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fget-quote-function.ec7f12c9.png&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fget-quote-function.ec7f12c9.png&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fget-quote-function.ec7f12c9.png&amp;w=3840&amp;q=75"/><div class="text-center text-slate-500 mt-[1rem]"></div></div></div></div><p>This takes a request payload with two inputs:</p><pre><code>{
   &quot;noClaimsBonus&quot; : 0.25,
   &quot;creditScore&quot;  : &quot;AAA&quot;
}
</code></pre><p>Semantically, this can be modelled as:</p><pre class="language-taxi"><code class="language-taxi"><span class="token keyword">type</span> <span class="token class-name"></span>NoClaimsBonus <span class="token keyword">inherits</span> <span class="token class-name"></span><span class="token builtin">Decimal</span>
<span class="token keyword">type</span> <span class="token class-name"></span>CreditScore <span class="token keyword">inherits</span> <span class="token class-name"></span><span class="token builtin">String</span>

<span class="token keyword">model</span> <span class="token class-name"></span>QuoteRequest <span class="token punctuation">{</span>
  noClaimsBonus<span class="token class-name"> <span class="token punctuation">:</span> NoClaimsBonus</span>
  creditScore<span class="token class-name"> <span class="token punctuation">:</span> CreditScore</span>
<span class="token punctuation">}</span></code></pre><p>This has added a small benefit of improved clarity in the docs.</p><p>However, the real payoff is in when we’re trying to get out services to work together…</p><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="the-payoff-automating-interoperability"><a href="#the-payoff-automating-interoperability" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>The Payoff: Automating Interoperability</span></h2><p>This is where semantic metadata really starts to shine.</p><p>With Semantic Metadata embedded in our API specs, we can start to infer relationships between APIs and data.</p><p>Looking at our previous example without field names, we required two inputs - a NoClaimsBonus and a CreditScore.</p><div class=""><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full mx-auto bg-slate-800 dark:bg-transparent"><div class=""><img loading="lazy" width="1072" height="265" decoding="async" data-nimg="1" class="rounded-md" style="color:transparent" sizes="(max-width: 1280px) 100vw, 65vw" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fget-quote-function-no-field-names.46d5f957.png&amp;w=640&amp;q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fget-quote-function-no-field-names.46d5f957.png&amp;w=750&amp;q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fget-quote-function-no-field-names.46d5f957.png&amp;w=828&amp;q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fget-quote-function-no-field-names.46d5f957.png&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fget-quote-function-no-field-names.46d5f957.png&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fget-quote-function-no-field-names.46d5f957.png&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fget-quote-function-no-field-names.46d5f957.png&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fget-quote-function-no-field-names.46d5f957.png&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fget-quote-function-no-field-names.46d5f957.png&amp;w=3840&amp;q=75"/><div class="text-center text-slate-500 mt-[1rem]"></div></div></div></div><p>If we don’t have those pieces of information, we need to look them up.  Which means we need to look for services that expose this data.</p><div class="breakout-image"><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full mx-auto lg:w-[65vw] bg-slate-800 dark:bg-transparent"><div class=""><img loading="lazy" width="2363" height="654" decoding="async" data-nimg="1" class="rounded-md" style="color:transparent" sizes="(max-width: 1280px) 100vw, 65vw" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmore-functions.170af80e.png&amp;w=640&amp;q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmore-functions.170af80e.png&amp;w=750&amp;q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmore-functions.170af80e.png&amp;w=828&amp;q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmore-functions.170af80e.png&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmore-functions.170af80e.png&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmore-functions.170af80e.png&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmore-functions.170af80e.png&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmore-functions.170af80e.png&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmore-functions.170af80e.png&amp;w=3840&amp;q=75"/><div class="text-center text-slate-500 mt-[1rem]"></div></div></div></div><p>As our APIs are enriched with Semantic Metadata, tooling can automatically infer relationships between systems.</p><p>So, in our Insurance Quote example, while it’s unlikely we have either a <code>NoClaimsBonus</code> or <code>CreditScore</code> available from our UI, we might have something else - like a <code>UserName</code> or <code>UserId</code>.</p><p>Semantic Metadata lets us use tooling to automate the integration, linking from the Things We Know (<code>UserName</code>) to the Things We Want To Find Out (a <code>Quote</code>).</p><p>We’ll look into this in more detail in the next post.</p><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="a-few-tips-and-tricks"><a href="#a-few-tips-and-tricks" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>A few tips &amp; tricks...</span></h2><p>Semantic metadata is a simple concept, and is super easy to get going with.  Here are a few tips &amp; tricks to take along your journey</p><h3 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="stay-small-and-nimble-when-using-distributed-ownership"><a href="#stay-small-and-nimble-when-using-distributed-ownership" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Stay small &amp; nimble when using distributed ownership</span></h3><p>Semantic Metadata is intended for wide collaboration, which can be tricky.</p><p>Where individual teams are responsible for defining API definitions, semantic metadata has distributed ownership.</p><p>If the idea of Distributed Ownership is giving you sweaty palms and flashbacks to Design-by-committee meetings
when your org tried to implement <a href="https://teivah.medium.com/why-is-a-canonical-data-model-an-anti-pattern-441b5c4cbff8">Canonical Domain Models</a>, you might already be rolling your eyes.</p><p>Therefore, it’s <a href="https://orbitalhq.com/blog/2023-01-16-using-semantic-metadata#defining-a-semantic-type">recommended</a> that Semantic Metadata is defined on Scalar terms only - single noun-like ideas that describe exactly one idea. eg:</p><ul role="list"><li><code>FirstName</code></li><li><code>LastName</code></li><li><code>DateOfBirth</code></li><li><code>PostCode</code></li></ul><p>These are relatively un-contentious to define, and - unlike domain models (which evolve as systems mature) - semantics don’t really change.</p><h3 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="git-ops-all-the-things"><a href="#git-ops-all-the-things" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>GitOps all the things</span></h3><p>Semantics are a bridge between business language and software.  There’s no shortage of First-generation data catalog platforms that will sell you a glorified Wiki for defining your semantic terms.</p><p>Instead, consider using Open Source tooling, that aligns with GitOps.</p><p>You get peer review, audit trails, and automated workflows through all your existing Git tooling, without having to invest in expensive enterprise tooling.</p><h3 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="staying-technology-agnostic"><a href="#staying-technology-agnostic" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Staying technology agnostic</span></h3><p>Organisations these days aren’t “Java Shops” or “.NET Shops” anymore - they’re polyglot, with tech teams
choosing the tech stack that best fits the task and team.</p><p>Likewise, most API and schema technologies (eg., OpenAPI, Protobuf, etc) are language agnostic, with bindings / generators
allowing them to be consumed in whichever technology consuming teams are working with.</p><p><a href="https://github.com/taxilang/taxilang">Taxi</a> is an example of a Semantic Metadata language, which is also platform-agnostic.</p><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="summary"><a href="#summary" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Summary</span></h2><p>This has been a high level introduction into some of the ideas behind Semantic Metadata.</p><p>To go deeper, take a read into <a href="">Why we created Taxi</a>, and <a href="https://orbitalhq.com/blog/2023-01-16-using-semantic-metadata">Using Semantic Metadata for easier Integration</a>.</p><p>In the next article, we’ll take a look at building a simple application using Semantic Metadata to automate the orchestration.</p><p>Also, if you liked this article, consider giving <a href="https://github.com/taxilang/taxilang">Taxi a star</a></p><p><a href="https://GitHub.com/taxilang/taxilang/stargazers/"><div class="relative not-prose my-[2em] first:mt-0 last:mb-0 rounded-lg overflow-hidden"><img src="https://img.shields.io/github/stars/taxilang/taxilang.svg?style=social&amp;label=Star&amp;maxAge=2592000" alt="GitHub stars" decoding="async"/><div class="absolute inset-0 rounded-lg ring-1 ring-inset ring-slate-900/10"></div></div></a></p><p><em>(The post <a href="https://orbitalhq.com/blog/2023-05-22-semantic-metadata-101">Semantic Metadata 101</a> appeared first on <a href="https://orbitalhq.com/blog">Orbital Blog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/api/og?path=/blog/2023-05-22-semantic-metadata-101" length="0" type="image//api/og"/>
        </item>
        <item>
            <title><![CDATA[Why we created Taxi, and why we felt the need for Another Schema Language]]></title>
            <link>https://orbitalhq.com/blog/2023-05-12-why-we-created-taxi</link>
            <guid>Why we created Taxi, and why we felt the need for Another Schema Language</guid>
            <pubDate>Fri, 12 May 2023 19:00:00 GMT</pubDate>
            <description><![CDATA[A look into why we created Taxi and TaxiQL.]]></description>
            <content:encoded><![CDATA[<p>I’m often asked why we felt the need for another schema language - why not just use <code>OpenAPI | SQL | Protobuf | GraphQL</code>?</p><p>Inevitably, someone links <a href="https://xkcd.com/927/"><strong>that</strong> xkcd</a> cartoon.  Luckily, that cartoon is actually really funny,
so I don’t mind re-reading over and over and over.</p><p><div class="relative not-prose my-[2em] first:mt-0 last:mb-0 rounded-lg overflow-hidden"><img src="https://imgs.xkcd.com/comics/standards.png" alt="It seems if there&#x27;s one standard the internet can agree on, it&#x27;s that cartoon is a required response in discussions about schema languages." decoding="async"/><div class="absolute inset-0 rounded-lg ring-1 ring-inset ring-slate-900/10"></div></div></p><p>It seems the one standard the internet can agree on is to respond to discussions about schema languages with that cartoon.</p><p>However, it’s a fair question, and one that deserves a good answer.  So, to summarize:</p><ul role="list"><li>Yes, Taxi is another schema language.  It’s different.</li><li>Yes, we felt there need for one more.  It has different goals than the others, and addresses shortcomings we felt existed.</li><li>Yes, there’s now one more way to do things… kinda  (We don’t expect you to migrate from OpenAPI to Taxi.)</li></ul><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="what-is-taxi"><a href="#what-is-taxi" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>What is Taxi?</span></h2><p><a href="https://taxilang.org">Taxi</a> is a language for documenting data models and data sources (APIs, Event streams, Databases).</p><p>It’s designed for describing how
data relates <em>across</em> an ecosystem of datasources (such as an enterprise), rather than a single API.</p><p>We do this so we can automate orchestration and interoperability between data sources, without writing glue code.</p><blockquote><p>Where most schema languages describe a single data source (API, Event Stream, Db, Serverless function), Taxi is designed for describing how
data relates <em>across</em> an ecosystem of datasources (such as an enterprise).</p></blockquote><p>Taxi can partially describe:</p><ul role="list"><li>Databases - but you can’t replace DDL with Taxi.</li><li>HTTP APIs - but you’ll probably keep using OpenAPI / gRPC - and that’s cool.</li><li>Message queues, like Kafka and Rabbit - but you can’t replace Protobuf with Taxi.</li></ul><p>For example, here’s a Taxi spec describing a database, a Kafka topic, and a REST API:</p><pre class="language-taxi"><code class="language-taxi"><span class="token keyword">service</span> <span class="token class-name"></span>FilmsDatabase <span class="token punctuation">{</span>
  <span class="token keyword">table</span> <span class="token class-name"></span>films<span class="token class-name"> <span class="token punctuation">:</span> Film</span><span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token punctuation">}</span>

<span class="token keyword">model</span> <span class="token class-name"></span>Film <span class="token punctuation">{</span>
  filmId<span class="token class-name"> <span class="token punctuation">:</span> FilmId</span> <span class="token keyword">inherits</span> <span class="token class-name"></span><span class="token builtin">String</span>
<span class="token punctuation">}</span>

<span class="token keyword">service</span> <span class="token class-name"></span>FilmEvents <span class="token punctuation">{</span>
    <span class="token keyword">stream</span> <span class="token class-name"></span>newReleases<span class="token class-name"><span class="token punctuation">:</span> Stream</span><span class="token operator">&lt;</span>NewReviewSubmittedEvent<span class="token operator">&gt;</span>
<span class="token punctuation">}</span>

<span class="token keyword">model</span> <span class="token class-name"></span>NewReviewSubmittedEvent <span class="token punctuation">{</span>
    filmId<span class="token class-name"> <span class="token punctuation">:</span> FilmId</span>
    reviewId<span class="token class-name"> <span class="token punctuation">:</span> ReviewId</span> <span class="token keyword">inherits</span> <span class="token class-name"></span><span class="token builtin">String</span>
<span class="token punctuation">}</span>


<span class="token keyword">service</span> <span class="token class-name"></span>ReviewsApi <span class="token punctuation">{</span>
    <span class="token decorator"><span class="token at operator">@</span><span class="token function">HttpOperation</span></span><span class="token punctuation">(</span>method <span class="token operator">=</span> <span class="token string">&quot;GET&quot;</span><span class="token punctuation">,</span> url <span class="token operator">=</span> <span class="token string">&quot;https://reviews/{id}&quot;</span><span class="token punctuation">)</span>
    <span class="token keyword">operation</span> <span class="token class-name"></span><span class="token function">getReviews</span><span class="token punctuation">(</span>id<span class="token class-name"><span class="token punctuation">:</span> FilmId</span><span class="token punctuation">)</span><span class="token punctuation">:</span> FilmReview<span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token punctuation">}</span>

<span class="token keyword">model</span> <span class="token class-name"></span>FilmReview <span class="token punctuation">{</span>
    id<span class="token class-name"><span class="token punctuation">:</span> ReviewId</span>
    filmId<span class="token class-name"><span class="token punctuation">:</span> FilmId</span>
    score<span class="token class-name"><span class="token punctuation">:</span> ReviewScore</span> <span class="token keyword">inherits</span> <span class="token class-name"></span>Int
<span class="token punctuation">}</span></code></pre><p>There’s enough metadata there for us to understand how everything hangs together - here’s a diagram of that spec:</p><div class="breakout-image"><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full mx-auto lg:w-[65vw]"><div class=""><img loading="lazy" width="2065" height="664" decoding="async" data-nimg="1" class="rounded-md" style="color:transparent" sizes="(max-width: 1280px) 100vw, 65vw" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdb-kafka-api-2.ff2fa0ea.png&amp;w=640&amp;q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdb-kafka-api-2.ff2fa0ea.png&amp;w=750&amp;q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdb-kafka-api-2.ff2fa0ea.png&amp;w=828&amp;q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdb-kafka-api-2.ff2fa0ea.png&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdb-kafka-api-2.ff2fa0ea.png&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdb-kafka-api-2.ff2fa0ea.png&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdb-kafka-api-2.ff2fa0ea.png&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdb-kafka-api-2.ff2fa0ea.png&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdb-kafka-api-2.ff2fa0ea.png&amp;w=3840&amp;q=75"/><div class="text-center text-slate-500 mt-[1rem]"></div><div class="text-center"><a class="text-slate-400 text-sm" target="_blank" href="https://playground.taxilang.org/#pako:H4sIAAAAAAAAA3VSwW7CMAz9lSgnkCpxr7Zpk2Abl02ju1EOgRgaKUm72AWhqv++NGkETOz28vye/Syn47irwAiecwR3VDtgr0obnAsSW4HAutIy5rEGth8KLA+C9aa0fWlLa2oJOlBROoiWclR5oGwFThGygpyyh9F1PWtxBOvrwc0YkgNhmIXTCjT4BJgPVs89fAzcUcGpaLdGEYEM1qebJP+IUvs/8SLpgiHQqwTv574kj0J8aVRq/fxO1Hw24ASp2k4MUFVL9shK/rb4LnnGWqfDs/I6zGezOBZnnZJ9yaexS50asAPQOGSiZAo8jSAW7hwhFlKkwZc2ut7/dn3c1Q6SsBgel+2XlvwMnvGfFtzZ/xIPG+GE3w4c8rzrM47Ubj1cbzLu7yQNRJkW57olL+FY1ae5Egdv4zm5FrJArUbxXmgcqa845Yopxu852Pr+F4Ec0S2vAgAA">Fork this diagram on playground.taxilang.org</a></div></div></div></div><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="taxi-embeds-within-existing-specs"><a href="#taxi-embeds-within-existing-specs" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Taxi embeds within existing specs</span></h2><p>In practice, Taxi actually breaks down into two separate activities:</p><ul role="list"><li>Defining a set of semantic scalar types, that describe a single field, which live in a Taxi project.  These are designed for sharing.</li><li>Embedding references to those types within existing API specs.</li></ul><p>Our example above breaks down into a few simple types:</p><pre class="language-taxi"><code class="language-taxi"><span class="token comment">// A taxi project.  Generally, this is committed into</span>
<span class="token comment">// a Git repo somewhere.</span>

<span class="token keyword">type</span> <span class="token class-name"></span>FilmId <span class="token keyword">inherits</span> <span class="token class-name"></span><span class="token builtin">String</span>
<span class="token keyword">type</span> <span class="token class-name"></span>ReviewId <span class="token keyword">inherits</span> <span class="token class-name"></span><span class="token builtin">String</span>
<span class="token keyword">type</span> <span class="token class-name"></span>ReviewScore <span class="token keyword">inherits</span> <span class="token class-name"></span>Int</code></pre><p>And some other specs:</p><button type="button" aria-hidden="true" style="position:fixed;top:1px;left:1px;width:1px;height:0;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0"></button><div class="not-prose bg-slate-800 rounded-xl shadow-md"><div class="flex"><div class="flex text-slate-400 text-xs leading-6 overflow-hidden rounded-tl-xl pt-2" role="tablist" aria-orientation="horizontal"><button class="flex items-center relative z-10 overflow-hidden px-4 py-1 [&amp;:not(:focus-visible)]:focus:outline-none text-sky-300" id="headlessui-tabs-tab-:Raoo:" role="tab" type="button" aria-selected="true" tabindex="0" data-headlessui-state="selected"><span class="z-10">reviews.openapi.yml</span><div class="pointer-events-none absolute inset-0 border-b border-b-sky-300"></div></button><button class="flex items-center relative z-10 overflow-hidden px-4 py-1 [&amp;:not(:focus-visible)]:focus:outline-none text-slate-400" id="headlessui-tabs-tab-:Rioo:" role="tab" type="button" aria-selected="false" tabindex="-1" data-headlessui-state=""><span class="z-10">NewReviewSubmittedEvent.proto</span><div class="pointer-events-none absolute inset-0 bg-slate-700/50 border-y border-slate-500/30 border-l rounded-tl"></div><div class="pointer-events-none absolute inset-0 inset-y-px border-r border-slate-200/5 z-20"></div></button><button class="flex items-center relative z-10 overflow-hidden px-4 py-1 [&amp;:not(:focus-visible)]:focus:outline-none text-slate-400" id="headlessui-tabs-tab-:Rqoo:" role="tab" type="button" aria-selected="false" tabindex="-1" data-headlessui-state=""><span class="z-10">films.taxi</span><div class="pointer-events-none absolute inset-0 bg-slate-700/50 border-y border-slate-500/30"></div><div class="pointer-events-none absolute inset-0 inset-y-px border-r border-slate-200/5 z-20"></div></button></div><div class="flex-auto flex pt-2 rounded-tr-xl overflow-hidden"><div class="flex-auto flex justify-end bg-slate-700/50 border-y border-slate-500/30 pr-4"></div></div></div><div class="flex overflow-auto"><div class="flex-none min-w-full p-5 text-sm leading-6 text-slate-50 ligatures-none" id="headlessui-tabs-panel-:R38o:" role="tabpanel" tabindex="0" data-headlessui-state="selected"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">openapi</span><span class="token punctuation">:</span> 3.0.1
<span class="token key atrule">info</span><span class="token punctuation">:</span>
<span class="token key atrule">title</span><span class="token punctuation">:</span> ReviewsApi
<span class="token key atrule">version</span><span class="token punctuation">:</span> 1.0.0
<span class="token key atrule">paths</span><span class="token punctuation">:</span>
https<span class="token punctuation">:</span>//reviews/<span class="token punctuation">{</span>id<span class="token punctuation">}</span><span class="token punctuation">:</span>
  <span class="token key atrule">get</span><span class="token punctuation">:</span>
    <span class="token key atrule">parameters</span><span class="token punctuation">:</span>
    <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> id
      <span class="token key atrule">in</span><span class="token punctuation">:</span> path
      <span class="token key atrule">required</span><span class="token punctuation">:</span> <span class="token boolean important">true</span>
      <span class="token key atrule">schema</span><span class="token punctuation">:</span>
        <span class="token key atrule">type</span><span class="token punctuation">:</span> string
        <span class="token key atrule">x-taxi-type</span><span class="token punctuation">:</span>
          <span class="token key atrule">name</span><span class="token punctuation">:</span> FilmId  <span class="token comment"># &lt;-- Taxi metadata</span>
    <span class="token key atrule">responses</span><span class="token punctuation">:</span>
      <span class="token key atrule">&quot;200&quot;</span><span class="token punctuation">:</span>
        <span class="token key atrule">content</span><span class="token punctuation">:</span>
          <span class="token key atrule">application/json</span><span class="token punctuation">:</span>
            <span class="token key atrule">schema</span><span class="token punctuation">:</span>
              <span class="token key atrule">type</span><span class="token punctuation">:</span> array
              <span class="token key atrule">items</span><span class="token punctuation">:</span>
                <span class="token key atrule">$ref</span><span class="token punctuation">:</span> <span class="token string">&#x27;#/components/schemas/FilmReview&#x27;</span>
<span class="token key atrule">components</span><span class="token punctuation">:</span>
<span class="token key atrule">schemas</span><span class="token punctuation">:</span>
  <span class="token key atrule">FilmReview</span><span class="token punctuation">:</span>
    <span class="token key atrule">type</span><span class="token punctuation">:</span> object
    <span class="token key atrule">properties</span><span class="token punctuation">:</span>
      <span class="token key atrule">id</span><span class="token punctuation">:</span>
        <span class="token key atrule">type</span><span class="token punctuation">:</span> string
        <span class="token key atrule">x-taxi-type</span><span class="token punctuation">:</span>
          <span class="token key atrule">name</span><span class="token punctuation">:</span> ReviewId  <span class="token comment"># &lt;-- Taxi metadata</span>
      <span class="token key atrule">filmId</span><span class="token punctuation">:</span>
        <span class="token key atrule">type</span><span class="token punctuation">:</span> string
        <span class="token key atrule">x-taxi-type</span><span class="token punctuation">:</span>
          <span class="token key atrule">name</span><span class="token punctuation">:</span> FilmId  <span class="token comment"># &lt;-- Taxi metadata</span>
      <span class="token key atrule">score</span><span class="token punctuation">:</span>
        <span class="token key atrule">type</span><span class="token punctuation">:</span> integer
        <span class="token key atrule">format</span><span class="token punctuation">:</span> int32
        <span class="token key atrule">x-taxi-type</span><span class="token punctuation">:</span>
          <span class="token key atrule">name</span><span class="token punctuation">:</span> ReviewScore <span class="token comment"># &lt;-- Taxi metadata</span></code></pre></div><span id="headlessui-tabs-panel-:R58o:" role="tabpanel" tabindex="-1" style="position:fixed;top:1px;left:1px;width:1px;height:0;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0"></span><span id="headlessui-tabs-panel-:R78o:" role="tabpanel" tabindex="-1" style="position:fixed;top:1px;left:1px;width:1px;height:0;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0"></span></div></div><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="why-do-this"><a href="#why-do-this" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Why do this?</span></h2><p>At Orbital, we’re on a mission to eradicate integration code.</p><p>Even though we were heavy users of OpenAPI, we found that when consuming APIs there’s a tonne of busywork in
writing glue code stitching things together.</p><p>Often, we were composing multiple APIs together to achieve a single task.  Each API required
more glue code, and meant we were tightly coupling to that spec - meaning when the spec introduced breaking changes, our
glue code had to be repaired.</p><p>That seemed silly.  Even though we had all these specs that describe what APIs do, it still
fell to engineers to work out which API to call, what data to pass for inputs, and write the glue code.</p><blockquote><p>Even though we had all these specs that describe what APIs do, it still
fell to engineers to work out which API to call, to track down inputs, and write the glue code.</p></blockquote><p>We wanted to provide a way to let APIs describe themselves richly enough that software could work out how to orchestrate
them together automatically.  We also had some other goals:</p><ul role="list"><li>We shouldn’t be relying on field names - they’re a <a href="/blog/2023-01-16-using-semantic-metadata#field-names-are-a-bad-proxy-for-semantics">bad proxy for semantics</a>, and teams should be free to chose names that make sense to their domain.</li><li>We shouldn’t force teams building APIs to replace their existing specs with something new - we want to complement what’s already in place.</li><li>We had to be technology-agnostic.  Modern enterprises are heterogeneous, so we needed to work everywhere.</li><li>Teams building APIs need to be able to change their APIs easily, without cascading change onto consumers.</li></ul><h3 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="producer-vs-consumer-once-vs-many-times"><a href="#producer-vs-consumer-once-vs-many-times" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Producer vs Consumer - Once vs Many times</span></h3><p>Taxi shifts the obligation of describing how things stitch together from Consumers to Producers.</p><p>Traditionally, it falls to consumers to work out how to do this.</p><p>And, it’s an expensive question to answer… it involves tracking down API specs, reading docs,
and building a mental model of how things hang together.</p><div class="breakout-image"><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full mx-auto lg:w-[65vw] bg-slate-800 dark:bg-transparent"><div class=""><img alt="How integration works today.  Over, and over, and over." loading="lazy" width="1532" height="341" decoding="async" data-nimg="1" class="rounded-md" style="color:transparent" sizes="(max-width: 1280px) 100vw, 65vw" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fhow-we-integrate-over-and-over.0c7a9530.png&amp;w=640&amp;q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fhow-we-integrate-over-and-over.0c7a9530.png&amp;w=750&amp;q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fhow-we-integrate-over-and-over.0c7a9530.png&amp;w=828&amp;q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fhow-we-integrate-over-and-over.0c7a9530.png&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fhow-we-integrate-over-and-over.0c7a9530.png&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fhow-we-integrate-over-and-over.0c7a9530.png&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fhow-we-integrate-over-and-over.0c7a9530.png&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fhow-we-integrate-over-and-over.0c7a9530.png&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fhow-we-integrate-over-and-over.0c7a9530.png&amp;w=3840&amp;q=75"/><div class="text-center text-slate-500 mt-[1rem]">How integration works today.  Over, and over, and over.</div></div></div></div><p>That sucks, because consumers are a-plenty, meaning that the “how does this relate to that” is answered over and over.</p><p>Instead, with Taxi, we shift the obligation of documenting how things relate to producers, by embedding metadata
in their APIs.</p><p>This means work is done once - by the teams who understand the APIs the best - the ones building it.</p><h3 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="what-if-teams-put-the-wrong-metadata"><a href="#what-if-teams-put-the-wrong-metadata" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>What if teams put the wrong metadata?</span></h3><p>Yeah, that’s a problem.  If teams map fields together incorrectly, then the wrong APIs are stitched together.</p><p>But, that problem exists today - every time a new consumer stitches together some APIs, they’re performing the Field Mapping Foxtrot, and there’s a chance they’ll get it wrong.</p><p>So, by leaving it to consumers to map fields together, we’re actually facing this risk over and over.</p><p>In practice, the teams who are building the API have a much deeper understanding of how their data relates to the broader ecosystem, as they know their API best.  And, whilst producers
can’t map their APIs to all consumers, they can attach a piece of well-defined metadata that assigns a <a href="/blog/2023-01-16-using-semantic-metadata">semantic contract we all agree on</a>.</p><p>That being said, I think tooling can help more here than we do currently.  Watch this space.</p><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="what-is-taxi-ql"><a href="#what-is-taxi-ql" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>What is TaxiQL?</span></h2><p>TaxiQL is part of the <a href="https://github.com/taxilang/taxilang/blob/develop/compiler/src/main/antlr4/lang/taxi/Taxi.g4">Taxi Spec</a> - it’s a query language that lets consumers ask for data they want using the
same semantic types that producers have embedded in their API specs.</p><pre class="language-taxi"><code class="language-taxi"><span class="token class-name"><span class="token keyword">find</span> <span class="token punctuation">{</span> Film</span><span class="token punctuation">(</span> Title <span class="token operator">==</span> <span class="token string">&#x27;Gladiator&#x27;</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">as</span> <span class="token class-name"></span><span class="token punctuation">{</span>
   title<span class="token class-name"><span class="token punctuation">:</span> FilmTitle</span>
   cast <span class="token punctuation">:</span> <span class="token punctuation">{</span>
     actorName<span class="token class-name"> <span class="token punctuation">:</span> FirstName</span> <span class="token operator">+</span> <span class="token string">&#x27; &#x27;</span> <span class="token operator">+</span> LastName
     twitter<span class="token class-name"> <span class="token punctuation">:</span> TwitterHandle</span>
   <span class="token punctuation">}</span><span class="token punctuation">[</span><span class="token punctuation">]</span>
   rating<span class="token class-name"><span class="token punctuation">:</span> ReviewScore</span>
   reviews<span class="token class-name"><span class="token punctuation">:</span> ReviewText</span><span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token punctuation">}</span></code></pre><p>Taxi works just as well with request-response interfaces, as well as streaming data sources:</p><pre class="language-taxi"><code class="language-taxi"><span class="token comment">// Whenver a new film review is emitted, give me the data I want.</span>
<span class="token keyword">stream</span> <span class="token class-name"></span><span class="token punctuation">{</span> FilmReviewSubmittedEvent <span class="token punctuation">}</span> <span class="token keyword">as</span> <span class="token class-name"></span><span class="token punctuation">{</span>
   title<span class="token class-name"><span class="token punctuation">:</span> FilmTitle</span>
   cast <span class="token punctuation">:</span> <span class="token punctuation">{</span>
     actorName<span class="token class-name"> <span class="token punctuation">:</span> FirstName</span> <span class="token operator">+</span> <span class="token string">&#x27; &#x27;</span> <span class="token operator">+</span> LastName
     twitter<span class="token class-name"> <span class="token punctuation">:</span> TwitterHandle</span>
   <span class="token punctuation">}</span><span class="token punctuation">[</span><span class="token punctuation">]</span>
   rating<span class="token class-name"><span class="token punctuation">:</span> ReviewScore</span>
   reviews<span class="token class-name"><span class="token punctuation">:</span> ReviewText</span><span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token punctuation">}</span></code></pre><p>By using types in the consumer contract, and combining with the metadata in producers,
there’s enough information to infer how everything hangs together, and to automate the integration.</p><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="taxi-ql-vs-graph-ql"><a href="#taxi-ql-vs-graph-ql" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>TaxiQL vs GraphQL</span></h2><p>Both Taxi and GraphQL share similar goals - providing a single entrypoint for
composing multiple APIs together. GraphQL has been a strong inspiration in how we’ve designed
Taxi.</p><p>However, there are key differences in their approach.</p><h3 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="no-global-schema"><a href="#no-global-schema" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>No global schema</span></h3><p>GraphQL defines a single global schema that all consumers adhere to.  Consumers can
cherry-pick the fields they want, but the structure is fixed.</p><p>That global schema can create friction to change - if you need to refactor the schema, you either need
to make backwards compatible changes, or consumers need to update.</p><p>Which is to say - evolving a shared structural contract is hard, and <em>someone</em> needs to take the hit - either the schema owner (through maintaining a backwards compatible change),
or the consumers (by fixing what breaks when the schema changes).</p><p>This isn’t just a GraphQL issue - it’s true of any structural contract that is widely shared - they’re hard to change.</p><h3 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="consumer-driven-contracts"><a href="#consumer-driven-contracts" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Consumer driven contracts</span></h3><p>GraphQL has consumer-driven-contracts-lite.  ie., consumers can cherry-pick the fields they want from
the global schema.  However, that’s it - structure, encoding, etc is fixed.</p><p>If you want to consume data in a different shape, you’ll need to map the data on the consumer side.</p><p>Those additional mapping layers are troublesome - each mapping layer you build is a tight coupling between contracts - ie.,
a thing that has to change when the upstream contract changes.</p><p>Instead, with Taxi, consumers define the data contract they want to consume in the request they send.</p><p>There is no single central schema - producer APIs are composed together on-the-fly to satisfy the consumer contract.</p><p>The types and query language provide enough flexibility that consumers can express the exact
contract they require, and the middleware can understand how to assemble a response.</p><h3 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="no-resolvers"><a href="#no-resolvers" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>No resolvers</span></h3><p>GraphQL uses resolvers to stitch together APIs - which is exactly the type of integration code
we’re on a mission to eliminate.</p><p>As APIs change, resolvers need to be maintained and updated.</p><p>Generally, with Taxi you don’t need resolvers - the API specs are rich enough to automate the resolvers.</p><h3 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="technology-agnostic"><a href="#technology-agnostic" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Technology-agnostic</span></h3><p>GraphQL requires GraphQL everywhere, or shims to adapt to GraphQL.</p><p>Taxi (and taxiQL) is trying hard to keep the footprint low - Taxi will happily compose together a Kafka topic
publishing Protobuf, with a gRPC service, some REST APIs, and a database.</p><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="what-about-implementations"><a href="#what-about-implementations" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>What about implementations?</span></h2><p>Taxi - the spec, compiler, and tooling ecosystem are all open source.  Head over to <a href="https://github.com/taxilang/taxilang">Github</a> and give it some stars.</p><p>The TaxiQL query server is currently part of Orbital - which we’re working to open source this summer.
In the meantime, you can take it for a spin following our <a href="https://orbitalhq.com/docs/guides/apis-databases-kafka">getting started guide</a>.</p><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="summary"><a href="#summary" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Summary</span></h2><p>So, here’s the key takeaways:</p><p>Taxi exists to describe how data and data sources relate to one another, and to automate interoperability.</p><p>OpenAPI, SQL, Protobuf, etc., all do a great job of describing a single data source.  By adding additional
metadata into those APIs, we have enough information to automate integration between services, without
writing (or maintaining) glue code.</p><p>TaxiQL is a way to use Taxi types to ask for data, and for consumers  to remain decoupled from producer schemas,
so as things change, there’s no glue code to maintain.</p><p>XKCD is the one true standard, which is how it was always meant to be.</p><p><em>(The post <a href="https://orbitalhq.com/blog/2023-05-12-why-we-created-taxi">Why we created Taxi, and why we felt the need for Another Schema Language</a> appeared first on <a href="https://orbitalhq.com/blog">Orbital Blog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/api/og?path=/blog/2023-05-12-why-we-created-taxi" length="0" type="image//api/og"/>
        </item>
        <item>
            <title><![CDATA[Backends for frontends]]></title>
            <link>https://orbitalhq.com/blog/2023-04-24-backends-for-frontends-part-1</link>
            <guid>Backends for frontends</guid>
            <pubDate>Mon, 24 Apr 2023 12:21:00 GMT</pubDate>
            <description><![CDATA[Walkthrough of the backends-for-frontends pattern.]]></description>
            <content:encoded><![CDATA[<p>Here at Orbital, we’re interested in all things integration and backends-for-frontends (BFFs) fall squarely in that category. From one perspective, they’re simply a transformation and aggregation layer. Others would say they exist to tightly align with the requirements of the different frontends in your stack. </p><p>We prefer to see them as an API that’s customized for a single consumer rather than many consumers like typical APIs. It flips the concept of who an API is built for on its head.</p><p>This is the first of two posts with our take on BFFs. First we’ll take a look at the pattern itself, why they emerged and what the trade offs are. In our follow-up we’ll go through how Orbital acts as a BFF and why it’s an elegant solution (if we don’t say so ourselves)</p><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="how-did-they-become-a-thing"><a href="#how-did-they-become-a-thing" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>How did they become a thing?</span></h2><p>Historically, developers build APIs from the perspective of the backend system. They create models based on their own domain. Patterns like REST let them split entities into clean and well-structured endpoints. Which is all completely rational if you’re building one of those systems.</p><p>Enter UX designers who (rightly so) have very different ideas and are concerned with how to create an intuitive and pleasant interface. They care not if we’re serving User and Post data from two different systems and laugh in the face of the completely rational schema designs.</p><p>Backends-for-frontends is a pattern that emerged to resolve this tension. It allows us to cater for the different data fetching needs of web and mobile applications.  However, the functionality and type of data are often similar across both mobile and desktop platforms. So, when developers started creating more complex mobile applications in the 2010s, it made sense to use the same backend systems as their desktop counterparts.</p><blockquote><p>As the designs for desktop and mobile diverged, so did the requirements for the APIs serving them.</p></blockquote><p>As the designs for desktop and mobile diverged, so did the requirements for the APIs serving them.  The importance for optimizing for mobile meant fixing issues like over-fetching data on limited bandwidths. At the end of this path, it’s common to have similar data, all from the same domain, but very different API footprints. </p><p>Organizational structures accentuated these differences by using different teams to manage the frontend and backend systems. As the web and mobile teams were also split, backend teams became a bottleneck for implementing API requests.</p><p>Enter the BFF from stage-left. The savior of developers on both sides of this divide. Bringing gifts of freedom and autonomy for front end developers, and releasing backend developers from an onslaught of trivial requests to add fields. I can only assume that project managers celebrated in their own way too.</p><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="so-what-are-they"><a href="#so-what-are-they" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>So what are they?</span></h2><p>Assume we’re got a couple of frontend teams building separate desktop and mobile apps. Given the task of fetching data from our organization’s collection of services, let’s take a look at some of the options available to them.  </p><p><em>Note: Although it’s more common to see this applied in microservices architectures, it’s equally relevant for monoliths. We’d still expect a monolith to split up their API into distinct endpoints over one or more domains.</em></p><h3 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="diy-integration"><a href="#diy-integration" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>DIY integration</span></h3><p>The original method for this was something of a DIY approach. From each of our frontend applications, we’ll call out to each API and aggregate the data together. It’s basically everyone for themselves.</p><div class=""><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full mx-auto"><div class=""><img alt="" loading="lazy" width="1470" height="597" decoding="async" data-nimg="1" class="rounded-md" style="color:transparent" sizes="(max-width: 1280px) 100vw, 65vw" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdiy.7c5469b1.png&amp;w=640&amp;q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdiy.7c5469b1.png&amp;w=750&amp;q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdiy.7c5469b1.png&amp;w=828&amp;q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdiy.7c5469b1.png&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdiy.7c5469b1.png&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdiy.7c5469b1.png&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdiy.7c5469b1.png&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdiy.7c5469b1.png&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdiy.7c5469b1.png&amp;w=3840&amp;q=75"/><div class="text-center text-slate-500 mt-[1rem]"></div></div></div></div><p>There’s nothing wrong with this, but we do import a bunch of complexity into our UI code. For each of the APIs we need to do things like:</p><ul role="list"><li>manage the connection config</li><li>handle the success, failure or retry states</li><li>import the individual domain models</li></ul><p>And that’s assuming they’re all using a consistent protocol. It’s just as likely that one exposes a REST API with an OpenAPI spec, and another uses gRPC, or god forbid, SOAP.</p><h3 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="general-purpose-api"><a href="#general-purpose-api" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>General Purpose API</span></h3><p>An improvement on this is to create a backend service that takes on some of this integration complexity. Each frontend is kinda doing the same thing if you squint a bit so maybe that makes sense.</p><div class=""><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full mx-auto"><div class=""><img alt="" loading="lazy" width="1506" height="957" decoding="async" data-nimg="1" class="rounded-md" style="color:transparent" sizes="(max-width: 1280px) 100vw, 65vw" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fgeneral-purpose-api.40298982.png&amp;w=640&amp;q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fgeneral-purpose-api.40298982.png&amp;w=750&amp;q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fgeneral-purpose-api.40298982.png&amp;w=828&amp;q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fgeneral-purpose-api.40298982.png&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fgeneral-purpose-api.40298982.png&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fgeneral-purpose-api.40298982.png&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fgeneral-purpose-api.40298982.png&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fgeneral-purpose-api.40298982.png&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fgeneral-purpose-api.40298982.png&amp;w=3840&amp;q=75"/><div class="text-center text-slate-500 mt-[1rem]"></div></div></div></div><p>What you’d have then would be a bit more like a concierge. A high-end concierge, sure! They’ll be super polite, maybe even go above and beyond to get you what you want on occasion. Instead of having to know all the ins and outs of where to get your data from, you can rely on your concierge (general purpose API) to gather all the relevent data for you and put it in a nice little package. From the perspective of the front end apps, it’s much simpler to integrate with this one API with pre-aggregated data than to do that work themselves.</p><p>But they’re still serving any number of people, not just you. When the team building our general purpose backend gets approached by two different frontend teams, they’ve gotta balance both requests.</p><h3 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="backend-for-frontend"><a href="#backend-for-frontend" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Backend-for-frontend</span></h3><p>Backends for frontends are kind of like a personal butler for your frontend. They know how you like things done, are ready and willing to make any change you want, and sometimes even know you better than you know yourself (if Michael Caine is involved). </p><blockquote><p>Backends for frontends are kind of like a personal butler for your frontend.</p></blockquote><p>To meet the data fetching requirements of each frontend, we can create a distinct backend. That allow us to customize the API to serve exactly what we need and as a result improve our ability to solve over fetching or under fetching issues. If we want to trial GraphQL, we don’t have to convince a backend team to expose the same API in two different protocols, or have all our sibling frontends also switch over.</p><p>Since we’re not liaising with another team for changes, our whole change management cycle becomes easier too. Deploying a new feature that changes the API interface doesn’t need multi-team coordination. As such, the process to test, deploy and monitor the change to guard against an outage is much more contained. That flexibility is important where your deployments are via an App Store and somewhat out of your control.</p><div class=""><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full mx-auto"><div class=""><img alt="" loading="lazy" width="1488" height="945" decoding="async" data-nimg="1" class="rounded-md" style="color:transparent" sizes="(max-width: 1280px) 100vw, 65vw" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbff.160eaaa4.png&amp;w=640&amp;q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbff.160eaaa4.png&amp;w=750&amp;q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbff.160eaaa4.png&amp;w=828&amp;q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbff.160eaaa4.png&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbff.160eaaa4.png&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbff.160eaaa4.png&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbff.160eaaa4.png&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbff.160eaaa4.png&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fbff.160eaaa4.png&amp;w=3840&amp;q=75"/><div class="text-center text-slate-500 mt-[1rem]"></div></div></div></div><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="what-are-the-challenges"><a href="#what-are-the-challenges" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>What are the challenges?</span></h2><p>By design a BFF is tightly coupled with our frontend systems. That leads to interesting questions about which team should own it, and what technology it should be built with. From a work division and scheduling perspective it makes sense to sit with the frontend team. They’re also going to be driving it’s implementation so that it works best with the frontend.</p><p>However, this leaves us with a awkward technical choice for our server side BFF. We either have to pick technologies to match the skills of frontend engineers, they need learn them, or we need to import them. Luckily there’s good options for web and Android frontend teams to at least use the same programming language.  For Node.js there’s great frameworks like Express and Nest and on the JVM they’ve got options like Spring. </p><p>I’d argue though that the programming language used is only a component of the problem. There’s generally a wide gap in the bag of tricks required to work on a backend application compared to a frontend. A level of upskilling and extra complexity for the frontend team to deal with is inevitable in this autonomy trade-off.</p><blockquote><p>A level of upskilling and extra complexity for the frontend team to deal with is inevitable in this autonomy trade-off.</p></blockquote><p>We should also consider the raw time involved in building and deploying another service. With each frontend team now building and managing their own integration layer, there’s bound to be some duplication of code and effort as payment for the flexibility that we’re buying with this abstraction.</p><p>In terms of deployments, our tools have come a long <em>long</em> way and for many use cases it’s a simple click of the button. Once you leave the guardrails though, there’s often devops pain. As an intermittent, rather than full time devops engineer myself, scripting a cloud deployment and getting the infrastructure right can become a time-consuming task. Creating a separate BFF service buys a little more of that pain. That’s especially true if it’s the frontend team managing it as the infrastructure requirements will differ from those of the frontend code base.</p><p>Finally, although managing the coupling with the APIs of your downstream services is easier to manage in a BFF, the problem still exists. It’s just in a different place. When any of those services updates their API, our BFF needs to be updated too. For breaking changes, the mapping code we’ve written needs to be reviewed and modified, and run through the test-and-deploy cycle. That’s a win for isolating the effect of these changes and protecting our frontend code bases, but it’s still work that the frontend team needs to pick up.</p><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="what-s-next"><a href="#what-s-next" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>What&#x27;s next?</span></h2><p>Next up I’ll be writing about how you can use Orbital for your Backend for Frontend without needing to create a new custom backend service. We’ll look at how Orbital helps with automatically adapting to changes in downstream services, and with supporting multiple versions of frontend app being used in the wild. </p><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="other-bff-material"><a href="#other-bff-material" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Other BFF material</span></h2><p>If this hasn’t quenched your thirst for reading about BFFs, here’s a few other great articles.</p><ul role="list"><li><a target="_blank" href="https://samnewman.io/patterns/architectural/bff/">https://samnewman.io/patterns/architectural/bff/</a></li><li><a target="_blank" href="https://www.thoughtworks.com/insights/blog/bff-soundcloud">https://www.thoughtworks.com/insights/blog/bff-soundcloud</a></li><li><a target="_blank" href="https://philcalcado.com/2019/07/12/some_thoughts_graphql_bff.html">https://philcalcado.com/2019/07/12/some_thoughts_graphql_bff.html</a></li></ul><p><em>(The post <a href="https://orbitalhq.com/blog/2023-04-24-backends-for-frontends-part-1">Backends for frontends</a> appeared first on <a href="https://orbitalhq.com/blog">Orbital Blog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/api/og?path=/blog/2023-04-24-backends-for-frontends-part-1" length="0" type="image//api/og"/>
        </item>
        <item>
            <title><![CDATA[Uniting similar data from multiple sources]]></title>
            <link>https://orbitalhq.com/blog/2023-04-26-uniting-data-from-multiple-sources</link>
            <guid>Uniting similar data from multiple sources</guid>
            <pubDate>Sun, 23 Apr 2023 12:21:00 GMT</pubDate>
            <description><![CDATA[Often the same type of data arrives in different formats from multiple providers. Let's compare some familiar solutions, and see how Orbital offers as a federated data discovery platform.]]></description>
            <content:encoded><![CDATA[<p>There’s plenty of legitimate cases where your company could have ended up with multiple services
providing what is essentially the same type of data.</p><p>Possibly it’s as simple as a postcode resolution service, or it could be there’s a few Customer
databases floating around.  It’d be far too convenient for us for
these sources to have stored exactly the same data, using exactly the same representation.</p><p>Even so, the content they contain almost certainly will have commonalities.</p><p>In the case of Customer data, you definitely wouldn’t be surprised to find a first name,
last name and email address being represented in each system.</p><p>However, the way these fields are described may vary wildly, and you can’t help it if a developer long ago decided to label their last name property as <code>frequently_inherited_name</code>.</p><p>Regardless, the content of that field is equivalent to your last name, surname or family name fields which are present in the other Customer data sets.</p><p>Having systems that store and structure data in different ways is a Good Thing - we want our systems to be able to evolve independently, rather than conform to a rigid shared model. After all, you can’t force standardisation, without removing the ability for teams to evolve independently - and that’s not a tradeoff worth making.</p><p>What’s important is that there’s a common concept being represented, such as a Customer, an Order, or a Product.</p><p>Once our data scene has been set in this way, sooner or later someone in the business will realise that there’s some value to be gained by being able to query that spread out data in a consistent way.  That’s the Chameleon pattern in action.</p><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="where-does-this-happen"><a href="#where-does-this-happen" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Where does this happen?</span></h2><p>This is extremely common. Here’s a few examples that you might recognise:</p><ul role="list"><li>Your company may have grown up with independent divisions which have evolved separately and built their own versions of things</li><li>Through success and good fortune, you’ve acquired a bunch of related littler companies, that each came with their own unique IT infrastructure.</li><li>You’re using multiple providers for the same type of service (such as payments)</li><li>You’re using multiple vendors for the same type of product (perhaps in your supply chain)</li><li>You’ve started adopting microservices, and found that you’ve got duplicate services rearing their heads all over the place!</li><li>It’s come time to deal with that dilapidated legacy system, and you’d sooner walk on hot ashes than do a big bang cutover</li></ul><p>To handle these scenarios, typically we see a couple of different patterns implemented.</p><h3 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="1-consumers-aggregate-data-themselves"><a href="#1-consumers-aggregate-data-themselves" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>1. Consumers aggregate data themselves</span></h3><p>The consuming system queries all providers separately and manually combines them.</p><p>If multiple systems need to consume the same data, each needs to build the same integrations with the source systems, and implement the same aggregation and reshaping code to convert the source data to something that’s useful to it.</p><p>This is great for developers who get paid per line of code.</p><div class=""><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full mx-auto"><div class=""><img alt="Super App goes it alone and integrates with everyone separately" loading="lazy" width="559" height="298" decoding="async" data-nimg="1" class="rounded-md" style="color:transparent" sizes="(max-width: 1280px) 100vw, 65vw" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fconsumers-aggregate-data-themselves.d2356b8f.jpeg&amp;w=640&amp;q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fconsumers-aggregate-data-themselves.d2356b8f.jpeg&amp;w=750&amp;q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fconsumers-aggregate-data-themselves.d2356b8f.jpeg&amp;w=828&amp;q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fconsumers-aggregate-data-themselves.d2356b8f.jpeg&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fconsumers-aggregate-data-themselves.d2356b8f.jpeg&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fconsumers-aggregate-data-themselves.d2356b8f.jpeg&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fconsumers-aggregate-data-themselves.d2356b8f.jpeg&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fconsumers-aggregate-data-themselves.d2356b8f.jpeg&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fconsumers-aggregate-data-themselves.d2356b8f.jpeg&amp;w=3840&amp;q=75"/><div class="text-center text-slate-500 mt-[1rem]">Super App goes it alone and integrates with everyone separately</div></div></div></div><h3 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="2-our-data-providers-expose-canonical-models"><a href="#2-our-data-providers-expose-canonical-models" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>2. Our data providers expose canonical models</span></h3><p>To save every consumer from the burden of integrating and reshaping the diverse data formats provided by source systems, you might think of forcing each provider to expose a canonical version of the data.</p><p>This helps our Super App developers to an extent, they still have to call out to every system, but at least the data is in the same format. The downside is that the data has to be in the same format! Both of our providers need to agree what a common definition of a customer model is. Cue the politics.</p><div class=""><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full mx-auto"><div class=""><img alt="Super App, System 1 and System 2 convene a UN summit to agree a model" loading="lazy" width="621" height="298" decoding="async" data-nimg="1" class="rounded-md" style="color:transparent" sizes="(max-width: 1280px) 100vw, 65vw" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexpose-canonical-models.16feb799.png&amp;w=640&amp;q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexpose-canonical-models.16feb799.png&amp;w=750&amp;q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexpose-canonical-models.16feb799.png&amp;w=828&amp;q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexpose-canonical-models.16feb799.png&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexpose-canonical-models.16feb799.png&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexpose-canonical-models.16feb799.png&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexpose-canonical-models.16feb799.png&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexpose-canonical-models.16feb799.png&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexpose-canonical-models.16feb799.png&amp;w=3840&amp;q=75"/><div class="text-center text-slate-500 mt-[1rem]">Super App, System 1 and System 2 convene a UN summit to agree a model</div></div></div></div><h3 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="3-our-data-is-extracted-to-a-separate-store"><a href="#3-our-data-is-extracted-to-a-separate-store" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>3. Our data is extracted to a separate  store</span></h3><p>An ETL pipeline is built to extract data from the providers and store it in a Data Lake or Data Warehouse in a normalized format</p><div class=""><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full mx-auto"><div class=""><img alt="Super App hitches it&#x27;s feature cart to the world&#x27;s longest train" loading="lazy" width="882" height="296" decoding="async" data-nimg="1" class="rounded-md" style="color:transparent" sizes="(max-width: 1280px) 100vw, 65vw" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdata-in-a-seperate-store.e671b14b.png&amp;w=640&amp;q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdata-in-a-seperate-store.e671b14b.png&amp;w=750&amp;q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdata-in-a-seperate-store.e671b14b.png&amp;w=828&amp;q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdata-in-a-seperate-store.e671b14b.png&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdata-in-a-seperate-store.e671b14b.png&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdata-in-a-seperate-store.e671b14b.png&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdata-in-a-seperate-store.e671b14b.png&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdata-in-a-seperate-store.e671b14b.png&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdata-in-a-seperate-store.e671b14b.png&amp;w=3840&amp;q=75"/><div class="text-center text-slate-500 mt-[1rem]">Super App hitches it&#x27;s feature cart to the world&#x27;s longest train</div></div></div></div><p>This solves the problem of each Super App that comes along having to solve the same problem of fetching and aggregating data from multiple sources, but it does bring with it some important restrictions.</p><p>The data is now coupled to the canonical model which has been enforced by the ETL pipeline and Data Warehouse. Getting functionality changes through to our Super App is now an IT project involving at least 3 teams (Source system, data pipeline and super app). This clearly makes the lead time of feature requests an immediate challenge.</p><p>Depending on your perspective of life as a data engineer, this is either fantastic or very frustrating.  As the team building the pipelines and warehouse, you’re involved in all the action, but you’re not responsible for any end user functionality - and therefore the delivery pressure.</p><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="how-orbital-does-it"><a href="#how-orbital-does-it" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>How Orbital does it</span></h2><p>Orbital approaches this problem differently by providing a flexible data layer for consumers to query data. It automatically aggregates and reshapes the source data based on the needs of the consumer, saving you a huge amount of time typically spent on integrating with other systems and transforming data.</p><div class=""><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full mx-auto"><div class=""><img alt="Super App asks it&#x27;s trusty friend Orbital to worry about how to resolve the data it needs" loading="lazy" width="621" height="296" decoding="async" data-nimg="1" class="rounded-md" style="color:transparent" sizes="(max-width: 1280px) 100vw, 65vw" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fhow-orbital-does-it.dee4d8e7.png&amp;w=640&amp;q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fhow-orbital-does-it.dee4d8e7.png&amp;w=750&amp;q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fhow-orbital-does-it.dee4d8e7.png&amp;w=828&amp;q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fhow-orbital-does-it.dee4d8e7.png&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fhow-orbital-does-it.dee4d8e7.png&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fhow-orbital-does-it.dee4d8e7.png&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fhow-orbital-does-it.dee4d8e7.png&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fhow-orbital-does-it.dee4d8e7.png&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fhow-orbital-does-it.dee4d8e7.png&amp;w=3840&amp;q=75"/><div class="text-center text-slate-500 mt-[1rem]">Super App asks it&#x27;s trusty friend Orbital to worry about how to resolve the data it needs</div></div></div></div><p>By using our open source data language, Taxi, we define a shared language of terms which can be used to describe the data provided by each individual system. This helps us to focus on the content of what systems are providing, rather than the format and structure of their data.</p><p>The result for our Super App is that by querying via Orbital, it’s not limited to the data which can be provided by the data pipeline layer. It also doesn’t have to worry about managing individual integrations with each provider. We get the best of both worlds!</p><p>As a bonus, when the providers inevitably change, Orbital adapts with them to ensure minimal impact to our Super App and other consumers. We don’t have to wait for negotiations about our canonical model, or for our data pipeline team to complete work to propagate changes. When our data providers change, we can immediately change with them. Dare I say it, but that sounds a little bit agile.</p><p><em>(The post <a href="https://orbitalhq.com/blog/2023-04-26-uniting-data-from-multiple-sources">Uniting similar data from multiple sources</a> appeared first on <a href="https://orbitalhq.com/blog">Orbital Blog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/api/og?path=/blog/2023-04-26-uniting-data-from-multiple-sources" length="0" type="image//api/og"/>
        </item>
        <item>
            <title><![CDATA[Hello, Typescript SDK]]></title>
            <link>https://orbitalhq.com/blog/2023-03-21-hello-typescript-sdk</link>
            <guid>Hello, Typescript SDK</guid>
            <pubDate>Thu, 23 Mar 2023 12:21:00 GMT</pubDate>
            <description><![CDATA[Using Orbital's Typescript SDK to connect your microservices and data sources]]></description>
            <content:encoded><![CDATA[<p>Hot on the heels of our <a href="/blog/2023-03-06-hello-kotlin-sdk">Kotlin SDK</a>, we’re excited to release our Typescript SDK that lets you fetch data from APIs, databases and kafka topics from within your browser or Nodejs apps, without writing any integration code.</p><p>The Typescript ecosystem is close to our hearts and we’re looking forward to bringing more features and examples in different web and nodejs frameworks over the next few months.</p><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="in-this-post"><a href="#in-this-post" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>In this post</span></h2><ul role="list"><li><a href="#submitting-taxi-ql">Submitting TaxiQL queries</a></li><li><a href="#type-safe-query-builder">Building a type-safe query</a></li><li><a href="#providing-parameters">Providing parameters</a></li><li><a href="#type-safe-querying">Type-safe querying</a></li><li><a href="#why-orbital">Why Orbital?</a></li><li><a href="#what-next">What next?</a></li></ul><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="getting-started"><a href="#getting-started" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Getting Started</span></h2><pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> @orbitalhq/orbital-client</code></pre><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="usage"><a href="#usage" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Usage</span></h2><p>There’s two methods of using the SDK depending on your preferred style. </p><ol role="list"><li>Submit a TaxiQL query string</li><li>Use the typesafe query building</li></ol><p>For both cases, the first step is to generate a taxonomy of terms based on the schemas registered with Orbital. That’s done using a script provided in the Orbital client npm package that connects to the Orbital schema server and downloads the typescript version of the taxonomy. Simply define an <code>orbital.config.json</code> file with the schema server URL and away you go.</p><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
    <span class="token property">&quot;schemaServerUrl&quot;</span><span class="token operator">:</span> <span class="token string">&quot;http://localhost:9305/&quot;</span>
<span class="token punctuation">}</span></code></pre><p>The content of the taxonomy depends on the data providers that have uploaded their schemas to Orbital. There’s more info available in our docs on how <a href="https://orbitalhq.com/docs/connecting-data-sources/overview">schemas can be published</a>.</p><p>To run the taxonomy generation script from your project:</p><pre class="language-bash"><code class="language-bash">npx orbital-generate</code></pre><h3 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="submitting-taxi-ql"><a href="#submitting-taxi-ql" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Submitting TaxiQL</span></h3><p>This method is closer to what you’d use if you’ve experimented with the Query Editor in the Orbital UI. If you’ve already written a query in the UI you’re happy with, you can generate this code directly from the Query Editor by clicking the the <code>copy</code> button .</p><pre class="language-typescript"><code class="language-typescript"><span class="token keyword">const</span> orbitalClient <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HttpQueryClient</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">http://localhost:9022</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
<span class="token keyword">let</span> films <span class="token operator">=</span> orbitalClient<span class="token punctuation">.</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token template-punctuation string">`</span></span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">
import film.types.FilmId
import film.types.Title
import com.petflix.listings.StreamingProviderName
import com.petflix.listings.StreamingProviderPrice

find { Film[] } as {
    id: FilmId
    title : Title

    // where can I watch this?
    provider: StreamingProviderName
    cost: StreamingProviderPrice
}[]
</span><span class="token template-punctuation string">`</span></span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>Here, we simply send the query string over to Orbital which describes:</p><ul role="list"><li>the data we want to find (Films), </li><li>which pieces of data we want (id and title) </li><li>the structure we want it in (flat).</li></ul><p>In our projection of the pieces of data we want, we’re asking for two different types of information. Some details about the film itself (the FilmId and the Title), and information about where it’s availabled to watch (StreamingProviderName and StreamingProviderPrice). </p><p>If we check out the query history in the Orbital UI after running this query, we can see that the data has come from two different systems. We fetched the <code>id</code> and <code>title</code> from our <code>Films</code> database, and then we used the <code>FilmId</code> to call our <code>StreamingProvidersService</code> to fetch the <code>provider</code> and <code>cost</code> properties.  </p><div class="breakout-image"><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full mx-auto lg:w-[65vw]"><div class=""><img alt="The query execution plan executed by Orbital" loading="lazy" width="1380" height="760" decoding="async" data-nimg="1" class="rounded-md" style="color:transparent" sizes="(max-width: 1280px) 100vw, 65vw" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fquery-execution-plan.24962ad7.png&amp;w=640&amp;q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fquery-execution-plan.24962ad7.png&amp;w=750&amp;q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fquery-execution-plan.24962ad7.png&amp;w=828&amp;q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fquery-execution-plan.24962ad7.png&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fquery-execution-plan.24962ad7.png&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fquery-execution-plan.24962ad7.png&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fquery-execution-plan.24962ad7.png&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fquery-execution-plan.24962ad7.png&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fquery-execution-plan.24962ad7.png&amp;w=3840&amp;q=75"/><div class="text-center text-slate-500 mt-[1rem]">The query execution plan executed by Orbital</div></div></div></div><p>It’s worth noting that when defining the structure of data we want to receive, we can use whatever property names we want. It’s the semantic tags that we’ve imported from our generated taxonomy that are significant. In this example, <code>FilmId</code> and <code>Title</code> are the tags we’ve used, shown as the types of the <code>id</code> and <code>title</code> properties of our response projection. </p><p>Check out our other content for why we’re advocating for <a href="https://orbitalhq.com/blog/2023-01-16-using-semantic-metadata">using semantic metadata</a> to queries and schemas. </p><p>You can also extract the query to a separate <code>*.taxi</code> where you can take advantage of our <a href="https://taxilang.org/taxi-vs-code/editor-plugins/">VSCode Taxi language plugin</a> for editing your query.</p><h3 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="type-safe-query-builder"><a href="#type-safe-query-builder" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Type safe query builder</span></h3><p>The other option is to use the query builder in our SDK which allows us to build our query as a series of chained functions. Just like in our query string, we’ll define the data we want, the properties we’re interested in, and the structure.</p><pre class="language-typescript"><code class="language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> com<span class="token punctuation">,</span> film <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&#x27;@/app/taxonomy&#x27;</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> filmTaxonomy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">film</span><span class="token punctuation">.</span><span class="token function">Taxonomy</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> filmTypesTaxonomy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">film</span><span class="token punctuation">.</span>types<span class="token punctuation">.</span><span class="token function">Taxonomy</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> listingsTaxonomy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">com</span><span class="token punctuation">.</span>petflix<span class="token punctuation">.</span>listings<span class="token punctuation">.</span><span class="token function">Taxonomy</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">let</span> films <span class="token operator">=</span> orbitalClient
    <span class="token comment">// What data do I want to find</span>
    <span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token function">asArray</span><span class="token punctuation">(</span>filmTaxonomy<span class="token punctuation">.</span>Film<span class="token punctuation">)</span><span class="token punctuation">)</span>

    <span class="token comment">// Which properties do I want returned, and in what structure</span>
    <span class="token punctuation">.</span><span class="token function">as</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        <span class="token comment">// The property names can be whatever you want</span>
        <span class="token comment">// The types on the right hand side are our semantic tags that describe</span>
        <span class="token comment">// to Orbital what data to find</span>
        id<span class="token operator">:</span> filmTypesTaxonomy<span class="token punctuation">.</span>FilmId<span class="token punctuation">,</span>
        title<span class="token operator">:</span> filmTypesTaxonomy<span class="token punctuation">.</span>Title<span class="token punctuation">,</span>
        provider<span class="token operator">:</span> listingsTaxonomy<span class="token punctuation">.</span>StreamingProviderName<span class="token punctuation">,</span>
        cost<span class="token operator">:</span> listingsTaxonomy<span class="token punctuation">.</span>StreamingProviderPrice
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">execute</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre><h3 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="providing-parameters"><a href="#providing-parameters" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Providing parameters</span></h3><p>Sometimes we want to be more specific about the data we’re fetching. Instead of ALL the films, maybe we want more detailed information about one film. </p><p>Orbital works with your existing API endpoints and data sources - so provided you’ve got and endpoint that returns a single Film from it’s Id, Orbital will automatically query it.</p><p>We’ll add an extra function call <code>given()</code>, using the semantic tag of the item we’re specifying, the film ID. </p><pre class="language-typescript"><code class="language-typescript"><span class="token keyword">import</span> <span class="token punctuation">{</span> com<span class="token punctuation">,</span> film <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&#x27;@/app/taxonomy&#x27;</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> filmTaxonomy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">film</span><span class="token punctuation">.</span><span class="token function">Taxonomy</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> filmTypesTaxonomy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">film</span><span class="token punctuation">.</span>types<span class="token punctuation">.</span><span class="token function">Taxonomy</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> listingsTaxonomy <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">com</span><span class="token punctuation">.</span>petflix<span class="token punctuation">.</span>listings<span class="token punctuation">.</span><span class="token function">Taxonomy</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">let</span> film <span class="token operator">=</span> orbitalClient
    <span class="token comment">// Return the data for the film with a FilmId of &quot;5&quot;</span>
    <span class="token punctuation">.</span><span class="token function">given</span><span class="token punctuation">(</span>filmTypesTaxonomy<span class="token punctuation">.</span>FilmId<span class="token punctuation">,</span> <span class="token string">&quot;5&quot;</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token function">asArray</span><span class="token punctuation">(</span>filmTaxonomy<span class="token punctuation">.</span>Film<span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">as</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        id<span class="token operator">:</span> filmTypesTaxonomy<span class="token punctuation">.</span>FilmId<span class="token punctuation">,</span>
        title<span class="token operator">:</span> filmTypesTaxonomy<span class="token punctuation">.</span>Title<span class="token punctuation">,</span>
        provider<span class="token operator">:</span> listingsTaxonomy<span class="token punctuation">.</span>StreamingProviderName<span class="token punctuation">,</span>
        cost<span class="token operator">:</span> listingsTaxonomy<span class="token punctuation">.</span>StreamingProviderPrice
      <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">execute</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="type-safe-querying"><a href="#type-safe-querying" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Type-safe querying</span></h2><p>A big advantage from using the DSL is type safe querying of our data. For whatever property names and structure we specify in our <code>as()</code> block, the responses from Orbital will be correctly typed.</p><p>That’s significant because instead of making a request to a service and providing a type parameter based on what the response <em>should</em> be, we’re asking Orbital to fetch specific data and return it in a specific structure. There’s a direct link between the types  we’re asking for from Orbital and how the data will be returned. Additionally, the response type of our query is set of our specific object, not typed as <code>any</code>.</p><p>For example, if I add in explicit types to the variable we’re assigning our response to, we’ll see that the Typescript compiler won’t raise any concerns.</p><pre class="language-typescript"><code class="language-typescript">
<span class="token keyword">let</span> films<span class="token operator">:</span> Observable<span class="token operator">&lt;</span><span class="token punctuation">{</span>
    <span class="token string-property property">&#x27;id&#x27;</span><span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">,</span>
    <span class="token string-property property">&#x27;title&#x27;</span><span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">,</span>
    <span class="token string-property property">&#x27;provider&#x27;</span><span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">,</span>
    <span class="token string-property property">&#x27;cost&#x27;</span><span class="token operator">:</span> <span class="token builtin">number</span>
<span class="token punctuation">}</span><span class="token operator">&gt;</span> <span class="token operator">=</span> orbitalClient
    <span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token function">asArray</span><span class="token punctuation">(</span>taxonomy<span class="token punctuation">.</span>film<span class="token punctuation">.</span>Film<span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">as</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        id<span class="token operator">:</span> taxonomy<span class="token punctuation">.</span>film<span class="token punctuation">.</span>types<span class="token punctuation">.</span>FilmId<span class="token punctuation">,</span>
        title<span class="token operator">:</span> taxonomy<span class="token punctuation">.</span>film<span class="token punctuation">.</span>types<span class="token punctuation">.</span>Title<span class="token punctuation">,</span>
        provider<span class="token operator">:</span> taxonomy<span class="token punctuation">.</span>com<span class="token punctuation">.</span>petflix<span class="token punctuation">.</span>listings<span class="token punctuation">.</span>StreamingProviderName<span class="token punctuation">,</span>
        cost<span class="token operator">:</span> taxonomy<span class="token punctuation">.</span>com<span class="token punctuation">.</span>petflix<span class="token punctuation">.</span>listings<span class="token punctuation">.</span>StreamingProviderPrice
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">execute</span><span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="why-orbital"><a href="#why-orbital" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Why Orbital?</span></h2><p>We think there’s some great ergonomics here for Typescript developers when fetching data. There’s also a bunch of other benefits you get from using Orbital to power your Typescript apps:</p><ul role="list"><li>Adapt to schema changes - your code will automatically adapt to changes in schemas</li><li>Eliminate integration code - you’ll eliminate loads of integration code and code-gen of other teams schemas</li><li>Consumer defined schemas - regardless of the tech used by other teams you’ll gain the power to pick and choose which data is delivered to you.</li><li>Observability - see exactly how an integration was performed in the Orbital console, including response payloads and cell level lineage</li></ul><p>Check out our <a href="https://orbitalhq.com/docs">docs</a> for more information.</p><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="what-next"><a href="#what-next" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>What next?</span></h2><p>In terms of where we’re heading, there’s a number of exciting features we’ll be adding in the near future. They’re already available in the core platform, and we’ll be adding support for them in the Typescript SDK.</p><ul role="list"><li>Streaming query results - for larger result sets, start receiving responses as a stream as soon as the first results become available</li><li>Subscriptions - connect to kafka topics and other streaming sources of data</li><li>Publishing schemas from Nodejs apps - similar to the capability in our Kotlin SDK, this let’s publishers add a couple of decorators to their code to push their schemas up to Orbital</li><li>Type safety for projections to nested data structures - query projections for the DSL are currently limited to flat objects. While the Orbital query runner is capable of returning results in any shape requested in the query string, the DSL option in the SDK isn’t able to provide type safety for nested structures.</li></ul><p><em>(The post <a href="https://orbitalhq.com/blog/2023-03-21-hello-typescript-sdk">Hello, Typescript SDK</a> appeared first on <a href="https://orbitalhq.com/blog">Orbital Blog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/api/og?path=/blog/2023-03-21-hello-typescript-sdk" length="0" type="image//api/og"/>
        </item>
        <item>
            <title><![CDATA[Building an API Hub with Spring Boot, Kotlin and Orbital]]></title>
            <link>https://orbitalhq.com/blog/2023-03-13-spring-boot-service-hub</link>
            <guid>Building an API Hub with Spring Boot, Kotlin and Orbital</guid>
            <pubDate>Mon, 13 Mar 2023 08:00:00 GMT</pubDate>
            <description><![CDATA[Spring boot is awesome for building Microservices.  Orbital is awesome for discovering and connecting them.  A match made in South west London]]></description>
            <content:encoded><![CDATA[<p>Spring Boot is an awesome framework for building Microservices, and Orbital is
an amazing platform for connecting those microservices together.</p><p>Orbital works by reading the specs of microservices, (eg., OpenApi, Raml, Protobuf or <a href="https://taxilang.org">Taxi</a>)
and building a large mesh of APIs.  </p><p>All this schema metadata is browsable in Orbital’s UI, and can be
an awesome hub for developers to discover and document their APIs - even without
using Orbital’s integration capabilities.</p><p>In this blog post, we’re going to explore creating an awesome self-updating developer
hub using Spring Boot, Kotlin, and Orbital’s API catalog.  </p><div class="breakout-image"><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full lg:w-[65vw] mx-auto"><div class="p-[1rem]"><img src="[object Object]" decoding="async" alt="A GIF showing the working catalog, diagrams and API explorer"/><div class="text-center text-slate-500 mt-[1rem]">A GIF showing the working catalog, diagrams and API explorer</div></div></div></div><p>Our microservices will publish their APIs directly to Orbital on startup, so that Orbital is always up-to-date.
There’s lots of <a href="/docs/connecting-data-sources/overview">different ways</a> to publish API specs to Orbital - but in this post we’ll focus on
a code-first workflow.</p><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="what-we-ll-get"><a href="#what-we-ll-get" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>What we&#x27;ll get</span></h2><p>At the end of this post, we’ll end up with a local instance of Orbital, with a
couple of Spring Boot microservices that self-publish their API’s.</p><p>We’ll get beautiful diagrams like this, which show the running services,
as well as how the data between them is related:</p><div class="breakout-image"><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full mx-auto lg:w-[65vw]"><div class=""><img alt="Orbital&#x27;s service diagram - showing two microservices, their APIs, and how they relate" loading="lazy" width="3451" height="1714" decoding="async" data-nimg="1" class="rounded-md" style="color:transparent" sizes="(max-width: 1280px) 100vw, 65vw" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fservices-diagram-final.d031d644.png&amp;w=640&amp;q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fservices-diagram-final.d031d644.png&amp;w=750&amp;q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fservices-diagram-final.d031d644.png&amp;w=828&amp;q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fservices-diagram-final.d031d644.png&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fservices-diagram-final.d031d644.png&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fservices-diagram-final.d031d644.png&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fservices-diagram-final.d031d644.png&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fservices-diagram-final.d031d644.png&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fservices-diagram-final.d031d644.png&amp;w=3840&amp;q=75"/><div class="text-center text-slate-500 mt-[1rem]">Orbital&#x27;s service diagram - showing two microservices, their APIs, and how they relate</div></div></div></div><p>In addition, Orbital gives us a rich data and API catalog, where we can search and play with APIs:</p><div class="breakout-image"><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full mx-auto lg:w-[65vw]"><div class=""><img alt="Service explorer lets developers see the endpoints and operations exposed by an API" loading="lazy" width="2985" height="1010" decoding="async" data-nimg="1" class="rounded-md" style="color:transparent" sizes="(max-width: 1280px) 100vw, 65vw" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fservice-explorer-final.b208331d.png&amp;w=640&amp;q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fservice-explorer-final.b208331d.png&amp;w=750&amp;q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fservice-explorer-final.b208331d.png&amp;w=828&amp;q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fservice-explorer-final.b208331d.png&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fservice-explorer-final.b208331d.png&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fservice-explorer-final.b208331d.png&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fservice-explorer-final.b208331d.png&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fservice-explorer-final.b208331d.png&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fservice-explorer-final.b208331d.png&amp;w=3840&amp;q=75"/><div class="text-center text-slate-500 mt-[1rem]">Service explorer lets developers see the endpoints and operations exposed by an API</div></div></div></div><div class="breakout-image"><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full mx-auto lg:w-[65vw]"><div class=""><img alt="The operation explorer lets us interact and play around with individual APIs" loading="lazy" width="2990" height="1955" decoding="async" data-nimg="1" class="rounded-md" style="color:transparent" sizes="(max-width: 1280px) 100vw, 65vw" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Foperation-explorer-final.5dbd2226.png&amp;w=640&amp;q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Foperation-explorer-final.5dbd2226.png&amp;w=750&amp;q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Foperation-explorer-final.5dbd2226.png&amp;w=828&amp;q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Foperation-explorer-final.5dbd2226.png&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Foperation-explorer-final.5dbd2226.png&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Foperation-explorer-final.5dbd2226.png&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Foperation-explorer-final.5dbd2226.png&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Foperation-explorer-final.5dbd2226.png&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Foperation-explorer-final.5dbd2226.png&amp;w=3840&amp;q=75"/><div class="text-center text-slate-500 mt-[1rem]">The operation explorer lets us interact and play around with individual APIs</div></div></div></div><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="the-spring-boot-app"><a href="#the-spring-boot-app" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>The Spring Boot app</span></h2><p>We’ll start out with a vanilla Spring Boot app:</p><button type="button" aria-hidden="true" style="position:fixed;top:1px;left:1px;width:1px;height:0;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0"></button><div class="not-prose bg-slate-800 rounded-xl shadow-md"><div class="flex"><div class="flex text-slate-400 text-xs leading-6 overflow-hidden rounded-tl-xl pt-2" role="tablist" aria-orientation="horizontal"><button class="flex items-center relative z-10 overflow-hidden px-4 py-1 [&amp;:not(:focus-visible)]:focus:outline-none text-sky-300" id="headlessui-tabs-tab-:Raog:" role="tab" type="button" aria-selected="true" tabindex="0" data-headlessui-state="selected"><span class="z-10">FilmListingsApp.kt</span><div class="pointer-events-none absolute inset-0 border-b border-b-sky-300"></div></button><button class="flex items-center relative z-10 overflow-hidden px-4 py-1 [&amp;:not(:focus-visible)]:focus:outline-none text-slate-400" id="headlessui-tabs-tab-:Riog:" role="tab" type="button" aria-selected="false" tabindex="-1" data-headlessui-state=""><span class="z-10">FilmListings.kt</span><div class="pointer-events-none absolute inset-0 bg-slate-700/50 border-y border-slate-500/30 border-l rounded-tl"></div><div class="pointer-events-none absolute inset-0 inset-y-px border-r border-slate-200/5 z-20"></div></button><button class="flex items-center relative z-10 overflow-hidden px-4 py-1 [&amp;:not(:focus-visible)]:focus:outline-none text-slate-400" id="headlessui-tabs-tab-:Rqog:" role="tab" type="button" aria-selected="false" tabindex="-1" data-headlessui-state=""><span class="z-10">Reviews.kt</span><div class="pointer-events-none absolute inset-0 bg-slate-700/50 border-y border-slate-500/30"></div><div class="pointer-events-none absolute inset-0 inset-y-px border-r border-slate-200/5 z-20"></div></button><button class="flex items-center relative z-10 overflow-hidden px-4 py-1 [&amp;:not(:focus-visible)]:focus:outline-none text-slate-400" id="headlessui-tabs-tab-:R12og:" role="tab" type="button" aria-selected="false" tabindex="-1" data-headlessui-state=""><span class="z-10">pom.xml</span><div class="pointer-events-none absolute inset-0 bg-slate-700/50 border-y border-slate-500/30"></div><div class="pointer-events-none absolute inset-0 inset-y-px border-r border-slate-200/5 z-20"></div></button></div><div class="flex-auto flex pt-2 rounded-tr-xl overflow-hidden"><div class="flex-auto flex justify-end bg-slate-700/50 border-y border-slate-500/30 pr-4"></div></div></div><div class="flex overflow-auto"><div class="flex-none min-w-full p-5 text-sm leading-6 text-slate-50 ligatures-none" id="headlessui-tabs-panel-:R38g:" role="tabpanel" tabindex="0" data-headlessui-state="selected"><pre class="language-kotlin"><code class="language-kotlin"><span class="token keyword">package</span> com<span class="token punctuation">.</span>petflix<span class="token punctuation">.</span>voyager<span class="token punctuation">.</span>listings

<span class="token keyword">import</span> org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>beans<span class="token punctuation">.</span>factory<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span>Autowired
<span class="token keyword">import</span> org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>beans<span class="token punctuation">.</span>factory<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span>Value
<span class="token keyword">import</span> org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>boot<span class="token punctuation">.</span>SpringApplication
<span class="token keyword">import</span> org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>boot<span class="token punctuation">.</span>autoconfigure<span class="token punctuation">.</span>SpringBootApplication
<span class="token keyword">import</span> org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>boot<span class="token punctuation">.</span>info<span class="token punctuation">.</span>GitProperties
<span class="token keyword">import</span> org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span>Bean
<span class="token keyword">import</span> org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span>Configuration
<span class="token keyword">import</span> org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>stereotype<span class="token punctuation">.</span>Component

<span class="token annotation builtin">@SpringBootApplication</span>
<span class="token keyword">open</span> <span class="token keyword">class</span> FilmListingsApp <span class="token punctuation">{</span>

  <span class="token keyword">companion</span> <span class="token keyword">object</span> <span class="token punctuation">{</span>
      <span class="token keyword">val</span> logger <span class="token operator">=</span> LoggerFactory<span class="token punctuation">.</span><span class="token function">getLogger</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">.</span>java<span class="token punctuation">)</span>

      <span class="token annotation builtin">@JvmStatic</span>
      <span class="token keyword">fun</span> <span class="token function">main</span><span class="token punctuation">(</span>args<span class="token operator">:</span> Array<span class="token operator">&lt;</span>String<span class="token operator">&gt;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
          SpringApplication<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span>FilmListingsApp<span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">.</span>java<span class="token punctuation">,</span> <span class="token operator">*</span>args<span class="token punctuation">)</span>
      <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><span id="headlessui-tabs-panel-:R58g:" role="tabpanel" tabindex="-1" style="position:fixed;top:1px;left:1px;width:1px;height:0;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0"></span><span id="headlessui-tabs-panel-:R78g:" role="tabpanel" tabindex="-1" style="position:fixed;top:1px;left:1px;width:1px;height:0;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0"></span><span id="headlessui-tabs-panel-:R98g:" role="tabpanel" tabindex="-1" style="position:fixed;top:1px;left:1px;width:1px;height:0;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0"></span></div></div><div class="my-12 flex rounded-lg p-px bg-gradient-to-b from-sky-400 to-sky-700"><div class="bg-slate-800 rounded-lg p-4 w-full h-full"><div class="flex-auto"><div class="flex mb-4"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true" data-slot="icon" class="h-8 w-8 mr-4 text-sky-900 dark:text-sky-400"><path stroke-linecap="round" stroke-linejoin="round" d="M12 18v-5.25m0 0a6.01 6.01 0 0 0 1.5-.189m-1.5.189a6.01 6.01 0 0 1-1.5-.189m3.75 7.478a12.06 12.06 0 0 1-4.5 0m3.75 2.383a14.406 14.406 0 0 1-3 0M14.25 18v-.192c0-.983.658-1.823 1.508-2.316a7.5 7.5 0 1 0-7.517 0c.85.493 1.509 1.333 1.509 2.316V18"></path></svg><p class="m-0 font-display text-xl text-sky-900 dark:text-sky-400">Heads up...</p></div><div class="prose text-sky-800 [--tw-prose-background:theme(colors.sky.50)] prose-a:text-sky-900 prose-code:text-sky-900 dark:text-slate-300 dark:prose-code:text-slate-300"><p>To keep this example simple, we&#x27;re deploying a single Spring boot application with multiple API endpoints, each simulating a different microservice.</p><p>In practice, each of these controllers would be seperate microservices and Spring Boot applications. We&#x27;ll leave that as an exercise for the reader. You got this.</p></div></div></div></div><p>This consists of:</p><ul role="list"><li>A maven <code>pom.xml</code> file, declaring our vanilla Spring Boot dependencies, and a JPA database</li><li><code>FilmListingsApp.kt</code> - The spring boot app class file</li><li><code>FilmListings.kt</code> - A Spring Data repository and controller for listing films</li><li><code>Reviews.kt</code> - A Spring Data repository and controller for listing reviews of our films</li></ul><p>Since these are all pretty standard, we won’t go into them in more detail here</p><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="starting-orbital"><a href="#starting-orbital" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Starting Orbital</span></h2><p>To get Orbital running, grab the docker compose from <a href="https://start.orbitalhq.com">start.orbitalhq.com</a>
and start Orbital running</p><pre class="language-bash"><code class="language-bash"><span class="token function">curl</span> https://start.orbitalhq.com <span class="token operator">&gt;</span> docker-compose.yml
<span class="token function">docker-compose</span> up <span class="token parameter variable">-d</span></code></pre><p>If you head over to <a href="http://localhost:9022">http://localhost:9022</a> you should see Orbital running, and
waiting for connections</p><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="publishing-our-schemas"><a href="#publishing-our-schemas" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Publishing our schemas</span></h2><p>Next up, let’s get our Spring Boot applications publishing their schemas.</p><p>When the apps start, they’ll create a schema (using Taxi), and publish them up.</p><p>Note - you don’t have to use Taxi here - if you already have an OpenAPI spec
you can use that, by following the [docs](/docs/describing - data - sources / open - api).</p><p>First, we’ll add some dependencies to our Maven:</p><pre class="language-xml"><code class="language-xml">  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>properties</span><span class="token punctuation">&gt;</span></span>
     <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>taxi.version</span><span class="token punctuation">&gt;</span></span>1.36.2<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>taxi.version</span><span class="token punctuation">&gt;</span></span>
     <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>orbital.version</span><span class="token punctuation">&gt;</span></span>0.22.0<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>taxi.version</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>properties</span><span class="token punctuation">&gt;</span></span>
 <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependencies</span><span class="token punctuation">&gt;</span></span>
    <span class="token comment">&lt;!-- others omitted --&gt;</span>

      <span class="token comment">&lt;!-- A publisher, which will push our service schema
      to Orbital on startup --&gt;</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
         <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>com.orbitalhq<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
         <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>schema-rsocket-publisher<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
         <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>version</span><span class="token punctuation">&gt;</span></span>${orbital.version}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>version</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>

      <span class="token comment">&lt;!-- The taxi codegen, which generates schemas for a spring boot app --&gt;</span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
         <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.taxilang<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
         <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>java-spring-taxi<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
         <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>version</span><span class="token punctuation">&gt;</span></span>${taxi.version}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>version</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependencies</span><span class="token punctuation">&gt;</span></span>

   <span class="token comment">&lt;!-- Also, add the Orbital maven repository --&gt;</span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>repositories</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>repository</span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>id</span><span class="token punctuation">&gt;</span></span>orbital<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>id</span><span class="token punctuation">&gt;</span></span>
          <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>url</span><span class="token punctuation">&gt;</span></span>https://repo.orbitalhq.com/release<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>url</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>repository</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>repositories</span><span class="token punctuation">&gt;</span></span></code></pre><p>Now, add a Kotlin class with the following code:</p><pre class="language-kotlin"><code class="language-kotlin"><span class="token keyword">import</span> com<span class="token punctuation">.</span>orbitalhq<span class="token punctuation">.</span>PackageMetadata
<span class="token keyword">import</span> com<span class="token punctuation">.</span>orbitalhq<span class="token punctuation">.</span>schema<span class="token punctuation">.</span>publisher<span class="token punctuation">.</span>SchemaPublisherService
<span class="token keyword">import</span> com<span class="token punctuation">.</span>orbitalhq<span class="token punctuation">.</span>schema<span class="token punctuation">.</span>publisher<span class="token punctuation">.</span>rsocket<span class="token punctuation">.</span>RSocketSchemaPublisherTransport
<span class="token keyword">import</span> com<span class="token punctuation">.</span>orbitalhq<span class="token punctuation">.</span>schema<span class="token punctuation">.</span>rsocket<span class="token punctuation">.</span>TcpAddress
<span class="token keyword">import</span> lang<span class="token punctuation">.</span>taxi<span class="token punctuation">.</span>generators<span class="token punctuation">.</span>java<span class="token punctuation">.</span>spring<span class="token punctuation">.</span>SpringTaxiGenerator
<span class="token comment">/**
 * Create a task, which runs on startup, generating &amp; publishing our schema
 */</span>
<span class="token annotation builtin">@Component</span>
<span class="token keyword">class</span> <span class="token function">RegisterSchemaTask</span><span class="token punctuation">(</span>
   <span class="token annotation builtin">@Value</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">&quot;\$\{spring.application.name}&quot;</span></span><span class="token punctuation">)</span> appName<span class="token operator">:</span> String<span class="token punctuation">,</span>
   <span class="token annotation builtin">@Value</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">&quot;\$\{server.port}&quot;</span></span><span class="token punctuation">)</span> <span class="token keyword">private</span> <span class="token keyword">val</span> serverPort<span class="token operator">:</span> String
<span class="token punctuation">)</span> <span class="token punctuation">{</span>
   <span class="token keyword">init</span> <span class="token punctuation">{</span>
      <span class="token comment">/**
       * Declare a publisher, which will connect to the local running Orbital,
       * and publish the generated schema
       */</span>
      <span class="token keyword">val</span> publisher <span class="token operator">=</span> <span class="token function">SchemaPublisherService</span><span class="token punctuation">(</span>
         appName<span class="token punctuation">,</span>
         <span class="token function">RSocketSchemaPublisherTransport</span><span class="token punctuation">(</span>
            <span class="token comment">// Orbital accepts schema submissions over</span>
            <span class="token comment">// RSocket using port 7655</span>
            <span class="token function">TcpAddress</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">&quot;localhost&quot;</span></span><span class="token punctuation">,</span> <span class="token number">7655</span><span class="token punctuation">)</span>
         <span class="token punctuation">)</span>
      <span class="token punctuation">)</span>
      publisher<span class="token punctuation">.</span><span class="token function">publish</span><span class="token punctuation">(</span>
         <span class="token comment">// Package metadata identifies this project.</span>
         <span class="token comment">// Kinda like maven poms, or npm package.json</span>
         <span class="token comment">// This can be whatever you want, but make it unique to this service</span>
         PackageMetadata<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span>
            organisation <span class="token operator">=</span> <span class="token string-literal singleline"><span class="token string">&quot;io.petflix.demos&quot;</span></span><span class="token punctuation">,</span>
            name <span class="token operator">=</span> <span class="token string-literal singleline"><span class="token string">&quot;films-listings&quot;</span></span>
         <span class="token punctuation">)</span><span class="token punctuation">,</span>
         <span class="token comment">// The generator creates Taxi schemas.</span>
         <span class="token comment">// The base url should be the url of this application.</span>
         <span class="token comment">// All published URLs are relative to this url</span>
         SpringTaxiGenerator<span class="token punctuation">.</span><span class="token function">forBaseUrl</span><span class="token punctuation">(</span><span class="token string-literal singleline"><span class="token string">&quot;http://localhost:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token expression">serverPort</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&quot;</span></span><span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">forPackage</span><span class="token punctuation">(</span>FilmListingsApp<span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">.</span>java<span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">generate</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
      <span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
   <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><p>That’s it!  Now, restart your application.</p><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="exploring-our-catalog"><a href="#exploring-our-catalog" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Exploring our catalog</span></h2><p>Inside Orbital, Click on the Catalog tab, and then the Services Diagram tab.</p><p>You should now see a diagram, showing our two API’s.</p><p>Clicking on any of the endpoints will also add the response schema to the diagram.</p><div class="breakout-image"><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full lg:w-[65vw] mx-auto"><div class="p-[1rem]"><img src="/_next/static/media/orbital-catalog-1.9d23782b.gif" decoding="async" alt="Our services diagram"/><div class="text-center text-slate-500 mt-[1rem]">Our services diagram</div></div></div></div><p>Our catalog also already has rich information about our services - including an API browser,
and data catalog.</p><div class="breakout-image"><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full lg:w-[65vw] mx-auto"><div class="p-[1rem]"><img src="/_next/static/media/orbital-catalog-2.3aa1c9ab.gif" decoding="async" alt="The data and API catalog"/><div class="text-center text-slate-500 mt-[1rem]">The data and API catalog</div></div></div></div><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="going-further-exposing-links-between-our-ap-is"><a href="#going-further-exposing-links-between-our-ap-is" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Going further - Exposing links between our APIs</span></h2><p>So far, we have a pretty rich catalog, from just a few lines of code.</p><p>However, there’s important relationships here that we’re not exposing.</p><p>The Id from the Films can be passed to my Review service to lookup a review.This is key information for developers who are trying to navigate between services to
Get Stuff Done.</p><div class="breakout-image"><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full mx-auto lg:w-[65vw]"><div class=""><img alt="There&#x27;s a missing relationship between the Film model and the ReviewService" loading="lazy" width="1808" height="790" decoding="async" data-nimg="1" class="rounded-md" style="color:transparent" sizes="(max-width: 1280px) 100vw, 65vw" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmissing-relationship.25da7f02.png&amp;w=640&amp;q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmissing-relationship.25da7f02.png&amp;w=750&amp;q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmissing-relationship.25da7f02.png&amp;w=828&amp;q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmissing-relationship.25da7f02.png&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmissing-relationship.25da7f02.png&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmissing-relationship.25da7f02.png&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmissing-relationship.25da7f02.png&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmissing-relationship.25da7f02.png&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fmissing-relationship.25da7f02.png&amp;w=3840&amp;q=75"/><div class="text-center text-slate-500 mt-[1rem]">There&#x27;s a missing relationship between the Film model and the ReviewService</div></div></div></div><p>However, we’re in luck.</p><p>The schema that was generated is actually built using <a href="https://taxilang.org">Taxi</a> - an <a href="https://gitlab.com/taxi-lang/taxi-lang">open source</a> schema language that focuses
on describing the semantic relationship of data between services.</p><p>Taxi has amazing support for Kotlin, and lets us use Kotlin’s <code>typealias</code> to express that the data
is related.</p><p>First, let’s define a type alias:</p><pre class="language-kotlin"><code class="language-kotlin"><span class="token keyword">import</span> lang<span class="token punctuation">.</span>taxi<span class="token punctuation">.</span>annotations<span class="token punctuation">.</span>DataType

<span class="token comment">// The DataType annotation from </span>
<span class="token annotation builtin">@DataType</span>
<span class="token keyword">typealias</span> FilmId <span class="token operator">=</span> Int</code></pre><p>Then update our code to use this.</p><p>There’s a few places we can change:</p><pre class="language-diff-kotlin"><code class="language-diff-kotlin"><span class="token language-kotlin unchanged"><span class="token comment">// Update the response object our API returns</span><span class="token plain"></span>
</span><span class="token language-kotlin unchanged"><span class="token plain"></span><span class="token annotation builtin">@Entity</span><span class="token plain"></span>
</span><span class="token language-kotlin unchanged"><span class="token plain"></span><span class="token keyword">data</span><span class="token plain"> </span><span class="token keyword">class</span><span class="token plain"> </span><span class="token function">Film</span><span class="token punctuation">(</span><span class="token plain"></span>
</span><span class="token language-kotlin unchanged"><span class="token plain"> </span><span class="token annotation builtin">@Id</span><span class="token plain"></span>
</span><span class="token language-kotlin deleted"><span class="token plain">  </span><span class="token keyword">val</span><span class="token plain"> filmId</span><span class="token operator">:</span><span class="token plain"> Int</span><span class="token punctuation">,</span><span class="token plain"></span>
</span><span class="token language-kotlin inserted"><span class="token plain">  </span><span class="token keyword">val</span><span class="token plain"> filmId</span><span class="token operator">:</span><span class="token plain"> FilmId</span><span class="token punctuation">,</span><span class="token plain"></span>
</span><span class="token language-kotlin unchanged"><span class="token plain"> </span><span class="token keyword">val</span><span class="token plain"> title</span><span class="token operator">:</span><span class="token plain"> String</span>
</span><span class="token language-kotlin unchanged"><span class="token plain"></span><span class="token punctuation">)</span>
</span></code></pre><pre class="language-diff-kotlin"><code class="language-diff-kotlin"><span class="token language-kotlin unchanged"><span class="token comment">// Update the input into our Review service</span><span class="token plain"></span>
</span><span class="token language-kotlin unchanged"><span class="token plain"></span><span class="token keyword">fun</span><span class="token plain"> </span><span class="token function">getReviewsForFilm</span><span class="token punctuation">(</span><span class="token plain"></span>
</span><span class="token language-kotlin deleted"><span class="token plain"> </span><span class="token annotation builtin">@PathVariable</span><span class="token punctuation">(</span><span class="token string-literal singleline string">&quot;filmId&quot;</span><span class="token punctuation">)</span><span class="token plain"> filmId</span><span class="token operator">:</span><span class="token plain"> Int</span>
</span><span class="token language-kotlin inserted"><span class="token plain"> </span><span class="token annotation builtin">@PathVariable</span><span class="token punctuation">(</span><span class="token string-literal singleline string">&quot;filmId&quot;</span><span class="token punctuation">)</span><span class="token plain"> filmId</span><span class="token operator">:</span><span class="token plain"> FilmId</span>
</span><span class="token language-kotlin unchanged"><span class="token plain"></span><span class="token punctuation">)</span><span class="token operator">:</span><span class="token plain"> Review </span><span class="token punctuation">{</span><span class="token plain"></span>
</span><span class="token language-kotlin unchanged"><span class="token plain"></span><span class="token keyword">return</span><span class="token plain"> repo</span><span class="token punctuation">.</span><span class="token function">findAllByFilmId</span><span class="token punctuation">(</span><span class="token plain">filmId</span><span class="token punctuation">)</span><span class="token plain"></span>
</span><span class="token language-kotlin unchanged"><span class="token plain"></span><span class="token punctuation">}</span>
</span></code></pre><p>Now, if restart the Spring Boot app, our updated schema will get published directly to Orbital.</p><p>Refreshing the services diagram now shows an updated diagram with the relationship mapped:</p><div class="breakout-image"><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full mx-auto lg:w-[65vw]"><div class=""><img alt="Using type aliases, the relationship between services can be mapped" loading="lazy" width="2006" height="795" decoding="async" data-nimg="1" class="rounded-md" style="color:transparent" sizes="(max-width: 1280px) 100vw, 65vw" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fupdated-services-diagram.48afe9cc.png&amp;w=640&amp;q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fupdated-services-diagram.48afe9cc.png&amp;w=750&amp;q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fupdated-services-diagram.48afe9cc.png&amp;w=828&amp;q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fupdated-services-diagram.48afe9cc.png&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fupdated-services-diagram.48afe9cc.png&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fupdated-services-diagram.48afe9cc.png&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fupdated-services-diagram.48afe9cc.png&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fupdated-services-diagram.48afe9cc.png&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fupdated-services-diagram.48afe9cc.png&amp;w=3840&amp;q=75"/><div class="text-center text-slate-500 mt-[1rem]">Using type aliases, the relationship between services can be mapped</div></div></div></div><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="changelog"><a href="#changelog" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Changelog</span></h2><p>We just pushed a change to our schema.While this one was fairly harmless(changing an input type from<code>Int</code> to<code>typealias FilmId = Int</code>),
it’s useful to know when changes occur.</p><p>Orbital has a full changelog, every time a change is pushed.</p><p>Navigate over to the Schemas tab, and see the changelog entry</p><div class="breakout-image"><div class="relative my-[2em] first:mt-0 last:mb-0 rounded-lg rounded-lg w-full mx-auto lg:w-[65vw]"><div class=""><img alt="Orbital&#x27;s changelog shows changes to APIs as they&#x27;re published" loading="lazy" width="2555" height="1364" decoding="async" data-nimg="1" class="rounded-md" style="color:transparent" sizes="(max-width: 1280px) 100vw, 65vw" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fchangelog.f94fc0b8.png&amp;w=640&amp;q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fchangelog.f94fc0b8.png&amp;w=750&amp;q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fchangelog.f94fc0b8.png&amp;w=828&amp;q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fchangelog.f94fc0b8.png&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fchangelog.f94fc0b8.png&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fchangelog.f94fc0b8.png&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fchangelog.f94fc0b8.png&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fchangelog.f94fc0b8.png&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fchangelog.f94fc0b8.png&amp;w=3840&amp;q=75"/><div class="text-center text-slate-500 mt-[1rem]">Orbital&#x27;s changelog shows changes to APIs as they&#x27;re published</div></div></div></div><h2 class="group flex whitespace-pre-wrap -ml-4 pl-4" id="summary"><a href="#summary" class="absolute -ml-10 flex items-center opacity-0 border-0 group-hover:opacity-100" aria-label="Anchor">​<div class="w-6 h-6 text-slate-400 ring-1 ring-slate-900/5 rounded-md shadow-sm flex items-center justify-center hover:ring-slate-900/10 hover:shadow hover:text-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:shadow-none dark:ring-0"><svg width="12" height="12" fill="none" aria-hidden="true"><path d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path></svg></div></a><span>Summary</span></h2><p>That’s a lot of catalog, for only a few lines of change.</p><p>To recap - the only change we needed to make to our Spring Boot application
was adding our schema publisher - about a dozen lines of simple code.</p><p>Of course, we can go much further— Orbital’s real power is using the
data in these schemas to automate integration between services.Check out
our [Kotlin SDK](/blog/2023 - 03 - 06 - hello - kotlin - sdk) for more information!</p><p>As always, if you have any questions, come chat to us on <a href="https://join.slack.com/t/orbitalapi/shared_invite/zt-697laanr-DHGXXak5slqsY9DqwrkzHg">Slack</a>,
or reach out on Twitter(either <a href="https://twitter.com/marty_pitt">me</a>, or our <a href="https://twitter.com/orbitalapi">team</a>)</p><p><em>(The post <a href="https://orbitalhq.com/blog/2023-03-13-spring-boot-service-hub">Building an API Hub with Spring Boot, Kotlin and Orbital</a> appeared first on <a href="https://orbitalhq.com/blog">Orbital Blog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/api/og?path=/blog/2023-03-13-spring-boot-service-hub" length="0" type="image//api/og"/>
        </item>
    </channel>
</rss>