httpyac: HTTP Testing in VS Code and the Command Line

httpyac: HTTP Testing in VS Code and the Command Line

There are two kinds of API testing tools: the ones that look impressive in demos and the ones that actually fit into your daily workflow. httpyac is firmly in the second category. It extends the familiar .http file format with scripting, environments, authentication helpers, and a capable CLI — then wraps it all in a polished VS Code extension that makes running tests as easy as clicking a gutter button.

This post walks through what httpyac offers, how it compares to simpler .http tools, and how to use it effectively for both local development and CI pipelines.

What Is httpyac?

httpyac is an open-source HTTP client and test runner available as a VS Code extension and a standalone CLI (httpyac on npm). It reads .http and .rest files — the same format used by the VS Code REST Client extension — but adds a substantial layer of features on top: JavaScript scripting, multiple environment support, OAuth2/OpenID Connect helpers, GraphQL support, WebSocket testing, and gRPC.

The VS Code extension adds send buttons next to each request in the editor, a response viewer panel, an environment switcher in the status bar, and a history sidebar. The CLI (httpyac run) lets you execute the same files in CI without VS Code installed.

The combination means you write your tests once, run them interactively during development, and then execute the same files automatically in your pipeline.

Installation

For the VS Code extension, search for "httpyac" in the Extensions marketplace or install from the command palette:

ext install anweber.vscode-httpyac

For the CLI:

npm install -g httpyac
# or
yarn global add httpyac

The .http File Format (httpyac Style)

At its core, httpyac uses the standard .http format — HTTP method, URL, headers, blank line, body. But it layers on top of that significantly.

Basic request:

### Get user profile
GET https://api.example.com/users/me
Authorization: Bearer {{token}}
Accept: application/json

Request with assertions (httpyac's test scripting):

### Create product
POST https://api.example.com/products
Content-Type: application/json
Authorization: Bearer {{token}}

{
  "name": "Widget Pro",
  "price": 49.99,
  "sku": "WGT-PRO-001"
}

?? status == 201
?? body.id != null
?? body.name == "Widget Pro"
?? body.price == 49.99

The ?? lines are httpyac assertions. They run inline without switching to a separate section or writing JavaScript. For simple checks, this is much cleaner than embedding assertion logic in a script block.

Environments and Variables

One of httpyac's strongest features is its environment system. You define environments in a .env file, a http-client.env.json file, or directly in the VS Code settings:

.env.json example:

{
  "dev": {
    "baseUrl": "http://localhost:3000",
    "token": "dev-token-abc123",
    "adminToken": "dev-admin-token-xyz"
  },
  "staging": {
    "baseUrl": "https://api.staging.example.com",
    "token": "{{$env.STAGING_TOKEN}}",
    "adminToken": "{{$env.STAGING_ADMIN_TOKEN}}"
  },
  "production": {
    "baseUrl": "https://api.example.com",
    "token": "{{$env.PROD_TOKEN}}",
    "adminToken": "{{$env.PROD_ADMIN_TOKEN}}"
  }
}

In the VS Code extension, an environment switcher in the status bar lets you flip between dev, staging, and production without changing a single file. In CI, you pass the environment name via CLI flag:

httpyac run tests/**/*.http --env staging

Sensitive values reference actual environment variables using {{$env.VAR_NAME}} — they never appear in committed files.

JavaScript Scripting

For logic that cannot be expressed with simple assertions, httpyac supports JavaScript in @js script blocks before or after a request:

### Login and capture token
# @name login
POST https://{{baseUrl}}/auth/login
Content-Type: application/json

{
  "email": "test@example.com",
  "password": "{{$env.TEST_PASSWORD}}"
}

?? status == 200

{{
  const body = response.parsedBody;
  exports.authToken = body.access_token;
  exports.userId = body.user.id;
  console.log(`Logged in as user ${body.user.email}`);
}}

### Use the captured token
GET https://{{baseUrl}}/users/{{userId}}
Authorization: Bearer {{authToken}}

?? status == 200
?? body.email == "test@example.com"

The exports object makes values available to subsequent requests in the same file. This is how you chain dependent requests — login, capture the token, use it downstream.

Pre-request scripts work the same way, letting you compute values or set up state before the request fires:

### Request with computed signature
{{
  const crypto = require('crypto');
  const timestamp = Date.now().toString();
  const signature = crypto
    .createHmac('sha256', process.env.API_SECRET)
    .update(timestamp)
    .digest('hex');
  exports.timestamp = timestamp;
  exports.signature = signature;
}}

GET https://{{baseUrl}}/secure-endpoint
X-Timestamp: {{timestamp}}
X-Signature: {{signature}}

OAuth2 and Authentication Helpers

httpyac has built-in helpers for common authentication patterns, which saves a lot of boilerplate for APIs that require OAuth2:

### OAuth2 Client Credentials
# @auth oauth2
# @grantType client_credentials
# @clientId {{clientId}}
# @clientSecret {{$env.CLIENT_SECRET}}
# @tokenEndpoint https://auth.example.com/oauth/token
GET https://api.example.com/resource

httpyac fetches the token automatically, caches it, refreshes it when it expires, and injects the Authorization: Bearer header. No scripting required.

Supported flows include client credentials, authorization code (with local redirect listener), device code, and PKCE. For teams testing APIs that use OIDC or enterprise SSO, this is a significant time-saver.

GraphQL Support

httpyac handles GraphQL natively without any plugin:

### Search products
POST https://api.example.com/graphql
Content-Type: application/json
Authorization: Bearer {{token}}

query SearchProducts($query: String!, $limit: Int) {
  products(search: $query, limit: $limit) {
    id
    name
    price
    category {
      name
    }
  }
}

{
  "query": "widget",
  "limit": 10
}

?? status == 200
?? body.data.products != null
?? body.errors == null

GraphQL variables follow the request body naturally — no separate configuration needed.

Pros and Cons

Pros:

  • Excellent VS Code integration with inline send buttons and response viewer
  • Robust environment system with sensitive variable masking
  • Built-in OAuth2/OIDC helpers reduce auth boilerplate significantly
  • JavaScript scripting for complex logic without leaving the .http format
  • Supports HTTP, GraphQL, WebSocket, gRPC, and SSE in one tool
  • Active maintenance and strong documentation

Cons:

  • Heavier than minimal tools like Hurl — more surface area to learn
  • JavaScript scripting adds power but also adds complexity
  • CLI requires Node.js, unlike Hurl's single binary
  • Some advanced features (WebSocket, gRPC) are less mature than dedicated tools
  • Environment file format is slightly different from VS Code REST Client, causing friction when migrating

CI Integration

Running httpyac in CI is straightforward with the CLI:

# GitHub Actions
name: API Tests
on: [push, pull_request]

jobs:
  api-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install httpyac
        run: npm install -g httpyac

      - name: Run API tests
        env:
          STAGING_TOKEN: ${{ secrets.STAGING_TOKEN }}
          STAGING_ADMIN_TOKEN: ${{ secrets.STAGING_ADMIN_TOKEN }}
          TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}
        run: |
          httpyac run tests/**/*.http \
            --env staging \
            --output-failed \
            --junit tests/results.xml

      - name: Publish results
        uses: mikepenz/action-junit-report@v4
        if: always()
        with:
          report_paths: tests/results.xml

The --output-failed flag makes the CLI print details only for failed requests, keeping CI logs clean. The --junit flag writes results in a format most CI systems can parse for test reporting.

For parallelism, split your .http files across multiple CI jobs by directory or feature area. Since httpyac files are independent, there are no ordering constraints across jobs.

Organizing Tests for Scale

For larger projects, a practical structure looks like this:

tests/api/
├── .env.json              # environments (baseUrl, non-sensitive defaults)
├── auth/
│   ├── login.http
│   ├── refresh-token.http
│   └── logout.http
├── users/
│   ├── create-user.http
│   ├── get-user.http
│   └── update-user.http
├── products/
│   ├── search.http
│   └── product-crud.http
└── smoke/
    └── health-checks.http

In CI, run the smoke/ tests on every commit and the full suite on pull requests and deployments. The environment system makes running the same files against staging or production a single flag change.

httpyac vs. Hurl vs. REST Client

A quick comparison for teams choosing between tools:

Feature httpyac Hurl REST Client
VS Code integration Excellent None Good
CLI support Yes (Node.js) Yes (binary) No
Scripting JavaScript Limited None
OAuth2 helpers Built-in Manual Manual
GraphQL Native Basic Basic
CI readiness Good Excellent Poor
Learning curve Medium Low Low

For teams that split time between IDE and terminal, httpyac's unified experience is hard to beat. For pure CI/CD use cases with minimal setup requirements, Hurl's binary distribution wins on simplicity.

Working Alongside Broader Test Coverage

httpyac covers the HTTP layer well — request formation, response validation, authentication flows. What it does not cover is the full user journey: what happens in the browser, how the UI responds to API errors, whether the end-to-end flow from sign-up to first action actually works.

For that layer, tools like HelpMeTest work alongside your HTTP tests. HelpMeTest uses AI to generate Robot Framework and Playwright tests from natural language descriptions, running them continuously in the cloud. You describe what a user should be able to do, and the system generates, runs, and monitors the tests. The Pro plan is $100/month. It is a different layer of coverage — browser-level end-to-end — that complements your HTTP-level httpyac tests rather than replacing them.

Conclusion

httpyac hits a productive middle ground between minimal HTTP clients and full-featured test frameworks. The VS Code extension makes iterative API exploration fast and visual. The CLI makes the same files executable in CI without modification. The environment system handles the dev/staging/production problem cleanly. And when you need logic, JavaScript scripting is right there.

If you spend significant time working with HTTP APIs in VS Code and want tests that run the same way in your pipeline, httpyac is worth setting up. The investment in learning its conventions pays off quickly in reduced context-switching between tools.

Start with the VS Code extension, create a .env.json for your environments, write a few .http files for your most-used endpoints, and wire the CLI into your CI pipeline. The workflow will feel natural within a day.

Read more