<?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: Shayan Shojaei</title>
    <description>The latest articles on DEV Community by Shayan Shojaei (@shayanshojaei).</description>
    <link>https://dev.to/shayanshojaei</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F459749%2F85d42aa8-da08-4486-91fa-856b4ea7bbd5.jpg</url>
      <title>DEV Community: Shayan Shojaei</title>
      <link>https://dev.to/shayanshojaei</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shayanshojaei"/>
    <language>en</language>
    <item>
      <title>I got tired of Swagger UI, so I built a TUI API explorer in Go</title>
      <dc:creator>Shayan Shojaei</dc:creator>
      <pubDate>Fri, 15 May 2026 08:35:06 +0000</pubDate>
      <link>https://dev.to/shayanshojaei/i-got-tired-of-swagger-ui-so-i-built-a-tui-api-explorer-in-go-4e6</link>
      <guid>https://dev.to/shayanshojaei/i-got-tired-of-swagger-ui-so-i-built-a-tui-api-explorer-in-go-4e6</guid>
      <description>&lt;p&gt;There's a workflow I've repeated so many times it hurts to think about it. I'm working on a backend service, I've got a decent OpenAPI spec, and I just want to quickly poke at a few endpoints. So I open Swagger UI.&lt;/p&gt;

&lt;p&gt;And then I remember why I hate Swagger UI.&lt;/p&gt;

&lt;p&gt;The layout is a wall of accordions. There's no way to filter endpoints. You fill in your auth header, send a request, navigate somewhere else, come back — everything is gone. Every. Single. Time. It's like it was designed for demoing APIs to non-developers, not actually using them.&lt;/p&gt;

&lt;p&gt;The obvious alternatives are Postman and Insomnia. Both are great tools! But they're also full GUI applications that take several seconds to launch, sit in your taskbar, and quietly consume a few hundred megabytes of RAM. If you're context-switching between terminal and browser all day, opening a whole separate app just to fire off a quick API call starts to feel like a lot.&lt;/p&gt;

&lt;p&gt;One afternoon I got annoyed enough to actually do something about it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Introducing radar
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;radar&lt;/strong&gt; is a terminal API explorer for OpenAPI 3.x and Swagger 2.0 specs. You point it at a spec URL (or a local file), and it launches a Bubble Tea TUI where you can browse endpoints, fill in params and body fields, fire requests, and inspect responses — without ever leaving your terminal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2x2tenhgfahr8np6add1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2x2tenhgfahr8np6add1.gif" alt="radar in action" width="720" height="521"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why a TUI specifically?
&lt;/h2&gt;

&lt;p&gt;I spend most of my day in a terminal anyway. A TUI is just another tab — it starts instantly, uses almost no memory, and disappears the moment you close the tab. I don't need to alt-tab to a separate app window or wait for Electron to boot up. It's just &lt;em&gt;there&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Plus, if you already have a well-documented OpenAPI spec (and you should), you don't actually need anything beyond what the spec gives you. radar reads the spec and builds the whole interface from it automatically.&lt;/p&gt;




&lt;h2&gt;
  
  
  What it can do
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Browse and filter endpoints.&lt;/strong&gt; All endpoints are grouped by tag with collapsible sections. Hit &lt;code&gt;/&lt;/code&gt; to filter as you type — super handy when you're working with a spec that has 80+ endpoints and you just want the &lt;code&gt;POST /users&lt;/code&gt; one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Edit everything.&lt;/strong&gt; Path params, query params, headers, cookies, and request body are all editable fields. The body editor supports both raw JSON and structured field mode — toggle between them with &lt;code&gt;Ctrl+T&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Send and inspect.&lt;/strong&gt; &lt;code&gt;Ctrl+S&lt;/code&gt; fires the request. The response viewer shows status code, headers (toggle with &lt;code&gt;H&lt;/code&gt;), and pretty-printed JSON.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Persistent sessions, encrypted.&lt;/strong&gt; This was the big one for me. Every request you make is auto-saved to &lt;code&gt;~/.config/radar/sessions/&lt;/code&gt; as an &lt;a href="https://age-encryption.org/" rel="noopener noreferrer"&gt;age&lt;/a&gt;-encrypted file. Next time you open the same endpoint, everything is pre-filled exactly as you left it. Set &lt;code&gt;RADAR_PASSPHRASE&lt;/code&gt; in your environment and you won't even see a prompt.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cookie jar.&lt;/strong&gt; Non-HttpOnly cookies from &lt;code&gt;Set-Cookie&lt;/code&gt; responses are captured automatically and sent on subsequent requests to the same host. HttpOnly cookies prompt you to confirm. You can view and edit the jar from the endpoint list with &lt;code&gt;K&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Global Authorization header.&lt;/strong&gt; Set it once in the cookie manager and it gets injected into every request that doesn't already have one. No more re-typing your Bearer token.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Saved spec picker.&lt;/strong&gt; Run &lt;code&gt;radar&lt;/code&gt; with no arguments and you get a picker of your saved specs. Add one with &lt;code&gt;a&lt;/code&gt;, rename with &lt;code&gt;r&lt;/code&gt;, delete with &lt;code&gt;d&lt;/code&gt;. Useful when you're bouncing between a few different services throughout the day.&lt;/p&gt;




&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;One-liner install for macOS and Linux:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/shayan-shojaei/radar/main/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or if you prefer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;install &lt;/span&gt;github.com/shayan-shojaei/radar@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pre-built binaries are also on the &lt;a href="https://github.com/shayan-shojaei/radar/releases" rel="noopener noreferrer"&gt;releases page&lt;/a&gt; if you'd rather not build from source.&lt;/p&gt;

&lt;p&gt;Then just run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Point it at a spec URL&lt;/span&gt;
radar &lt;span class="nt"&gt;--url&lt;/span&gt; https://petstore3.swagger.io/api/v3/openapi.json

&lt;span class="c"&gt;# Or a local file&lt;/span&gt;
radar ./openapi.yaml

&lt;span class="c"&gt;# No args → opens your saved spec picker&lt;/span&gt;
radar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Key bindings cheat sheet
&lt;/h2&gt;

&lt;p&gt;A few of the ones you'll use most:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Key&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Filter endpoints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Enter&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Select endpoint / toggle tag&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;C&lt;/code&gt; / &lt;code&gt;E&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Collapse all / expand all tags&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Ctrl+S&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Send request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Ctrl+T&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Toggle body mode (raw ↔ structured)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Ctrl+L&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reload saved session&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;K&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Open cookie jar &amp;amp; auth header manager&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Esc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Go back&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Full keybinding reference is in the &lt;a href="https://github.com/shayan-shojaei/radar" rel="noopener noreferrer"&gt;README&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Under the hood (briefly)
&lt;/h2&gt;

&lt;p&gt;It's written in Go, using &lt;a href="https://github.com/charmbracelet/bubbletea" rel="noopener noreferrer"&gt;Bubble Tea&lt;/a&gt; for the TUI layer and &lt;a href="https://age-encryption.org/" rel="noopener noreferrer"&gt;filippo.io/age&lt;/a&gt; for session encryption. The architecture is pretty clean — one top-level model owns the state and delegates to sub-models for each view (endpoint list, request editor, response viewer). All I/O happens inside &lt;code&gt;tea.Cmd&lt;/code&gt; closures so nothing ever blocks the update loop.&lt;/p&gt;

&lt;p&gt;I wanted the codebase to stay readable and hackable, so if you're curious about how a Bubble Tea app gets structured at this scale, it might be a decent reference.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try it out, break it, tell me about it
&lt;/h2&gt;

&lt;p&gt;radar is at &lt;a href="https://github.com/shayan-shojaei/radar" rel="noopener noreferrer"&gt;github.com/shayan-shojaei/radar&lt;/a&gt; and it's fully open source.&lt;/p&gt;

&lt;p&gt;If you use it and find a bug, please &lt;a href="https://github.com/shayan-shojaei/radar/issues" rel="noopener noreferrer"&gt;open an issue&lt;/a&gt;. Specific reproduction steps + the spec URL you were using goes a long way. If there's a feature you'd want — better response formatting, auth flow support, something else entirely — open an issue for that too. I'd genuinely like to know what people want out of a tool like this.&lt;/p&gt;

&lt;p&gt;And if you want to contribute, the contributing section of the README has everything you need to get a local build running. The codebase is pretty approachable — &lt;code&gt;make run url=&amp;lt;spec&amp;gt;&lt;/code&gt; gets you going in under a minute.&lt;/p&gt;

&lt;p&gt;If you find it useful, a ⭐ on GitHub means a lot and helps other developers find it.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with Go, Bubble Tea, and a healthy amount of frustration with Swagger UI.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>showdev</category>
      <category>go</category>
      <category>backend</category>
    </item>
  </channel>
</rss>
