Skip to content
| Marketplace
Sign in
Visual Studio Code>Programming Languages>Assay - HTTP client with testsNew to Visual Studio Code? Get it now.
Assay - HTTP client with tests

Assay - HTTP client with tests

efega

|
8 installs
| (0) | Free
No account, no cloud, nothing paywalled later. Run .http files, assert on the response, and chain requests without leaving your editor.
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

Assay

An HTTP client for VS Code that tests your API.

Plain .http files. No account, no cloud, nothing paywalled later.

Install Version npm CI VS Code License


Assay running a chained request with assertions


One line is the whole setup

GET https://api.example.com/health

Press Send above the request, or Ctrl+Alt+R.

Then make it a test

@base = https://api.example.com

### Log in
# @name login
POST {{base}}/auth
Content-Type: application/json

{ "user": "ana", "password": "{{password}}" }

### Use the token (login runs on its own if it hasn't yet)
GET {{base}}/me
Authorization: Bearer {{login.response.body.$.token}}

# @assert status 200
# @assert time < 500
# @assert body.$.roles.length > 0

Assay tells you what a request will do before you send it: how many assertions will run, and which requests it will fire first.


Why this one

Assertions built in Status, timing, headers and JSON paths. Declarative: no scripting sandbox, and the diff reads clean in code review.
Request chaining Use one response in the next request. Dependencies run on their own, with cycle detection and a depth limit.
Failures where you are looking A failed assertion is underlined on its own line with the value that came back, and lands in the Problems panel. You never leave your request file.
Environments Standard http-client.env.json. Secrets live in a separate file that stays out of git, and Assay tells you if it isn't ignored yet.
Nothing is paywalled retroactively Your saved requests are yours. Export is always free. That is a promise, not a tier.

The same file runs in CI

The extension answers "what does this return?". The CLI answers "does it still return that?", which is the question a team actually pays attention to.

npx assay-http run api.http
api.http
  ok   POST https://api.example.com/auth 200 · 107ms 3/3 assertions
  ok   GET  https://api.example.com/me   200 · 8ms   3/3 assertions
  FAIL GET  https://api.example.com/plan 200 · 3ms   1/2 assertions
        FAIL body.$.tier enterprise -> free

3 requests, 1 failed

Exit code 1 when something fails, so CI stops. Point it at a directory and it runs every .http it finds, in order, sharing the chain and the session, so a file becomes a suite without changing anything in it.

- uses: efega/assay@v0.5.0
  with:
    files: tests/
    env: staging
    reporter: junit
    output: report.xml

--reporter junit writes one <testcase> per assertion, not per request, so the CI report names the assertion that broke rather than only the request.

Credentials are masked in the output by default. A CI log is not a private place: it is read, archived, and on a public repository anyone can see it. Values from http-client.private.env.json are masked everywhere they appear, including inside a response body that echoes them back. --show-secrets turns that off, deliberately loudly.

No config file, no dependencies, 17 kB. Full guide: Running .http files in CI.

How it compares

Honest version, because you will find these anyway.

Assay REST Client httpyac Thunder Client
Assertions live in the .http file yes no yes, richer no, in a panel
Other .http tools still read the file yes n/a no n/a
Chained requests run on their own yes no yes yes
CLI for CI yes no yes paid plan
JUnit report, one case per assertion yes no per request yes
XPath, JS expressions, hashes no no yes scripting is paid
Free tier limits none none none 3 collections, 15 requests each, 0 environments
Last release this week 4 years ago 1.4 years ago active

httpyac is the closest thing to this, it is good, and its assertions do strictly more than these: XPath, JavaScript expressions, hash checks, fifteen operators against ten. If you need any of that, or you need to run your tests in CI today, use httpyac. That is a real recommendation, not a hedge.

One thing here works differently, and it is the reason this exists:

# @assert status 200      <- a comment. Every .http tool ignores it.
?? status == 200          <- httpyac syntax. Only httpyac understands it.

# is a comment prefix in the .http format, honoured by REST Client, JetBrains, Visual Studio 2022 and Neovim alike. So assertions written for Assay are invisible to every other client: you can add a test layer to a .http file your team already shares, and nobody who does not use Assay notices anything changed. Nothing to migrate, nothing to agree on first.

That is the whole trade. Fewer features, in exchange for not asking anyone else to move.

Release dates and tier limits checked 2026-08-31. If something here is out of date or wrong, open an issue and it gets fixed.

Reads like code, not like a text file

.http files get proper syntax highlighting: methods, URLs, headers, variables, {{substitutions}}, section titles and assertions.

It uses standard TextMate scopes rather than fixed colours, so it follows whatever theme you already use and reads correctly in light and dark.


The small decisions

None of these are features. They are the difference between a tool you tolerate and one you forget you are using.

  • Highlighting follows your theme, not ours. Standard TextMate scopes, so it reads correctly in light, dark and whatever you actually use. Hardcoded colours look right on the author's machine and wrong on everyone else's.
  • Failures appear on the line that failed, with the value that came back, because that is where you are looking. Not in a popup you have to dismiss.
  • A failed assertion is a warning, not an error. It tells you something about a server, not about your file. Marking it red would put an error badge on a perfectly valid document.
  • The response is read only. No Untitled-1 buffers piling up, nothing asking whether you want to save a response you never wrote.
  • The tab tells you the outcome: me · 3 passed · 13ms. You can read the result without switching to the panel.
  • The editor tells you what a request will do before you send it: how many assertions will run, and which requests it will fire first.
  • Chained responses are dropped the moment you edit the file, so a stale token never travels silently after you changed the login above it.
  • No popup for something already on screen. If the failure is underlined and listed in Problems, a modal on top of that is noise.

Works with the files you already have

Assay reads the same .http syntax as REST Client: ### separators, @variables, # @name, {{substitution}} and {{name.response.body.$.path}} chaining. Point it at your existing files and they work.

The format outlives any one tool. Visual Studio 2022 ships .http support of its own, and Microsoft's documentation says it was inspired by the REST Client extension. Your requests are plain text in your repository, readable by more than one editor, and they stay yours if you stop using this one.


Assertions

# @assert status 200
# @assert status < 300
# @assert time < 1000
# @assert header.content-type contains json
# @assert body.$.token exists
# @assert body.$.items.length > 0
# @assert body.$.name matches ^ana
Targets status · time · bytes · header.<name> · body.<path>
Operators = != < <= > >= contains matches exists empty

Omit the operator for equality. Assertions work anywhere in the block.

Results land at the top of the response, passes in green and failures in red, and the editor tab tells you the outcome at a glance: me · 3 passed · 13ms.

A failure is also underlined on the assertion line itself with the value that came back, and listed in the Problems panel. You see what broke without leaving your request file.


Environments

http-client.env.json, committed with the project:

{
  "dev":  { "base": "http://localhost:3000" },
  "prod": { "base": "https://api.example.com" }
}

http-client.private.env.json, never committed:

{ "dev": { "password": "the-real-one" } }

Pick the active one from the status bar. Values in the private file win. Variables declared in the .http file itself still take precedence, so existing files keep behaving exactly as before.


Sessions

APIs that authenticate with a cookie instead of a bearer token work without writing anything extra. Log in once and the session carries:

### Log in, responds with Set-Cookie
# @name login
POST {{base}}/auth

### Already authenticated
GET {{base}}/me

The session belongs to the file and is cleared when you edit it, when you close it, or with Reset chain. A Cookie: header you write yourself always wins over the stored session.

Requests follow redirects, so a cookie set on an intermediate 302 is not visible. Form logins that redirect are affected; JSON APIs, which answer 200 with Set-Cookie, are not.


Your credentials stay on your machine

  • No account, ever. Nothing to sign up for.
  • No cloud sync, no telemetry, no phoning home.
  • Resolved secrets are never written to the log. You see the reference (login.response.body.$.token), not its value.
  • Query parameters and headers that look like credentials are shown as *** (set-cookie included, since that is where the session usually travels).
  • Values from your private environment file are masked anywhere they appear, including inside a response body, because servers do echo back what you sent.
  • Chained responses are dropped as soon as you edit the file, so a stale token never travels silently.

What redaction cannot do. Assay masks what it knows is secret: credential looking parameters and headers, and the exact values from your private environment file. It cannot guess that an arbitrary string in a response body is sensitive, because doing so would corrupt real data. Turn redaction off with assay.redactSecrets when you need the raw response.


Reference

Command
Assay: Send request Ctrl+Alt+R · Cmd+Alt+R on macOS
Assay: Select environment Also on the status bar
Assay: New request file Starter file with the three ideas
Assay: Reset chain Discards saved responses
Setting Default
assay.timeoutMs 30000 How long to wait for a response
assay.redactSecrets true Mask credential-looking values

Status

Early, and honest about it.

Working today: syntax highlighting, request parsing, file and environment variables, assertions with editor diagnostics, request chaining, secret redaction.

Not yet: server-sent events, GraphQL helpers, a cookie jar, and a CLI runner so a .http file can run in CI.

Missing something? Open an issue. The roadmap is driven by what people actually ask for.


MIT · Built for people who keep their requests in the repo
  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
  • Your Privacy Choices
  • Consumer Health Privacy
© 2026 Microsoft