<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Api-Design on Brian Faust</title><link>https://wimdy.works/tags/api-design/</link><description>Recent content in Api-Design on Brian Faust</description><generator>Hugo</generator><language>en-US</language><lastBuildDate>Mon, 01 Jan 0001 00:00:00 +0000</lastBuildDate><atom:link href="https://wimdy.works/tags/api-design/rss.xml" rel="self" type="application/rss+xml"/><item><title>The Engine Prices Parcels, Not Copies</title><link>https://wimdy.works/thoughts/the-engine-prices-parcels-not-copies/</link><pubDate>Sun, 01 Mar 2026 00:00:00 +0000</pubDate><guid>https://wimdy.works/thoughts/the-engine-prices-parcels-not-copies/</guid><description>&lt;p&gt;I dropped the package-copy shortcut during the rating engine&amp;rsquo;s development.
If a shipment contained ten parcels, I wanted ten parcel records, not one
record with &lt;code&gt;copies: 10&lt;/code&gt;. Count-based pricing stayed. The alternative way of
describing the things being priced didn&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;This was an earlier input-model decision, not another change made during the
Go port. It matters to the rest of the engine because parcels acquire
references: a transport leg carries particular parcels, an item allocation
belongs to a particular parcel, and a package-scoped rule needs that parcel&amp;rsquo;s
facts. A multiplier doesn&amp;rsquo;t answer those questions without more conventions.&lt;/p&gt;</description></item><item><title>Boolean Parameters Hide Different Operations</title><link>https://wimdy.works/thoughts/boolean-parameters-hide-different-operations/</link><pubDate>Sun, 01 Mar 2020 00:00:00 +0000</pubDate><guid>https://wimdy.works/thoughts/boolean-parameters-hide-different-operations/</guid><description>&lt;p&gt;This method call is legal:&lt;/p&gt;
&lt;figure class="code-figure"&gt;
 &lt;div class="code-block" data-copy-code&gt;
 &lt;button class="copy-code" type="button" aria-label="Copy code"&gt;copy&lt;/button&gt;&lt;span class="sr-only" data-copy-status role="status" aria-live="polite"&gt;&lt;/span&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$exporter&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$accountId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
 &lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;It is also semantically wrong.&lt;/p&gt;
&lt;p&gt;The first boolean in the exporter meant “source billing details from
the effective payer.” The payload still targeted the original account and kept
that account&amp;rsquo;s operational fields. The second boolean meant “the source&amp;rsquo;s
billing mode is an authoritative instruction.”&lt;/p&gt;
&lt;p&gt;An effective-payer export described who pays; it was not allowed to change the
original account&amp;rsquo;s billing mode. The &lt;code&gt;true, true&lt;/code&gt; combination therefore had to
be neutralized by a later guard.&lt;/p&gt;</description></item><item><title>Renaming a Field Is a Protocol Migration</title><link>https://wimdy.works/thoughts/renaming-a-field-is-a-protocol-migration/</link><pubDate>Thu, 01 Nov 2018 00:00:00 +0000</pubDate><guid>https://wimdy.works/thoughts/renaming-a-field-is-a-protocol-migration/</guid><description>&lt;p&gt;An API changes &lt;code&gt;serviceIds&lt;/code&gt; to &lt;code&gt;deliveryOptionIds&lt;/code&gt;. The new name describes the
domain better, and the implementation is easier to read. It is probably the
better name. That is also beside the point.&lt;/p&gt;
&lt;p&gt;An existing client still sends:&lt;/p&gt;
&lt;figure class="code-figure"&gt;
 &lt;div class="code-block" data-copy-code&gt;
 &lt;button class="copy-code" type="button" aria-label="Copy code"&gt;copy&lt;/button&gt;&lt;span class="sr-only" data-copy-status role="status" aria-live="polite"&gt;&lt;/span&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;serviceIds&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;express&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
 &lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;The request now fails validation before any application code runs. Nothing
about the client&amp;rsquo;s intent changed. The server chose a cleaner name and turned
that preference into a breaking protocol change.&lt;/p&gt;</description></item></channel></rss>