Back to Articles

Posting: The Terminal-Native API Client That Treats Requests Like Code

[ View on GitHub ]

Posting: The Terminal-Native API Client That Treats Requests Like Code

Hook

While Postman collections sit in binary formats behind cloud sync, Posting stores your API requests as plain YAML files you can grep, diff, and merge like any other source code.

Context

The API client landscape has been dominated by GUI tools like Postman and Insomnia for years, and for good reason—they're powerful, feature-rich, and accessible. But they come with friction points that terminal-dwelling developers feel acutely: context switching between terminal and browser, proprietary file formats that don't play well with git, collaboration features locked behind cloud accounts, and interfaces optimized for clicking rather than typing.

Posting emerged from a simple premise: API testing belongs in the same environment where developers write code, debug services, and tail logs. Built on Textual, a modern Python framework for terminal UIs, it brings the interactive convenience of GUI clients into the terminal. More importantly, it treats API requests as first-class code artifacts—plain text files that live in your repository, version control naturally, and can be manipulated with standard Unix tools. For developers who already spend their day in tmux or SSH sessions, this isn't just about preference; it's about eliminating the cognitive overhead of tool-switching.

Technical Insight

Posting's architecture reveals thoughtful decisions about how local-first tools should work. At its core, it stores each HTTP request as a YAML file with a straightforward structure. A typical request file looks like this:

name: Create User
method: POST
url: ${BASE_URL}/api/users
headers:
  Content-Type: application/json
  Authorization: Bearer ${AUTH_TOKEN}
body: |
  {
    "email": "{{$randomEmail}}",
    "name": "Test User"
  }
scripts:
  pre_request: |
    import os
    posting.env["timestamp"] = str(int(time.time()))
  post_response: |
    if response.status_code == 201:
      user_id = response.json()["id"]
      posting.env["CREATED_USER_ID"] = user_id

This isn't just configuration—it's executable documentation. The scripts section runs arbitrary Python code with access to the request and response objects, enabling workflows that would require Postman's paid team features: extracting auth tokens, chaining requests, transforming payloads, or writing assertions. Because it's Python, you can import libraries, make database queries, or integrate with internal tools.

The environment variable system demonstrates thoughtful layering. Posting supports multiple environment files (dev.yaml, staging.yaml, production.yaml) with variable interpolation using ${VAR_NAME} syntax. Variables cascade: collection-level settings override global config, and request-level values override collection settings. This mirrors how developers already think about configuration in application code.

The TUI itself leverages Textual's reactive programming model. Unlike traditional ncurses applications that manually manage screen updates, Textual components react to state changes automatically. When you switch environments, the UI re-renders affected request parameters without explicit update calls. This keeps the codebase maintainable while delivering a responsive interface that handles terminal resizing, focus management, and keyboard navigation without the usual TUI jank.

Posting's jump mode deserves special mention—press / and type a few characters to fuzzy-find any request in your collection. It's the terminal equivalent of Cmd+K command palettes that every modern app now includes, except it works over SSH on a remote server where you're debugging production issues. The implementation uses tree-sitter for parsing HTTP syntax, which means you get accurate syntax highlighting for JSON, XML, and other body formats without hand-rolled parsers.

The cURL bidirectional conversion is surprisingly powerful. Paste a cURL command copied from browser DevTools, and Posting parses it into a structured request you can modify and save. Going the other way, any request exports to cURL syntax for documentation or sharing with teammates who haven't adopted Posting yet. This interoperability reduces the migration barrier—you're not locked into a proprietary ecosystem.

One architectural choice stands out: Posting deliberately avoids building a request history database. Instead, it treats your filesystem as the database. Want to see request history? Check your git log. Want to search old requests? Use grep. Need to backup collections? Copy the directory. This Unix philosophy approach means Posting doesn't need to solve data synchronization, backup strategies, or export formats—your existing tools already handle it.

Gotcha

The YAML-first approach has real limitations when you need features that require more structure. While Postman can visualize response times in graphs, run collection-level test suites with detailed reporting, or manage complex authentication flows with OAuth2 helpers, Posting treats these as outside its scope. If you're testing APIs that return images, PDFs, or binary data, you'll be looking at hex dumps or piping to external viewers—there's no inline preview.

The Python scripting is both a strength and a constraint. Teams already invested in Postman's JavaScript pre-request scripts face a rewrite cost when migrating. More subtly, running Python code in request scripts means you can accidentally create side effects (file system changes, network calls) that make requests non-reproducible. The power is there, but so is the rope to hang yourself. You'll need discipline to keep scripts focused on request preparation rather than turning them into general-purpose automation that should live in proper scripts.

Collaboration is fundamentally file-based. While this enables git-based workflows, it lacks real-time features that teams using Postman's cloud workspace expect. There's no built-in way to see who's editing what, comment on requests, or maintain team-wide mock servers. If your team needs these features, you're building them separately or living without them.

Verdict

Use Posting if you're a backend developer, DevOps engineer, or systems programmer who lives in the terminal and wants API testing to fit your existing workflow. It shines when you need version-controlled collections, work over SSH frequently, prefer keyboard-driven interfaces, or want to automate complex request chains with Python. It's exceptional for teams already doing GitOps who want their API tests to follow the same code review process as everything else. Skip it if your team relies on Postman's collaboration features, you need graphical response visualization for debugging complex APIs, your pre-request scripts are heavily invested in JavaScript, or you're testing APIs that return rich media. It's a powerful tool for developers who think of API requests as code artifacts, not a universal replacement for GUI clients that serve different workflows.

// ADD TO YOUR README
[![Featured on Starlog](https://starlog.is/api/badge/developer-tools/darrenburns-posting.svg)](https://starlog.is/api/badge-click/developer-tools/darrenburns-posting)