Files

79 lines
20 KiB
HTML

<!DOCTYPE html><html class="default" lang="en" data-base="./"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>@nats-io/services</title><meta name="description" content="Documentation for @nats-io/services"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="assets/style.css"/><link rel="stylesheet" href="assets/highlight.css"/><script defer src="assets/main.js"></script><script async src="assets/icons.js" id="tsd-icons-script"></script><script async src="assets/search.js" id="tsd-search-script"></script><script async src="assets/navigation.js" id="tsd-nav-script"></script><script async src="assets/hierarchy.js" id="tsd-hierarchy-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="index.html" class="title">@nats-io/services</a><div id="tsd-toolbar-links"></div><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="assets/icons.svg#icon-search"></use></svg></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="assets/icons.svg#icon-menu"></use></svg></a></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><h1>@nats-io/services</h1></div><div class="tsd-panel tsd-typography"><p><a href="./LICENSE"><img src="https://img.shields.io/badge/Licence-Apache%202.0-blue.svg" alt="License"></a>
<img src="https://github.com/nats-io/nats.js/actions/workflows/test.yml/badge.svg" alt="services">
<a href="https://nats-io.github.io/nats.js/services/index.html"><img src="https://img.shields.io/badge/JSDoc-reference-blue" alt="JSDoc"></a></p>
<p><a href="https://jsr.io/@nats-io/services"><img src="https://jsr.io/badges/@nats-io/services" alt="JSR"></a>
<a href="https://jsr.io/@nats-io/services"><img src="https://jsr.io/badges/@nats-io/services/score" alt="JSR"></a></p>
<p><a href="https://www.npmjs.com/package/@nats-io/services"><img src="https://img.shields.io/npm/v/%40nats-io%2Fservices" alt="NPM Version"></a>
<img src="https://img.shields.io/npm/dt/%40nats-io%2Fservices" alt="NPM Downloads">
<img src="https://img.shields.io/npm/dm/%40nats-io%2Fservices" alt="NPM Downloads"></p>
<h1 id="services" class="tsd-anchor-link">Services<a href="#services" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h1><p>For a quick overview of the libraries and how to install them, see
<a href="media/runtimes.md">runtimes.md</a>.</p>
<p>The Services module introduces a higher-level API for implementing services with
NATS. NATS has always been a strong technology on which to build services, as
they are easy to write, are location and DNS independent and can be scaled up or
down by simply adding or removing instances of the service.</p>
<p>The services module further streamlines NATS services development by providing
observability and standardization. The Service Framework allows your services to
be discovered, queried for status and schema information without additional
work.</p>
<p>To create services using the services module simply install this library and
create a <code>new Svc(nc)</code>.</p>
<h2 id="creating-a-service" class="tsd-anchor-link">Creating a Service<a href="#creating-a-service" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2><pre><code class="typescript"><span class="hl-0">const</span><span class="hl-1"> </span><span class="hl-2">svc</span><span class="hl-1"> = </span><span class="hl-0">new</span><span class="hl-1"> </span><span class="hl-3">Svc</span><span class="hl-1">(</span><span class="hl-4">nc</span><span class="hl-1">);</span><br/><span class="hl-0">const</span><span class="hl-1"> </span><span class="hl-2">service</span><span class="hl-1"> = </span><span class="hl-5">await</span><span class="hl-1"> </span><span class="hl-4">svc</span><span class="hl-1">.</span><span class="hl-3">add</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-4">name:</span><span class="hl-1"> </span><span class="hl-6">&quot;max&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-4">version:</span><span class="hl-1"> </span><span class="hl-6">&quot;0.0.1&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-4">description:</span><span class="hl-1"> </span><span class="hl-6">&quot;returns max number in a request&quot;</span><span class="hl-1">,</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-7">// add an endpoint listening on &quot;max&quot;</span><br/><span class="hl-0">const</span><span class="hl-1"> </span><span class="hl-2">max</span><span class="hl-1"> = </span><span class="hl-4">service</span><span class="hl-1">.</span><span class="hl-3">addEndpoint</span><span class="hl-1">(</span><span class="hl-6">&quot;max&quot;</span><span class="hl-1">, (</span><span class="hl-4">err</span><span class="hl-1">, </span><span class="hl-4">msg</span><span class="hl-1">) </span><span class="hl-0">=&gt;</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-4">msg</span><span class="hl-1">?.</span><span class="hl-3">respond</span><span class="hl-1">();</span><br/><span class="hl-1">});</span>
</code><button type="button">Copy</button></pre>
<p>If you omit the handler, the service is actually an iterator for service
messages. To process messages incoming to the service:</p>
<pre><code class="typescript"><span class="hl-5">for</span><span class="hl-1"> </span><span class="hl-5">await</span><span class="hl-1"> (</span><span class="hl-0">const</span><span class="hl-1"> </span><span class="hl-2">r</span><span class="hl-1"> </span><span class="hl-0">of</span><span class="hl-1"> </span><span class="hl-4">max</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-4">r</span><span class="hl-1">.</span><span class="hl-3">respond</span><span class="hl-1">();</span><br/><span class="hl-1">}</span>
</code><button type="button">Copy</button></pre>
<p>For those paying attention, this looks suspiciously like a regular subscription.
And it is. The only difference is that the service collects additional
<em>metadata</em> that allows the service framework to provide some monitoring and
discovery for free.</p>
<p>To invoke the service, it is a simple NATS request:</p>
<pre><code class="typescript"><span class="hl-0">const</span><span class="hl-1"> </span><span class="hl-2">response</span><span class="hl-1"> = </span><span class="hl-5">await</span><span class="hl-1"> </span><span class="hl-4">nc</span><span class="hl-1">.</span><span class="hl-3">request</span><span class="hl-1">(</span><span class="hl-6">&quot;max&quot;</span><span class="hl-1">, </span><span class="hl-2">JSON</span><span class="hl-1">.</span><span class="hl-3">stringify</span><span class="hl-1">([</span><span class="hl-8">1</span><span class="hl-1">, </span><span class="hl-8">2</span><span class="hl-1">, </span><span class="hl-8">3</span><span class="hl-1">]));</span>
</code><button type="button">Copy</button></pre>
<h2 id="discovery-and-monitoring" class="tsd-anchor-link">Discovery and Monitoring<a href="#discovery-and-monitoring" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2><p>When the service started, the framework automatically assigned it an unique
<code>ID</code>. The <code>name</code> and <code>ID</code> identify particular instance of the service. If you
start a second instance, that instance will also have the same <code>name</code> but will
sport a different <code>ID</code>.</p>
<p>To discover services that are running, create a monitoring client:</p>
<pre><code class="typescript"><span class="hl-0">const</span><span class="hl-1"> </span><span class="hl-2">m</span><span class="hl-1"> = </span><span class="hl-4">svc</span><span class="hl-1">.</span><span class="hl-3">client</span><span class="hl-1">();</span><br/><br/><span class="hl-7">// you can ping, request info, and stats information.</span><br/><span class="hl-7">// All the operations return iterators describing the services found.</span><br/><span class="hl-5">for</span><span class="hl-1"> </span><span class="hl-5">await</span><span class="hl-1"> (</span><span class="hl-0">const</span><span class="hl-1"> </span><span class="hl-2">s</span><span class="hl-1"> </span><span class="hl-0">of</span><span class="hl-1"> </span><span class="hl-5">await</span><span class="hl-1"> </span><span class="hl-4">m</span><span class="hl-1">.</span><span class="hl-3">ping</span><span class="hl-1">()) {</span><br/><span class="hl-1"> </span><span class="hl-4">console</span><span class="hl-1">.</span><span class="hl-3">log</span><span class="hl-1">(</span><span class="hl-4">s</span><span class="hl-1">.</span><span class="hl-4">id</span><span class="hl-1">);</span><br/><span class="hl-1">}</span><br/><span class="hl-5">await</span><span class="hl-1"> </span><span class="hl-4">m</span><span class="hl-1">.</span><span class="hl-3">stats</span><span class="hl-1">();</span><br/><span class="hl-5">await</span><span class="hl-1"> </span><span class="hl-4">m</span><span class="hl-1">.</span><span class="hl-3">info</span><span class="hl-1">();</span>
</code><button type="button">Copy</button></pre>
<p>Additional filtering is possible, and they are valid for all the operations:</p>
<pre><code class="typescript"><span class="hl-7">// get the stats services that have the name &quot;max&quot;</span><br/><span class="hl-5">await</span><span class="hl-1"> </span><span class="hl-4">m</span><span class="hl-1">.</span><span class="hl-3">stats</span><span class="hl-1">(</span><span class="hl-6">&quot;max&quot;</span><span class="hl-1">);</span><br/><span class="hl-7">// or target a specific instance:</span><br/><span class="hl-5">await</span><span class="hl-1"> </span><span class="hl-4">m</span><span class="hl-1">.</span><span class="hl-3">stats</span><span class="hl-1">(</span><span class="hl-6">&quot;max&quot;</span><span class="hl-1">, </span><span class="hl-4">id</span><span class="hl-1">);</span>
</code><button type="button">Copy</button></pre>
<p>For a more elaborate first example see:
<a href="media/01_services.ts">simple example here</a></p>
<h2 id="multiple-endpoints" class="tsd-anchor-link">Multiple Endpoints<a href="#multiple-endpoints" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2><p>More complex services will have more than one endpoint. For example a calculator
service may have endpoints for <code>sum</code>, <code>average</code>, <code>max</code>, etc. This type of
service is also possible with the service api.</p>
<p>You can create the service much like before. In this case, you don't need the
endpoint (yet!):</p>
<pre><code class="typescript"><span class="hl-0">const</span><span class="hl-1"> </span><span class="hl-2">calc</span><span class="hl-1"> = </span><span class="hl-5">await</span><span class="hl-1"> </span><span class="hl-4">nc</span><span class="hl-1">.</span><span class="hl-4">services</span><span class="hl-1">.</span><span class="hl-3">add</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-4">name:</span><span class="hl-1"> </span><span class="hl-6">&quot;calc&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-4">version:</span><span class="hl-1"> </span><span class="hl-6">&quot;0.0.1&quot;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-4">description:</span><span class="hl-1"> </span><span class="hl-6">&quot;example calculator service&quot;</span><span class="hl-1">,</span><br/><span class="hl-1">});</span>
</code><button type="button">Copy</button></pre>
<p>One of the simplifications for service it that it helps build consistent subject
hierarchy for your services. To create a subject hierarchy, you add a <em>group</em>.</p>
<pre><code class="typescript"><span class="hl-0">const</span><span class="hl-1"> </span><span class="hl-2">g</span><span class="hl-1"> = </span><span class="hl-4">calc</span><span class="hl-1">.</span><span class="hl-3">addGroup</span><span class="hl-1">(</span><span class="hl-6">&quot;calc&quot;</span><span class="hl-1">);</span>
</code><button type="button">Copy</button></pre>
<p>The group is a <em>prefix</em> subject where you can add endpoints. The name can be
anything that is a valid subject prefix.</p>
<pre><code class="typescript"><span class="hl-0">const</span><span class="hl-1"> </span><span class="hl-2">sums</span><span class="hl-1"> = </span><span class="hl-4">g</span><span class="hl-1">.</span><span class="hl-3">addEndpoint</span><span class="hl-1">(</span><span class="hl-6">&quot;sum&quot;</span><span class="hl-1">);</span><br/><span class="hl-1">(</span><span class="hl-0">async</span><span class="hl-1"> () </span><span class="hl-0">=&gt;</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-5">for</span><span class="hl-1"> </span><span class="hl-5">await</span><span class="hl-1"> (</span><span class="hl-0">const</span><span class="hl-1"> </span><span class="hl-2">m</span><span class="hl-1"> </span><span class="hl-0">of</span><span class="hl-1"> </span><span class="hl-4">sums</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-7">// decode the message payload into an array of numbers</span><br/><span class="hl-1"> </span><span class="hl-0">const</span><span class="hl-1"> </span><span class="hl-2">numbers</span><span class="hl-1"> = </span><span class="hl-4">m</span><span class="hl-1">.</span><span class="hl-3">json</span><span class="hl-1">&lt;</span><span class="hl-9">number</span><span class="hl-1">[]&gt;();</span><br/><span class="hl-1"> </span><span class="hl-7">// add them together</span><br/><span class="hl-1"> </span><span class="hl-0">const</span><span class="hl-1"> </span><span class="hl-2">s</span><span class="hl-1"> = </span><span class="hl-4">numbers</span><span class="hl-1">.</span><span class="hl-3">reduce</span><span class="hl-1">((</span><span class="hl-4">sum</span><span class="hl-1">, </span><span class="hl-4">v</span><span class="hl-1">) </span><span class="hl-0">=&gt;</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-5">return</span><span class="hl-1"> </span><span class="hl-4">sum</span><span class="hl-1"> + </span><span class="hl-4">v</span><span class="hl-1">;</span><br/><span class="hl-1"> });</span><br/><span class="hl-1"> </span><span class="hl-7">// return a number</span><br/><span class="hl-1"> </span><span class="hl-4">m</span><span class="hl-1">.</span><span class="hl-3">respond</span><span class="hl-1">(</span><span class="hl-2">JSON</span><span class="hl-1">.</span><span class="hl-3">stringify</span><span class="hl-1">(</span><span class="hl-4">s</span><span class="hl-1">));</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">})();</span>
</code><button type="button">Copy</button></pre>
<p><code>addEndpoint()</code> takes a name, and an optional handler (it can also take a set of
options). The <code>name</code> must be a simple name. This means no dots, wildcards, etc.
<code>name</code> is then appended to the group where it is added, forming the subject
where the endpoint listens.</p>
<p>In the above case, the <code>sum</code> endpoint is listening for requests on <code>calc.sum</code>.</p>
<p>For those paying attention, you can specify a callback much like in the first
example, if you don't, the return value of the add endpoint is an iterator.</p>
<p>For a complete example see:
<a href="media/02_multiple_endpoints.ts">multiple endpoints</a></p>
</div></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-external" name="external"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>External</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div><details open class="tsd-accordion tsd-page-navigation"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="assets/icons.svg#icon-chevronDown"></use></svg><h3>On This Page</h3></summary><div class="tsd-accordion-details"><a href="#services"><span>Services</span></a><ul><li><a href="#creating-a-service"><span>Creating a <wbr/>Service</span></a></li><li><a href="#discovery-and-monitoring"><span>Discovery and <wbr/>Monitoring</span></a></li><li><a href="#multiple-endpoints"><span>Multiple <wbr/>Endpoints</span></a></li></ul></div></details></div><div class="site-menu"><nav class="tsd-navigation"><a href="modules.html">@nats-io/services</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>