<?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>Forem: ak</title>
    <description>The latest articles on Forem by ak (@akdevblog).</description>
    <link>https://forem.com/akdevblog</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%2F86387%2F9b1957ec-34c2-4974-ba93-fd98594a8973.png</url>
      <title>Forem: ak</title>
      <link>https://forem.com/akdevblog</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/akdevblog"/>
    <language>en</language>
    <item>
      <title>Introducing XRest: A Service-First REST Client for Microservices Teams</title>
      <dc:creator>ak</dc:creator>
      <pubDate>Tue, 03 Feb 2026 22:55:08 +0000</pubDate>
      <link>https://forem.com/akdevblog/introducing-xrest-a-service-first-rest-client-for-microservices-teams-ffm</link>
      <guid>https://forem.com/akdevblog/introducing-xrest-a-service-first-rest-client-for-microservices-teams-ffm</guid>
      <description>&lt;p&gt;&lt;em&gt;This was originally published in my blog &lt;a href="https://akdev.blog/introducing-xrest-a-service-first-rest-client-for-microservices-teams" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TLDR&lt;/strong&gt;; modern REST clients follow a collections-first approach that breaks down with growing complexity of microservices and devops. I am introducing a service-first design philosophy, where each service is a self-contained unit with its own endpoints, versions, history and evolution. All of this with a secure by design approach, guardrails for unsafe requests, git-native, local-only, native application built with Tauri framework. XRest is a highly experimental prototype that I built and am actively using for my personal/pet projects. This post explains the philosophy, walks through the functionality with screenshots, and invites feedback from developers facing similar microservices workflow pain.&lt;/p&gt;

&lt;h2&gt;
  
  
  My story
&lt;/h2&gt;

&lt;p&gt;I started developing APIs and webpages when XML was the preferred option of communications between two systems. I was wide eyed when AJAX, JSON and HTTP API revolution took over the world. Those days, I used firefox with a few plugins to inspect API endpoints, and then progressed into postman, insomnia, hoppscotch, bruno over the last two decades. They are all great, developed by brilliant engineers and teams with a vision to support the developer experience.&lt;/p&gt;

&lt;p&gt;There were also revolutionary Microservices and DevOps movements that changed the way I worked. 10 years ago, I used to develop and maintain just one application, with one context path and one auth type. Today, I build and maintain more than a handful of applications. Each of those have different auth mechanisms, request payloads, versions, environments, the list goes on. Today, none of the REST clients are working for me anymore.&lt;/p&gt;

&lt;p&gt;What most, if not all, REST clients are optimized for is quick onboarding. Want to try an API? Click add, paste the URL, select the method, add request details, save—done. Another endpoint from the same service? Click, paste, select, save. Simple enough.&lt;/p&gt;

&lt;p&gt;Slowly, this model introduces entropy. The URL needs to point to QA—make a copy, change the URL, save. Dev has a different endpoint version coming—another copy, modify everything, save again. Too many duplicates to manage manually, so you build an environment. Now you need to figure out which variables go where and sync them across dozens of requests. Auth tokens? That's a separate request to a different endpoint, which means another environment, more variables to manage, more naming conventions to remember. Folder names that made sense for three requests become meaningless with thirty. Sharing this setup with teammates means exporting collections, syncing environment files, explaining which secrets go where.&lt;/p&gt;

&lt;p&gt;And URLs are not the only ones that change, payloads, headers, params all change. They all change depending on the environments.&lt;/p&gt;

&lt;p&gt;Then there are a lot of devs and teams who have access to production as well, me included. There are times I have to query production, and it is not safe by default, which makes me nervous about what I am doing. I have accidentally hit production URLs, only realizing that auth or environment was incorrect. I cannot share production details to everyone either, and that is another friction point that I always have to remember while exporting collections.&lt;/p&gt;

&lt;p&gt;What started as "quick onboarding" became a maintenance nightmare.&lt;/p&gt;

&lt;p&gt;What if there was a REST client, that had an opinionated view of how services need to be managed. Not requests or collections, the service as a whole, from its inception and its evolution, with guard rails. An opinionated approach and design, where everything required for that service is contained and managed together—"right first time".&lt;/p&gt;

&lt;h2&gt;
  
  
  Service-first design
&lt;/h2&gt;

&lt;p&gt;For many years, I thought the HTTP clients was a solved problem space. Existing tools handled the problem they set out to solve, which is to help teams quickly onboard and test APIs. But they weren't designed for long-term management across dozens of services. Same problem space, different time perspectives.&lt;/p&gt;

&lt;p&gt;Service-first design treats each service as the primary unit of organization, with endpoints, environments, authentication, and configurations scoped to that service boundary rather than globally managed collections.&lt;/p&gt;

&lt;p&gt;In order to solve this problem I applied bounded context thinking to this dev-centric tool. Just as microservices organize code by business domains rather than technical layers, service-first organizes interactions by service boundaries rather than HTTP method collections. Each service becomes a bounded context with its own environments, auth, safety rules, and evolutionary history — eliminating the cross-service pollution that happens when everything shares global state.&lt;/p&gt;

&lt;p&gt;And to test this out, I built an HTTP client. I am calling this XRest right now, and it is highly experimental. It works for me, and I have stopped using other clients already.&lt;/p&gt;

&lt;h2&gt;
  
  
  XRest - Service First, Git Native API Client
&lt;/h2&gt;

&lt;p&gt;XRest is built with modern, lightweight technologies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Rust backend via Tauri for native performance and security&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Vue 3 + TypeScript for reactive UI&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Shadcn-vue for accessible, composable components&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SQLite for local history storage&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;YAML for human-readable configuration&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Core Features
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Service Management&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Create and manage services as self-contained units&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Service-level authentication with pre-flight token acquisition&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Environment definitions scoped to each service (DEV, STAGING, PROD)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Unsafe environment guardrails with mandatory confirmation dialogs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Import from a swagger / openapi doc&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Endpoint Operations&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Full HTTP method support: GET, POST, PUT, DELETE, PATCH&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Content types: &lt;code&gt;application/json&lt;/code&gt;, &lt;code&gt;text/plain&lt;/code&gt;, &lt;code&gt;application/x-www-form-urlencoded&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Request configuration: params, headers, body&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Automatic auth inheritance from service configuration&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Secret and environment variable support in editable fields&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Import from curl&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Version Control &amp;amp; History&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Git-native architecture with automatic commits for all configuration changes&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Service definitions stored as YAML files in your local directory&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Schema specification in development to support pluggable storage backends&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Basic git status in the service settings view&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Per-endpoint revision history showing request evolution and backed up into git&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Global execution history stored in local SQLite database (not git backed)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Security&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;System keychain integration (macOS) for secret storage&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Environment-based safety controls for production access&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Others&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Native desktop application (Tauri + Rust + Vue.js)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dark mode support&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are a few initial screenshots and features.&lt;/p&gt;

&lt;h2&gt;
  
  
  Main page
&lt;/h2&gt;

&lt;p&gt;The service sidebar on the left lists all your services with their active environment. The main area is empty until you select an endpoint or create one. Two quick-action buttons are at the bottom: New Service and New Endpoint.&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%2Fyg54p5s8sui1p08d4q3l.png" 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%2Fyg54p5s8sui1p08d4q3l.png" alt="XRest main page" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Add a new service
&lt;/h2&gt;

&lt;p&gt;If you click the plus icon on the sidebar, it will show more options - Add New Service, Add New Endpoint, Import from Directory, Import from Swagger.&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%2Fbnfq6ozbxri7htwo3ivj.png" 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%2Fbnfq6ozbxri7htwo3ivj.png" alt="XRest add new service" width="578" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Add a new service&lt;/strong&gt;: A three-field form: Service Name, Save Directory (local path where YAML files live), and a toggle for Service Authentication if the service needs an auth token.&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%2Fzr4cluvq4c58aw9uau7i.png" 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%2Fzr4cluvq4c58aw9uau7i.png" alt="XRest add a service" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Environment variables setup&lt;/strong&gt;: The second step of service creation. A table where you define variables (like BASE_URL) with columns for each environment (Dev, Stage, Prod). Each environment gets its own value for the same variable.&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%2F6gmqajsdpxrbh9lu4rsf.png" 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%2F6gmqajsdpxrbh9lu4rsf.png" alt="XRest add environment vars" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Add a new endpoint
&lt;/h2&gt;

&lt;p&gt;This is a small dialog scoped to a service. You pick the service, give the endpoint a name, select the HTTP method, and define the path. The endpoint inherits the service's environments and auth automatically.&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%2Fbagviacnl2jv58y5vqe3.png" 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%2Fbagviacnl2jv58y5vqe3.png" alt="XRest add new endpoint" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Request panel
&lt;/h2&gt;

&lt;p&gt;The main workspace. Left sidebar shows the endpoint tree under the service. The top bar shows the resolved BASE_URL for the active environment. Tabs for Params, Auth, Headers, Body, History, and Preflight. The Send button is on the right.&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%2Fzag3mesdbhwuojqzkars.png" 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%2Fzag3mesdbhwuojqzkars.png" alt="XRest request panel" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicking the environment badge on the service opens a dropdown (DEV, STAGE, PROD). Switching environment changes the resolved BASE_URL across all endpoints in that service instantly.&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%2Fx8b2qhxs3jei7bkkqs9g.png" 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%2Fx8b2qhxs3jei7bkkqs9g.png" alt="XRest env dropdown" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When the active environment is PROD, the service badge turns red and the Send button turns red.&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%2Feqcm99we5l48gkykysrf.png" 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%2Feqcm99we5l48gkykysrf.png" alt="XRest prod cue" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicking Send on a PROD request triggers a confirmation modal. It states which environment is marked unsafe, asks for explicit confirmation, and shows a countdown (10 seconds) after which it auto-cancels. You have to actively click "I Accept the Risk" to proceed.&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%2Fr7s3fss3ovbozu5yce24.png" 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%2Fr7s3fss3ovbozu5yce24.png" alt="XRest safety dialog" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Service settings
&lt;/h2&gt;

&lt;p&gt;Service level settings which contains General Information (name, base directory), Service Authentication config (auth type selector, pre-flight toggle), Git Status, and the Shared Environments &amp;amp; Variables table. Each environment column has an UNSAFE toggle.&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%2F54dwv43kybuf17gv2twj.png" 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%2F54dwv43kybuf17gv2twj.png" alt="XRest service level settings" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Secrets and environment variables
&lt;/h3&gt;

&lt;p&gt;XRest keeps sensitive values out of plain text. Secrets are created once and stored securely in your macOS Keychain. From there, you have two ways to use them:&lt;/p&gt;

&lt;p&gt;Directly in any text field using &lt;code&gt;{{secret.SECRET_KEY}}&lt;/code&gt; syntax, or mapped to an environment variable and referenced using &lt;code&gt;{{ENV_NAME}}&lt;/code&gt;. The second approach exists because not every environment needs secrets. A local DEV setup might use hardcoded values, while STAGE and PROD pull from the Keychain. By mapping secrets through environment variables, each environment can define its own resolution strategy or skip secrets entirely.&lt;/p&gt;

&lt;p&gt;Environment variables themselves follow the same &lt;code&gt;{{ENV_NAME}}&lt;/code&gt; interpolation and work across params, headers, URLs, and body fields.&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%2F1owrmtxvzx44ugs0j927.png" 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%2F1owrmtxvzx44ugs0j927.png" alt="XRest secret interoplation" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the variables table, clicking a cell reveals a "Link Secret" option. This lets you map a Keychain secret to a specific environment variable. DEV might have a hardcoded value while STAGE and PROD pull from secrets.&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%2Fua7876bpwmksb1c47c8x.png" 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%2Fua7876bpwmksb1c47c8x.png" alt="XRest secret in env" width="800" height="478"&gt;&lt;/a&gt;&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%2F9ul221nd2eyy51osy1bf.png" 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%2F9ul221nd2eyy51osy1bf.png" alt="XRest secret in env" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When typing in any field (URL, params, body, headers), typing &lt;code&gt;{{secret.&lt;/code&gt; triggers an autocomplete dropdown listing all available secrets from the Keychain. Values are masked with dots.&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%2Fqs2vq67ke97bk943jqp2.png" 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%2Fqs2vq67ke97bk943jqp2.png" alt="XRest secret interpolation" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Service Level Auth ( pre-flight auth )
&lt;/h2&gt;

&lt;p&gt;The settings page lets you configure a request that runs &lt;em&gt;before&lt;/em&gt; the actual request. The primary use case is that the service needs a token before any endpoint call. You define the token endpoint, its payload, and map the response (e.g., the access_token field) to a variable that the main request uses automatically. This runs transparently on every Send, so you never manually fetch and paste tokens. There is also an option to cache the token based on the auth response model.&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%2F5lqkjjfput3qad19z33b.png" 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%2F5lqkjjfput3qad19z33b.png" alt="XRest preflight auth" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Endpoint history
&lt;/h2&gt;

&lt;p&gt;The History tab shows a numbered version list of the endpoint. Each version is timestamped. Expanding a version shows a diff of what changed (URL, params, body). A "Restore This Version" button lets you roll back to any previous state. Each version syncs to the YAML file and git automatically.&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%2Ftkgof49q2if68iktm3pt.png" 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%2Ftkgof49q2if68iktm3pt.png" alt="XRest endpoint history" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Other Features
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Import from Swagger / OpenAPI&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Import from CURL&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Export to curl, axios, java and kotlin&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Global history with filters&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What Next?
&lt;/h2&gt;

&lt;p&gt;I am exploring whether this design resonates with the developer community. You are welcome to try out the pre-alpha versions for Mac, click &lt;a href="https://github.com/aravindkunnath/xrest/releases/tag/v0.0.1" rel="noopener noreferrer"&gt;here&lt;/a&gt; to download it. You may be greeted with a Mac security warning, and that can be bypassed in Settings &amp;gt; Privacy and Security.&lt;/p&gt;

&lt;p&gt;I'm looking for&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Feedback on whether service-first design resonates&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Developers who've felt similar pain with existing tools&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Contributors who want to help build this&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you've managed multiple microservices and felt the same friction, I'd love to hear whether service-first design makes sense to you. Drop your thoughts in the comments or open a &lt;a href="https://github.com/aravindkunnath/xrest/discussions" rel="noopener noreferrer"&gt;discussion&lt;/a&gt; on GitHub or join me on &lt;a href="https://discord.gg/dxNrc99z2t" rel="noopener noreferrer"&gt;Discord&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As for features and roadmap, I have a lot of exciting ones to work on that helps me to manage services more efficiently. Some of them are&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Integration with password managers (1Password, Bitwarden)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Custom env support and management&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Secret manager support (AWS, GCP, Vault)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Windows and Linux testing and releases&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Manual git commit workflow&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Migrating from postman, insomnia and others&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;And a stable release&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;XRest is MIT licensed and available at &lt;a href="https://github.com/aravindkunnath/xrest" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

</description>
      <category>servicefirst</category>
      <category>apiclient</category>
      <category>gitnative</category>
      <category>devtools</category>
    </item>
    <item>
      <title>Hexagonal Architecture</title>
      <dc:creator>ak</dc:creator>
      <pubDate>Sun, 20 Apr 2025 00:48:41 +0000</pubDate>
      <link>https://forem.com/akdevblog/hexagonal-architecture-1a0d</link>
      <guid>https://forem.com/akdevblog/hexagonal-architecture-1a0d</guid>
      <description>&lt;p&gt;&lt;em&gt;Exploring hexagonal architecture and why context matters more than syntax and structure&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This was originally posted in my blog - &lt;a href="https://akdev.blog/hexagonal-architecture-1" rel="noopener noreferrer"&gt;https://akdev.blog/hexagonal-architecture-1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You're reading part one of a series on hexagonal architecture. Over the next few articles, I will cover everything that I have encountered so far from the basics to advanced strategies, failures and wtf moments included.&lt;/p&gt;

&lt;p&gt;Originally named the "Ports and Adapters Architecture," and widely referred to as Hexagonal Architecture first started shaping itself out of ideas that were working behind the scenes as far back as the 1990s, but not until the early 2000s really took shape as a formal framework. That’s what the LLMs tell me anyways, Dr. Alistair Cockburn’s site is down and the first entry in archive.org is in 2009 🥺 . The aim of this architectural style was to further insulate the inside of an application from the outside world - be it databases, user interfaces, or other external systems.&lt;/p&gt;

&lt;p&gt;I must admit, I came across this pattern fairly recently. For a number of early years in my career as software developer, I was highly committed to attempting to master as many programming languages as possible. Language upon language, syntax upon syntax, semi-colons and no semi-colons; in pursuit of the mirage that the more languages I could master, the greater developer I would be. But in time, I stalled at a humbling moment: I was just repeating the same structural patterns, the same mental models, over and over in every new language I acquired. In effect, I wasn't really learning anything. I was merely reimplementing the same application in different dialects. It felt like progress, but it wasn't. What a wake-up call.&lt;/p&gt;

&lt;p&gt;To all coders who read this: mastery is not just knowing everything about the language or many things in many languages; it's learning why we do things the way we do. Learn the context under which architectural and design solutions are best. Learn the problems they were intended to solve. Don’t try to kill a mosquito with a bazooka!&lt;/p&gt;

&lt;p&gt;Which brings me back to hexagonal architecture. Like all architecture styles, its value is not in simply doing it, but knowing when and why you should. The old adage applies once more: "It depends." Its relevance is largely dependent on the kind of problem you are attempting to solve, the complexity of your domain, and the kind of boundaries your application needs.&lt;/p&gt;

&lt;p&gt;Since I’ve already tried applying hexagonal architecture in a variety of projects, across different domains and in multiple programming languages, you could say I’ve willingly signed myself up for a fair bit of architectural suffering. And that’s exactly what I want to write about. The good, the bad, and the “what-was-I-thinking” moments that came with it.&lt;/p&gt;

&lt;p&gt;Some basics&lt;/p&gt;

&lt;p&gt;The closest analogy that I commonly see in other articles are the use of power outlets and plugs. As long as you have the same prongs, you are guaranteed electricity to charge your phone, if the grid is live. You travel to another country, buy an international adapter. All the concepts remain the same in this architecture - as long as you invoke the same inbound port, be it a REST call or a SOAP call or an undocumented untested protocol defined by a random IBM mainframe, the logic remains untouched and consistent and produces the same outcome. This predictability is a big deal!&lt;/p&gt;

&lt;p&gt;The term hexagon has no real meaning in the architecture. The author simply found boxes and circles too dull for diagrams and opted for a six-sided shape instead. There’s no deeper symbolic meaning , that I know of, behind the hexagon itself. I have tried to draw this out without a hexagon and it looks great! You are free to try it out, pen and paper anyone?&lt;/p&gt;

&lt;p&gt;Here is a representation of hexagonal architecture without any hexagons in it. The arrows represent information flow or call stack.&lt;/p&gt;

&lt;p&gt;What does matter, though, is the goal of this architecture: to protect the core of your system the application logic, the business rules from the noisy, ever-changing world outside. This means isolating the core from UI frameworks, REST controllers, messaging systems, databases, and all other external concerns.&lt;/p&gt;

&lt;p&gt;In hexagonal architecture, the core interacts with the outside world through clearly defined boundaries: a single entry point and a single exit point, known as the inbound port and outbound port, respectively.&lt;/p&gt;

&lt;p&gt;If something outside the application wants to invoke or use a capability within the core, it goes through the inbound port.&lt;/p&gt;

&lt;p&gt;If the application needs to communicate with or depend on something external like a database or message queue it does so via the outbound port.&lt;/p&gt;

&lt;p&gt;Adapters are the components that live on the edge. They’re responsible for translating between the messy, real-world technologies and the clean, intention-driven interfaces defined by the core. Think of them as interpreters: HTTP controllers, File / Disk operations, database connectors, messaging clients - they all act as adapters.&lt;/p&gt;

&lt;p&gt;The big WHY?&lt;/p&gt;

&lt;p&gt;Separation of concerns is an important aspect in software architecture. Mortal humans likes order, boundaries and control, however far fetched that might seem in the world we are in. Hexagonal architecture provides just that, separation of concerns through clear boundaries, an order in the flow of information and layered control of behaviours.&lt;/p&gt;

&lt;p&gt;Improved Unit Tests: By isolating the core logic, you can test it independently of the complexities and potential instability of external dependencies like databases or UI frameworks. Unit tests become more focused and reliable.&lt;/p&gt;

&lt;p&gt;Improved Integration Testing: Having clear boundaries between different layers helps to apply narrow integration tests, improves contracts between layers, promotes stubs. This makes it easier to test the interactions between different parts of the system without relying on expensive e2e tests.&lt;/p&gt;

&lt;p&gt;Increased Maintainability: Changes in the external world (e.g., upgrading a database, switching UI frameworks) are less likely to impact the core application logic, as long as the adapters are updated accordingly. This reduces the risk of introducing bugs and makes maintenance easier.&lt;/p&gt;

&lt;p&gt;Enhanced Flexibility: The application becomes more adaptable to change. You can swap out external dependencies without rewriting the core logic. For example, you could switch from one database to another by simply implementing a new adapter.&lt;/p&gt;

&lt;p&gt;Better Team Collaboration: Clear boundaries make it easier for different teams to work on different parts of the application with less risk of interference, mostly at the same time. As long as the boundaries and contracts remain the same, there should not be major conflicts.&lt;/p&gt;

&lt;p&gt;In the next article, I will cover a Spring Boot application and its project structure that would help us enable this architecture.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>hexarch</category>
    </item>
  </channel>
</rss>
