VReq - File Based API Testing for VS Code
Run API requests from simple text files with environments, chaining,
scripts, and tests directly inside VS Code.
VReq is a lightweight file-based API testing tool designed as a
developer-friendly alternative to GUI tools like Postman.
Sample test API repository setup here
Features
• Run HTTP requests directly from .vreq files
• Environment configuration using .venv files
• Request chaining and dependencies
• Pre/Post request scripts
• Multi-request scenario orchestration with .vscenario
• Built-in response viewer (JSON + headers + timing)
• Test assertions for API validation
• CodeLens support for quick execution
• Diagnostics and linting for request files
File Types
File Purpose
.vreq API requests and collections
.venv Environment variables
.vscript Pre/Post scripts
.vtest Optional test definitions
.vscenario Multi-request scenarios and workflows
Quick Start
Create an environment
Create env/dev.venv
host: https://postman-echo.com
headers.Accept: application/json
tenantId: dev
timeoutMs: 30000
debug: false
forceNoProxy: false
useSystemProxy: false
# optional enterprise CA bundle (PEM)
tls.caFile: C:\\certs\\corp-root-ca.pem
# optional local dev bypass for https://localhost only
tls.allowInsecureLocalhost: true
# optional override when useSystemProxy=true
# proxyUrl: http://proxy.company.local:8080
Create a request
Create reqs/echo.vreq
Collection: Echo Demo
---
Name: getEcho
Request:
GET {{host}}/get
Query:
hello: world
tenant: {{tenantId}}
page: 1
Headers:
Accept: application/json
Tests:
- status is 200
- header content-type contains json
Auth examples (with and without Auth)
Create reqs/auth-samples.vreq
Collection: Auth Samples
---
Name: publicEcho
Request:
GET {{host}}/get
Query:
mode: public
Headers:
Accept: application/json
Tests:
- status is 200
---
Name: securedApi
Request:
GET {{apiHost}}/secure/data
Auth:
Use: env
Headers:
Accept: application/json
Tests:
- status is 200
With Auth: Use: env, add these in .venv:
auth.type: oauth2-client-credentials
auth.tokenUrl: https://login.example.com/oauth2/token
auth.clientId: {{clientId}}
auth.clientSecret: {{clientSecret}}
auth.scope: api.read
You can override the OAuth scope per request using the request Auth: section:
Auth:
Use: env
Scope: api.write
You can also override the OAuth cache key per request:
Auth:
Use: env
CacheKey: pricing-uat-forward
For backward compatibility, you can also override the OAuth scope using a request header:
Headers:
Accept: application/json
Scope: api.write
OAuth client-credentials tokens are cached automatically per auth configuration. By default, VReq derives the cache key from tokenUrl, clientId, and scope, so different credentials do not reuse the same token.
Per-request Scope: overrides are included in that cache separation, so two requests or scenario steps using the same client credentials but different scopes will generate different cached tokens automatically.
In .vscenario flow runs, requests with the same OAuth client credentials and the same effective scope will reuse the cached token across steps to avoid unnecessary token requests.
If you want to control token reuse explicitly, set:
auth.cacheKey: pricing-auth
This is useful when you want multiple requests to intentionally share the same cached token, or when you want to force different requests to use separate cache entries.
If a request defines Auth: CacheKey: while using Auth: Use: env, that request-level cache key overrides the environment auth.cacheKey. This is especially useful in .vscenario flows where different requests need different cached tokens even when they share the same selected environment.
Only requests that contain an Auth: section will send Authorization headers.
Select environment
Open Command Palette and run:
VReq: Select Environment
Run the request
Open the .vreq file and click:
▶ Run Request
or
▶ Run File
Swagger/OpenAPI Import
VReq can generate requests directly from a local swagger.json / openapi.json file or a URL to one.
Open Command Palette and run:
VReq: Import Swagger/OpenAPI
Then paste either:
• https://petstore.swagger.io/v2/swagger.json
• /absolute/path/to/swagger.json
• relative/path/to/swagger.json
VReq generates everything under:
imports/swagger/<api-name>/
manifest.json
source.json
env/default.venv
requests/*.vreq
scenarios/smoke.vscenario
Notes:
• v1 supports JSON Swagger/OpenAPI documents
• generated request URLs convert path params like {id} to {{id}}
• generated requests include default tests and auth scaffolding where possible
• manifest.json stores the original import source for refresh
To regenerate an existing import, run:
VReq: Refresh Swagger/OpenAPI Imports
Scenarios
Use .vscenario when you need to:
• run multiple .vreq requests in sequence
• reuse one selected environment across all requests
• override request Vars, Query, Headers, or Body
• pass outputs between steps with SaveAs
• run JavaScript calculation or comparison scripts
• persist intermediate artifacts to disk
• trigger follow-up requests conditionally
• evaluate final scenario assertions
Step-by-step setup
1. Create the environment
Create env/dev.venv
host: https://postman-echo.com
tenantId: dev
quoteStartDate: 2026-01-01
quoteEndDate: 2027-12-31
debug: true
2. Create the request files
Create reqs/pricing.vreq
Collection: Pricing
---
Name: GetHistoricalPrices
Request:
GET {{host}}/get
Query:
type: historical
startDate: {{quoteStartDate}}
endDate: 2026-06-24
Headers:
Accept: application/json
X-Tenant: {{tenantId}}
Tests:
- status is 200
- header content-type contains json
---
Name: GetForwardPrices
Request:
GET {{host}}/get
Query:
type: forward
startDate: 2026-06-25
endDate: {{quoteEndDate}}
Headers:
Accept: application/json
X-Tenant: {{tenantId}}
Tests:
- status is 200
- header content-type contains json
Create reqs/integrations.vreq
Collection: Integrations
---
Name: GetSalesforceData
Request:
GET {{host}}/get
Query:
source: salesforce
expectedValue: 4.5
Headers:
Accept: application/json
X-Tenant: {{tenantId}}
Tests:
- status is 200
- header content-type contains json
---
Name: CreateJiraIssue
Request:
POST {{host}}/post
Headers:
Content-Type: application/json
Accept: application/json
X-Tenant: {{tenantId}}
Body:
{
"summary": "Price mismatch detected",
"description": "Calculated={{comparison.finalValue}}, Salesforce={{comparison.salesforceValue}}"
}
Tests:
- status is 200
- header content-type contains json
3. Create the scenario scripts
Create scripts/ProfitMargin.vscript
export default function run(inputs, ctx) {
ctx.log(`quoteStartDate=${inputs.quoteStartDate}`);
ctx.log(`quoteEndDate=${inputs.quoteEndDate}`);
const historicalAverage = 100;
const forwardAverage = 100;
const combinedAverage = (historicalAverage + forwardAverage) / 2;
const finalValue = combinedAverage * 0.045;
ctx.log(`combinedAverage=${combinedAverage}`);
ctx.log(`finalValue=${finalValue}`);
return {
historicalAverage,
forwardAverage,
combinedAverage,
finalValue
};
}
Create scripts/CompareSalesforce.vscript
export default function run(inputs, ctx) {
const calculated = Number(inputs.calculated.finalValue);
const salesforceValue = Number(inputs.salesforce.args.expectedValue);
const match = calculated === salesforceValue;
ctx.log(`calculated=${calculated}`);
ctx.log(`salesforceValue=${salesforceValue}`);
ctx.log(`match=${match}`);
return {
match,
finalValue: calculated,
salesforceValue
};
}
4. Create the scenario file
Create scenarios/price-validation.vscenario
Name: Price Validation
Use Requests:
- Collection: Pricing
Request: GetHistoricalPrices
- Collection: Pricing
Request: GetForwardPrices
- Collection: Integrations
Request: GetSalesforceData
- Collection: Integrations
Request: CreateJiraIssue
Inputs:
quoteStartDate: 2026-01-01
quoteEndDate: 2027-12-31
Request Overrides:
GetHistoricalPrices.Query:
startDate: {{quoteStartDate}}
endDate: 2026-06-24
GetForwardPrices.Query:
startDate: 2026-06-25
endDate: {{quoteEndDate}}
CreateJiraIssue.Body:
{
"summary": "Price mismatch detected"
}
Scripts:
- File: scripts/ProfitMargin.vscript
As: profitMargin
- File: scripts/CompareSalesforce.vscript
As: compareCalc
Flow:
- Run: GetHistoricalPrices
SaveAs: historical
Persist: artifacts/historical.json
PersistAs: json
- Run: GetForwardPrices
SaveAs: forward
Persist: artifacts/forward.json
PersistAs: json
- Script: profitMargin
Inputs:
quoteStartDate: {{quoteStartDate}}
quoteEndDate: {{quoteEndDate}}
historicalPrices: {{historical.response.json}}
forwardPrices: {{forward.response.json}}
SaveAs: calcResult
Persist: artifacts/calcResult.json
PersistAs: full
- Run: GetSalesforceData
SaveAs: salesforce
- Script: compareCalc
Inputs:
calculated: {{calcResult}}
salesforce: {{salesforce.response.json}}
SaveAs: comparison
Persist: artifacts/comparison.json
PersistAs: json
- If: comparison.match == false
Then:
- Run: CreateJiraIssue
SaveAs: jiraResult
Persist: artifacts/jiraResult.json
PersistAs: full
Assertions:
- expr comparison.match equals true
5. Select the environment
Open Command Palette and run:
VReq: Select Environment
Pick dev.
6. Run the scenario
Open the .vscenario file and use:
▶ Run Scenario
or press:
Ctrl+Enter / Cmd+Enter
7. Check outputs
After the run:
• the progress popup shows the current scenario stage
• the VReq response viewer shows scenario steps and assertions
• persisted artifacts are written to the artifacts/ folder
• script logs are written to Output -> VReq
Scenario syntax overview
Supported top-level sections:
Name:
Use Requests:
Inputs:
Request Overrides:
Scripts:
Flow:
Assertions:
Supported request overrides:
Request Overrides:
GetHistoricalPrices.Vars:
quoteStartDate: {{quoteStartDate}}
GetHistoricalPrices.Query:
startDate: {{quoteStartDate}}
GetHistoricalPrices.Headers:
X-Tenant: {{tenantId}}
GetHistoricalPrices.Body:
{
"from": "{{quoteStartDate}}"
}
Supported step types:
- Run: <request-name>
- Script: <script-alias>
- If: <expression>
Then:
- Run: <request-name>
Run steps also support step-level overrides. These override both the base .vreq request and any scenario-level Request Overrides: values:
- Run: <request-name>
Vars:
key: value
Query:
key: value
Headers:
key: value
Body:
{
"key": "value"
}
Scenario Inputs: can be referenced directly inside step-level Run: overrides, and also indirectly through step-level Vars: values. For example:
Inputs:
quoteStartDate: 2026-01-01
Flow:
- Run: GetPrices
Vars:
fromDate: {{quoteStartDate}}
Query:
startDate: {{fromDate}}
SaveAs: historical
In this example, {{quoteStartDate}} resolves from Inputs:, and {{fromDate}} then resolves from the step-level Vars: override.
Example: run the same request twice with different step-level overrides
Base request in reqs/pricing.vreq:
Collection: Pricing
Name: GetPrices
Vars:
priceType: historical
fromDate: 2026-01-01
toDate: 2026-06-24
Request:
GET {{host}}/get
Query:
type: {{priceType}}
startDate: {{fromDate}}
endDate: {{toDate}}
Headers:
Accept: application/json
X-Tenant: {{tenantId}}
Tests:
- status is 200
- header content-type contains json
Scenario:
Name: Run Same Request Twice
Use Requests:
- Collection: Pricing
Request: GetPrices
Request Overrides:
GetPrices.Headers:
X-Scenario: price-check
Flow:
- Run: GetPrices
Vars:
priceType: historical
fromDate: 2026-01-01
toDate: 2026-06-24
Query:
startDate: 2026-01-01
endDate: 2026-06-24
SaveAs: historical
- Run: GetPrices
Vars:
priceType: forward
fromDate: 2026-06-25
toDate: 2027-12-31
Query:
startDate: 2026-06-25
endDate: 2027-12-31
Headers:
X-Mode: forward
SaveAs: forward
Assertions:
- expr historical.status equals 200
- expr forward.status equals 200
In this example:
• Request Overrides: applies to every GetPrices execution in the scenario
• the first Run: step executes GetPrices with historical values
• the second Run: step executes the same GetPrices request again with different Vars, Query, and Headers
• step-level overrides take precedence over Request Overrides:
Supported persistence modes:
PersistAs: json
PersistAs: raw
PersistAs: full
Scenario validation checks
VReq validates .vscenario files in the editor before execution and shows diagnostics for common issues.
Current checks include:
• missing Use Requests: - File: ... targets
• missing Scripts: - File: ... targets
• unresolved Collection + Request references
• ambiguous Collection + Request matches across multiple .vreq files
• unknown Run: request names
• unknown Script: aliases
• duplicate script aliases
• Request Overrides: targeting unknown requests
• PersistAs used without Persist
• values referenced before a SaveAs step defines them
• warnings when multiple scenario Run: steps inherit the same env auth.cacheKey without a request-level Auth: CacheKey: override
• If: / Assertions: referencing unknown or conditionally-defined values
These checks help catch broken scenario wiring before you run the workflow.
Tests
Example assertions:
Tests:
- status is 200
- json.path code equals {{code}}
- json.path total greaterThan 10
- json.path discount lessThan 0.5
- json.expr subtotal + tax equals 108
- json.expr (subtotal + tax) / itemCount greaterThan 20
- json.expr qty * unitPrice lessThan 1000
- header content-type contains json
- json.path user.id exists
- json.path status equals success
- json.path items any(itemId equals "553")
- json.path items filter(itemId equals "553") count equals 1
- body contains success
- time lessThanMs 500
Scripts
Example pre-script.vscript
log.info("Executing pre request script")
ctx.set("traceId", crypto.randomUUID())
req.headers["X-Trace-Id"] = ctx.get("traceId")
Objects available inside scripts:
Object Purpose
env environment variables
ctx shared runtime variables
req request object
res response object
log extension logger
JSON bodies may include comments in Body: sections. VReq ignores // ..., /* ... */, and line-start # ... comments before sending JSON requests.
Scenario scripts use JavaScript too. A .vscenario script should export a default function:
export default function run(inputs, ctx) {
ctx.log("running scenario script");
return { ok: true };
}
Objects available inside scenario scripts:
Object Purpose
inputs resolved scenario step inputs
ctx script logger and metadata
Commands
Command Description
VReq: Select Environment choose environment
VReq: Run Current Request run request under cursor
VReq: Run File run entire collection
VReq: Run Scenario run current scenario file
VReq: Show Last Response open response viewer
Why VReq?
Most API tools rely heavily on GUI workflows.
VReq focuses on:
• version-controlled API tests
• simple text-based configuration
• automation-friendly workflows
• developer-centric experience
Your API tests live alongside your source code.
License
MIT License