<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jonas Gauffin</title>
    <description>The latest articles on DEV Community by Jonas Gauffin (@jgauffin).</description>
    <link>https://dev.to/jgauffin</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1108%2F7d88381e-7a75-4f83-8211-9c3e73455a4f.png</url>
      <title>DEV Community: Jonas Gauffin</title>
      <link>https://dev.to/jgauffin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jgauffin"/>
    <language>en</language>
    <item>
      <title>Live API specs for coding agents</title>
      <dc:creator>Jonas Gauffin</dc:creator>
      <pubDate>Sun, 30 Aug 2026 12:33:00 +0000</pubDate>
      <link>https://dev.to/jgauffin/live-api-specs-for-coding-agents-2dcm</link>
      <guid>https://dev.to/jgauffin/live-api-specs-for-coding-agents-2dcm</guid>
      <description>&lt;h1&gt;
  
  
  Live API specs for coding agents
&lt;/h1&gt;

&lt;p&gt;An agent writing frontend code has to know the backend's API. It has three options. It can read the backend source and work out from scratch what the service already publishes. It can ask you, which promotes you to API documentation. Or it can swallow the entire OpenAPI document in order to use one route out of it.&lt;/p&gt;

&lt;p&gt;Then it does the same thing again tomorrow, against a stale &lt;code&gt;swagger.json&lt;/code&gt; you exported last week.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docs-mcpserver&lt;/code&gt; takes the spec straight from the running service, caches it, and serves it one operation at a time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The config
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"cacheDir"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./cache"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"libraries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"orders-api"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Order handling service"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"sources"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"origin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://localhost:5001/openapi/v1.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"schema"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"orders"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; docs-mcpserver
claude mcp add docs &lt;span class="nt"&gt;--&lt;/span&gt; docs-mcpserver &lt;span class="nt"&gt;--config&lt;/span&gt; /path/to/dev-docs.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the whole setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  One operation, not the whole spec
&lt;/h2&gt;

&lt;p&gt;The agent lists the definitions in &lt;code&gt;orders&lt;/code&gt;, picks the one it needs, and fetches that. For an OpenAPI document the path operations are exposed as definitions named &lt;code&gt;GET /orders/{id}&lt;/code&gt;, so it can also search by keyword.&lt;/p&gt;

&lt;p&gt;A few hundred tokens for the operation it is writing against, instead of the entire document. That keeps working as the service grows, which a pasted spec does not.&lt;/p&gt;

&lt;h2&gt;
  
  
  The backend does not have to be running
&lt;/h2&gt;

&lt;p&gt;Every call is answered from the cached spec, never from the network. The fetch happens on startup and then in the background while you work, so an endpoint you added 20 seconds ago is already visible.&lt;/p&gt;

&lt;p&gt;Start the backend once, shut it down, and keep building the frontend. The agent still has real routes and real payload shapes. If the service is down, or answers with something that is not a spec, the last known-good copy keeps being served.&lt;/p&gt;

&lt;p&gt;Code and issues: &lt;a href="https://github.com/jgauffin/dev-docs-mcp" rel="noopener noreferrer"&gt;github.com/jgauffin/dev-docs-mcp&lt;/a&gt;. On npm as &lt;code&gt;docs-mcpserver&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>ai</category>
      <category>openapi</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Giving AI agents knowledge they were never trained on</title>
      <dc:creator>Jonas Gauffin</dc:creator>
      <pubDate>Thu, 14 May 2026 22:02:53 +0000</pubDate>
      <link>https://dev.to/jgauffin/giving-ai-agents-knowledge-they-were-never-trained-on-5fd7</link>
      <guid>https://dev.to/jgauffin/giving-ai-agents-knowledge-they-were-never-trained-on-5fd7</guid>
      <description>&lt;p&gt;I love coding my own stuff, and my clients typically have lots of internal specifications and libraries to use.&lt;/p&gt;

&lt;p&gt;But since LLMs haven't been trained on that, it's hard to get them to code accurately using those specs, libraries, or frameworks.&lt;/p&gt;

&lt;p&gt;You can, of course, let the agents parse everything, but that wastes tokens and your patience :)&lt;/p&gt;

&lt;p&gt;The same goes for well-known libraries, but you are stuck on a specific version that you must follow. You don't want it to guess the API.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docs-mcpserver&lt;/code&gt; exists to deal with both.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it is
&lt;/h2&gt;

&lt;p&gt;It is an MCP server that provides an agent with accurate knowledge of a framework or specification using documentation as the medium. It reads three kinds of docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Markdown docs&lt;/strong&gt; — your &lt;code&gt;*.md&lt;/code&gt; files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API reference&lt;/strong&gt; — C# XML documentation, or TypeDoc JSON.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Schema&lt;/strong&gt; — JSON Schema, OpenAPI 3.x, Swagger 2.0.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What the agent gets out of it is the same in every case: the real names, the real&lt;br&gt;
signatures, the real shapes. Sources can come from a&lt;br&gt;
local folder or straight from a GitHub URL. A single&lt;br&gt;
server instance can host several libraries side by side. For instance, your in-house framework, a client's framework, and a specific version of some public library. &lt;/p&gt;

&lt;p&gt;The agent picks which one to query.&lt;/p&gt;

&lt;p&gt;I personally have used it to code against a specification called DATEX (traffic information for roads), which is HUGE, my own &lt;a href="https://github.com/relax-js/core" rel="noopener noreferrer"&gt;SPA library&lt;/a&gt;, and against sound format specifications for a sound app I'm building.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why not just give the agent the files
&lt;/h2&gt;

&lt;p&gt;You could point the agent to the folders and let it read them. The MCP server does a few things that raw file access does not:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It is sandboxed.&lt;/strong&gt; Each source is scoped, with path-traversal protection. The
agent reads what you exposed, nothing else on the disk.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It reads in pieces.&lt;/strong&gt; Instead of loading a 4000-line reference file, the agent
asks for the table of contents, then pulls the one chapter it needs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It searches properly.&lt;/strong&gt; Dedicated search tools with regex and glob support,
instead of the agent improvising its own grep.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It is self-describing.&lt;/strong&gt; With several libraries configured, the agent calls
one tool to discover what is available. You do not have to spell out every path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub works without cloning.&lt;/strong&gt; Give it a repo URL and it handles the rest.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The multi-library part is the point. Instead of running several MCP servers for&lt;br&gt;
documentation, you get one with a small toolset. No token waste.&lt;/p&gt;
&lt;h2&gt;
  
  
  Setting it up
&lt;/h2&gt;

&lt;p&gt;Install and build:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The quick way, a single folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docs-mcpserver ./docs &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"My Docs"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the real use case — several libraries — use a config file. Here is an&lt;br&gt;
in-house framework served from disk, next to a pinned version of a public&lt;br&gt;
library pulled from GitHub:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dev-docs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Frameworks the model has not been trained on"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"cacheDir"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./cache"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"libraries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"acme-core"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Our internal application framework"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"sources"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"disk"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"origin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./frameworks/acme-core/docs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"docs"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"disk"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"origin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./frameworks/acme-core/api"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"api"&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"somelib-3.2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SomeLib, pinned to v3.2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"sources"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"github"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"origin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://github.com/someorg/somelib/tree/v3.2.0/docs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"docs"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start it with the config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docs-mcpserver &lt;span class="nt"&gt;--config&lt;/span&gt; dev-docs.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And register it with Claude Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add mydocs &lt;span class="nt"&gt;--&lt;/span&gt; node /path/to/markdown-docs-mcp/dist/index.js &lt;span class="nt"&gt;--config&lt;/span&gt; /path/to/dev-docs.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For private GitHub repos, set &lt;code&gt;GITHUB_TOKEN&lt;/code&gt; in the environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the agent actually sees
&lt;/h2&gt;

&lt;p&gt;Each library exposes tools based on the &lt;code&gt;kind&lt;/code&gt; of its sources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;docs&lt;/strong&gt; — &lt;code&gt;get_doc_index&lt;/code&gt;, &lt;code&gt;get_sub_index&lt;/code&gt;, &lt;code&gt;read_doc_file&lt;/code&gt;, &lt;code&gt;get_file_toc&lt;/code&gt;,
&lt;code&gt;get_chapters&lt;/code&gt;, &lt;code&gt;search_docs&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;api&lt;/strong&gt; — &lt;code&gt;get_api_index&lt;/code&gt;, &lt;code&gt;get_api_type&lt;/code&gt;, &lt;code&gt;get_api_member&lt;/code&gt;, &lt;code&gt;search_api&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;schema&lt;/strong&gt; — &lt;code&gt;list_schemas&lt;/code&gt;, &lt;code&gt;list_definitions&lt;/code&gt;, &lt;code&gt;get_definition&lt;/code&gt;,
&lt;code&gt;search_definitions&lt;/code&gt;, &lt;code&gt;search_all_schemas&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A typical run looks like this. The agent calls &lt;code&gt;list_libraries&lt;/code&gt; and sees&lt;br&gt;
&lt;code&gt;acme-core&lt;/code&gt; and &lt;code&gt;somelib-3.2&lt;/code&gt;. It needs to know how &lt;code&gt;acme-core&lt;/code&gt; handles&lt;br&gt;
configuration, so it calls &lt;code&gt;search_docs&lt;/code&gt; with &lt;code&gt;library: "acme-core"&lt;/code&gt;, finds the&lt;br&gt;
right file, asks for its table of contents with &lt;code&gt;get_file_toc&lt;/code&gt;, then pulls the&lt;br&gt;
one relevant section with &lt;code&gt;get_chapters&lt;/code&gt;. It answers the question without ever&lt;br&gt;
loading the whole file.&lt;/p&gt;

&lt;p&gt;When multiple libraries are configured, every tool takes a &lt;code&gt;library&lt;/code&gt; parameter.&lt;br&gt;
When there is only one, the parameter disappears, and the tools behave like a&lt;br&gt;
plain single-library server.&lt;/p&gt;

&lt;p&gt;The same applies to schema sources. For an OpenAPI spec, path operations show up&lt;br&gt;
as definitions named like &lt;code&gt;GET /pets&lt;/code&gt;, so the agent can ask for one endpoint&lt;br&gt;
without reading the whole document. Useful when you want the agent to call your&lt;br&gt;
API correctly rather than guess at the shape of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generating the API input
&lt;/h2&gt;

&lt;p&gt;One thing worth knowing up front: the &lt;code&gt;api&lt;/code&gt; pipeline does not read source code.&lt;br&gt;
It consumes a generated documentation file.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TypeScript / JavaScript&lt;/strong&gt; — use TypeDoc's JSON serializer:
&lt;code&gt;typedoc --json api.json src/index.ts&lt;/code&gt;. Point the source at that &lt;code&gt;.json&lt;/code&gt; file.
The markdown output from &lt;code&gt;typedoc-plugin-markdown&lt;/code&gt; is not supported — it has to
be the JSON serializer output.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;C#&lt;/strong&gt; — enable &lt;code&gt;&amp;lt;GenerateDocumentationFile&amp;gt;true&amp;lt;/GenerateDocumentationFile&amp;gt;&lt;/code&gt;
and point the source at the generated &lt;code&gt;*.xml&lt;/code&gt; file, or the build output folder
that contains it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What it does not do
&lt;/h2&gt;

&lt;p&gt;It does not read source code. If you want API reference, you generate the doc&lt;br&gt;
file first, as above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;The code is on &lt;a href="https://github.com/jgauffin/dev-docs-mcp" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, or on npm as &lt;code&gt;docs-mcpserver&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Feel free to leave feedback, or check my other MCP servers on &lt;a href="https://github.com/jgauffin" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>ai</category>
      <category>typescript</category>
      <category>llm</category>
    </item>
    <item>
      <title>Exception handling explained</title>
      <dc:creator>Jonas Gauffin</dc:creator>
      <pubDate>Thu, 10 May 2018 11:33:24 +0000</pubDate>
      <link>https://dev.to/jgauffin/exception-handling-explained-ima</link>
      <guid>https://dev.to/jgauffin/exception-handling-explained-ima</guid>
      <description>&lt;p&gt;This article explains what exception handling is and how it differs from&lt;br&gt;
traditional error handling with error codes. The article does not get&lt;br&gt;
into usage or exception classes, but only to explain their purpose.&lt;/p&gt;

&lt;p&gt;Let's start with errors.&lt;/p&gt;
&lt;h1&gt;
  
  
  A brief introduction to error
&lt;/h1&gt;

&lt;p&gt;From the dawn of programming, error codes have been used to deal with errors in applications. An error code is used to indicate if the&lt;br&gt;
executed function was successful or not.&lt;/p&gt;

&lt;p&gt;Here is a simple example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;SaveDefaultAccount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;accountName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetUserIdFromName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;accountId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetAccountFromName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;accountName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;accountId&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;StoreDefaultAccount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;accountId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The example illustrates that when you use error codes, it is the API&lt;br&gt;
consumer that must abort if something fails. You might, but how about&lt;br&gt;
the rest of the team, or those who maintained the application before&lt;br&gt;
you? It is like you would retire the entire police force and expect&lt;br&gt;
&lt;strong&gt;&lt;em&gt;all&lt;/em&gt;&lt;/strong&gt; citizens to behave and be good law abiding citizens.&lt;/p&gt;

&lt;p&gt;One developer could have been lazy and just written (or refactored) the&lt;br&gt;
code as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;SaveDefaultAccount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;accountName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetUserIdFromName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Arne"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;accountId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetAccountFromName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Savings account"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;StoreDefaultAccount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;accountId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem is that the code looks perfectly legal, but silently ignores&lt;br&gt;
errors. If you for instance mistakenly add a white space after all&lt;br&gt;
account names on the account selection page, the code above starts to&lt;br&gt;
fail silently. What's worse is that you will not know about it until&lt;br&gt;
code dependent upon the default account starts to fail, and that can be&lt;br&gt;
after a while. Tracking down that subsequent error can be challenging,&lt;br&gt;
primarily if the default account is set in different ways.&lt;/p&gt;

&lt;p&gt;Error codes are easy to get started with and can be quite powerful. Even&lt;br&gt;
modern languages like Go-lang uses errors instead of exceptions. Here is&lt;br&gt;
a go snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="p"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"filename.ext"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While errors are easy to understand and use, they have three&lt;br&gt;
significant drawbacks:&lt;/p&gt;
&lt;h2&gt;
  
  
  They do not convey context
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;This section is for languages that only uses error codes.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For instance, error code 2 means "File Not Found" in Windows. There is&lt;br&gt;
no way to state which file nor other information that might help you to&lt;br&gt;
understand why the file was missing. Error codes are just that. Codes&lt;br&gt;
that indicate a specific error, without context or clues.&lt;/p&gt;

&lt;p&gt;The problem with that is that it is hard to understand why or under what&lt;br&gt;
circumstances that the error occurred. The Windows API solves this by&lt;br&gt;
introducing a method called &lt;code&gt;GetLastError()&lt;/code&gt; which is used to get more&lt;br&gt;
information about the error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;OFSTRUCT&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;HFILE&lt;/span&gt; &lt;span class="n"&gt;hFile&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;OpenFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"d:\\sample.txt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OF_READ&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hFile&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;HFILE_ERROR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// all this is required to get the error message.&lt;/span&gt;
    &lt;span class="c1"&gt;// you typically add it to a separate function&lt;/span&gt;

    &lt;span class="c1"&gt;// Get the error code, as hFile only indicates an error&lt;/span&gt;
    &lt;span class="c1"&gt;// but not which one.&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;errorCode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetLastError&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Get the generic error message which&lt;/span&gt;
    &lt;span class="c1"&gt;// represents the above error code.&lt;/span&gt;
    &lt;span class="n"&gt;LPVOID&lt;/span&gt; &lt;span class="n"&gt;lpMsgBuf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;LPVOID&lt;/span&gt; &lt;span class="n"&gt;lpDisplayBuf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;FormatMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;FORMAT_MESSAGE_ALLOCATE_BUFFER&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; 
        &lt;span class="n"&gt;FORMAT_MESSAGE_FROM_SYSTEM&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;
        &lt;span class="n"&gt;FORMAT_MESSAGE_IGNORE_INSERTS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;errorCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nf"&gt;MAKELANGID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LANG_NEUTRAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SUBLANG_DEFAULT&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LPTSTR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;lpMsgBuf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NULL&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My point is that an error code is not enough when you want to&lt;br&gt;
&lt;em&gt;solve&lt;/em&gt; the error.&lt;/p&gt;
&lt;h2&gt;
  
  
  The burden is on the function caller
&lt;/h2&gt;

&lt;p&gt;It is safe to say that all applications have errors, it is exceptionally&lt;br&gt;
rare (pun intended) that errors can be ignored. Ignoring errors might&lt;br&gt;
seem to work, but sooner or later consequential problems will surface.&lt;br&gt;
It will be much harder to find the root cause since the found error is&lt;br&gt;
just a consequence of the first one. Any kind of "fix" is just a&lt;br&gt;
workaround which clutters the code base but does not prevent the root&lt;br&gt;
cause from happening again.&lt;/p&gt;

&lt;p&gt;It is crucial that all errors are handled in your code. When you use&lt;br&gt;
error codes, it is so easy to ignore or forget errors. Had a tight&lt;br&gt;
deadline? Wrestled with an obscure bug or incomprehensible requirements?&lt;br&gt;
Those situations make it so easy to take a shortcut. If not all&lt;br&gt;
developers on your team have the same discipline, errors will get&lt;br&gt;
ignored.&lt;/p&gt;
&lt;h1&gt;
  
  
  Enter exceptions
&lt;/h1&gt;

&lt;p&gt;Exceptions are for exceptional situations. If something didn't go as&lt;br&gt;
expected, you got an exceptional situation.&lt;/p&gt;

&lt;p&gt;Sounds easy, huh?&lt;/p&gt;

&lt;p&gt;But what does that mean?&lt;/p&gt;
&lt;h2&gt;
  
  
  An exceptional example
&lt;/h2&gt;

&lt;p&gt;If you expect that something can fail, you should guard against that&lt;br&gt;
situation.&lt;/p&gt;

&lt;p&gt;Here is an example:&lt;/p&gt;

&lt;p&gt;Let's say that you love shopping the newest and hottest technical&lt;br&gt;
gadgets. When the new gadget is released, you want to be first.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fo83dfiz9eacxmggbl7pf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fo83dfiz9eacxmggbl7pf.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Scenario 1
&lt;/h3&gt;

&lt;p&gt;If you are like most of us, you can probably not just go on a shopping&lt;br&gt;
spree. You need to make sure that you have enough money.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Check your bank account.&lt;/li&gt;
&lt;li&gt; Go shopping.&lt;/li&gt;
&lt;li&gt; Pay&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Scenario 2
&lt;/h3&gt;

&lt;p&gt;However, if you are fortunate enough to have plenty of money, you can&lt;br&gt;
go shopping directly:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Go shopping.&lt;/li&gt;
&lt;li&gt; Pay&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  The difference
&lt;/h3&gt;

&lt;p&gt;In the first scenario, we have a known issue that we need to deal with:&lt;br&gt;
A money limit. Therefore, we always need to check that we have enough&lt;br&gt;
money. In the second scenario, we should have enough money.&lt;/p&gt;

&lt;p&gt;What happens if someone has hacked us in scenario 2:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Someone hacked us&lt;/li&gt;
&lt;li&gt; Go shopping&lt;/li&gt;
&lt;li&gt; Pay &amp;lt;-- Failed, no money&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In that case, we got an exception, since it is a case that shouldn't&lt;br&gt;
happen since we &lt;strong&gt;&lt;em&gt;expect&lt;/em&gt;&lt;/strong&gt; to have enough money.&lt;/p&gt;

&lt;p&gt;That is an exceptional situation.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;em&gt;Why can't we always write the code like in scenario 1?&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;First, it's about communicating intent. We mostly get a set of business&lt;br&gt;
requirements that we should fulfill. They tell us what to expect when&lt;br&gt;
implementing different use cases. If we go and add many checks for&lt;br&gt;
things that might, but should not, happen we lose the connection between&lt;br&gt;
our use cases and the code. It will be hard to tell the intent of the&lt;br&gt;
code, which in turn lead to assumptions and in the end decreased code&lt;br&gt;
quality.&lt;/p&gt;

&lt;p&gt;Second, if we add many checks we are coding workarounds as the real&lt;br&gt;
problem is that our account was hacked, not that we could not pay. By&lt;br&gt;
adding checks and abort instead of paying we are hiding that fact.&lt;/p&gt;
&lt;h2&gt;
  
  
  What exceptions are
&lt;/h2&gt;

&lt;p&gt;Exceptions are for situations that wasn't considered when defining what&lt;br&gt;
the application should do. When writing a messaging library for message&lt;br&gt;
queues you expect to receive complete messages, but when you write one&lt;br&gt;
for TCP you expect to receive partial messages. What's exceptional in&lt;br&gt;
one case doesn't necessarily have to be exceptional in another.&lt;/p&gt;

&lt;p&gt;If you would open a file there are several errors that can happen.&lt;br&gt;
Non-existent directory, file is missing, access denied, partial file,&lt;br&gt;
etc. All those errors are known to most programmers, so they are not&lt;br&gt;
exceptions, right?&lt;/p&gt;

&lt;p&gt;Wrong. In most cases, they are exceptions. Because you typically do&lt;br&gt;
expect that a file exists and that it's complete and readable. Well, if&lt;br&gt;
you are writing a data forensics application, most of those errors are&lt;br&gt;
expected and should be dealt with (and therefore not exceptional cases).&lt;/p&gt;
&lt;h3&gt;
  
  
  Exceptions exist to prevent your application from doing something stupid.
&lt;/h3&gt;

&lt;p&gt;It's crucial for you to understand that. Don't think of exceptions as&lt;br&gt;
something you can use to control your application when coding. Think of&lt;br&gt;
exceptions as a mechanism to guard against your application doing&lt;br&gt;
something wrong/unexpected.&lt;/p&gt;
&lt;h3&gt;
  
  
  Exceptions exist to help you fix problems in the future
&lt;/h3&gt;

&lt;p&gt;Since exceptions are not a flow control mechanism, they do add little&lt;br&gt;
value when executing your code (previously described point excluded).&lt;/p&gt;

&lt;p&gt;However, writing informative exception messages makes it much easier to&lt;br&gt;
correct future bugs, since they add context to the error. Always try to&lt;br&gt;
do so, your future self will thank you for it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Code example
&lt;/h2&gt;

&lt;p&gt;Let's take the same code as was found in the beginning of this article,&lt;br&gt;
but changed to use exception handling instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;SaveDefaultAccount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;accountName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetUserIdFromName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Arne"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;accountId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetAccountFromName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Savings account"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;StoreDefaultAccount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;accountId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the method now returns void as it does not need to&lt;br&gt;
indicate that everything went successfully. Nor does it need to validate&lt;br&gt;
error codes from the called methods. One can safely assume that an&lt;br&gt;
exception abort the processing if the expected result cannot be&lt;br&gt;
guaranteed.&lt;/p&gt;

&lt;p&gt;In fact, in most cases, we do not have to care if exceptions are thrown&lt;br&gt;
at all. Remember, exceptions are used to communicate that something&lt;br&gt;
unexpected happened. If we cannot predict it, how on earth could we be&lt;br&gt;
able to handle the exception?&lt;/p&gt;

&lt;p&gt;Let's look at the &lt;code&gt;StoreDefaultAccount&lt;/code&gt; method. The most important thing&lt;br&gt;
to understand is that the method says that a default account should be&lt;br&gt;
stored successfully. Since that is the method promise, we must throw an&lt;br&gt;
exception every time we find something that would prevent the default&lt;br&gt;
account from being stored.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;StoreDefaultAccount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;accountId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ArgumentOutOfRangeException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"A valid user id must be specified."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;accountId&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ArgumentOutOfRangeException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;accountId&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;accountId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"A valid account id must be specified."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;account&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_accountRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;accountId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerId&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;accountId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;InvalidOperationException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"User &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; do not own account &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;accountId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_userRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DefaultAccount&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;accountId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;_userRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first two exceptions are used to mitigate errors like parse errors&lt;br&gt;
or invalid data.&lt;/p&gt;

&lt;p&gt;The third exception is for a business rule. We may only use the user's&lt;br&gt;
own accounts as default accounts.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;_accountRepository.GetById(accountId);&lt;/code&gt; will in turn throw an&lt;br&gt;
exception if the given accountId do not exist in the database since the&lt;br&gt;
method name states that an account should be fetched.&lt;/p&gt;

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

&lt;p&gt;The purpose of exceptions is not to allow you to take different actions&lt;br&gt;
depending on if something failed or not. i.e.&amp;nbsp;they are not a flow&lt;br&gt;
control mechanism. Instead, exceptions are used to make sure that your&lt;br&gt;
application delivers the expected result (or die trying).&lt;/p&gt;

&lt;p&gt;With that in mind, I hope that you find them as useful as I do. With&lt;br&gt;
the right mindset (and using exceptions) you can save much time since&lt;br&gt;
you do not have to track down why your database has a lot of data&lt;br&gt;
inconsistencies (which leads to bugs later).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article is part of our exception handling series. To learn more, visit our &lt;a href="https://coderr.io/exception-handling/" rel="noopener noreferrer"&gt;website&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>exceptions</category>
      <category>errors</category>
    </item>
  </channel>
</rss>
