<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Automation on Restish</title><link>https://rest.sh/tags/automation/</link><description>Recent content in Automation on Restish</description><generator>Hugo</generator><language>en-US</language><lastBuildDate>Sun, 28 Jun 2026 18:55:48 -0700</lastBuildDate><atom:link href="https://rest.sh/tags/automation/index.xml" rel="self" type="application/rss+xml"/><item><title>Scripting REST APIs Without Fragile curl Loops</title><link>https://rest.sh/blog/scripting-rest-apis-without-fragile-curl-loops/</link><pubDate>Tue, 30 Jun 2026 00:00:00 +0000</pubDate><guid>https://rest.sh/blog/scripting-rest-apis-without-fragile-curl-loops/</guid><description>&lt;p&gt;Somewhere in your infrastructure there is a shell script with a loop like
this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;https://api.example.com/items?page=1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -n &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;curl -s &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$resp&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; jq -r &lt;span class="s1"&gt;&amp;#39;.items[].id&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$resp&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; jq -r &lt;span class="s1"&gt;&amp;#39;.links.next // empty&amp;#39;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It works, mostly. It has also quietly accumulated a list of failure modes that
nobody will notice until a bad day:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;500&lt;/code&gt; response exits with status &lt;code&gt;0&lt;/code&gt;, so the error page flows into &lt;code&gt;jq&lt;/code&gt;,
which prints nothing, and the script &amp;ldquo;succeeds&amp;rdquo; with empty output.&lt;/li&gt;
&lt;li&gt;There is no retry, so one transient network blip fails the whole job — or
worse, half of it.&lt;/li&gt;
&lt;li&gt;There is no timeout, so a hung connection hangs the cron job behind it.&lt;/li&gt;
&lt;li&gt;There is no page bound, so a pagination bug upstream turns the loop into an
accidental load test.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;next&lt;/code&gt; ever points somewhere unexpected — another host, an attacker-
influenced URL in a response body — the loop follows it without a thought.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;None of these are exotic. They are the standard tax on hand-rolling HTTP
plumbing in shell, paid one incident at a time. This post is about paying it
once, in the tool, instead.&lt;/p&gt;</description></item></channel></rss>