skip to content

You inherit a Postman script calling tv4.validate(...). What is tv4 there, and what replaces it?

level: middleimportance: should knowfreq 42%

answer

  1. Resolving is not the same as current
  2. The sandbox lists a replacement for the name
  3. Both replacement and assertion share one engine
  4. The two validate calls reverse their arguments

basics

~10 s

tv4 is a legacy global the Postman sandbox still exposes and marks deprecated; the sandbox names require('ajv') as its replacement. New scripts assert a payload's shape with the jsonSchema assertion instead.

solid answer

~40 s

`tv4` is a **legacy global**, listed among the Postman sandbox's deprecated libraries alongside `atob`, `btoa`, `crypto-js` and `backbone`. The sandbox carries an explicit replacement for each of those names, and the one it gives for `tv4` is `require('ajv')`; the sandbox's type declarations annotate `tv4` the same way. That it still resolves in a script is not evidence it is current API — that is the shim trap. For asserting shape, the first-class spelling is the `jsonSchema` assertion, which is Ajv-backed anyway. Watch the argument order when porting: `tv4.validate(data, schema)` takes the data first, while `new Ajv().validate(schema, data)` takes the schema first. Swapping them does not throw — it validates data as a schema and passes on everything.

code

javascript · 11 lines
javascript
const schema = { type: 'object', properties: { alpha: { type: 'boolean' } } };

// legacy spelling: the DATA comes first
tv4.validate({ alpha: true }, schema);

// current validator: the SCHEMA comes first
const Ajv = require('ajv');
new Ajv().validate(schema, { alpha: true });

// current assertion, backed by the same engine
pm.expect({ alpha: true }).to.be.jsonSchema(schema);

go deeper

for a junior

Recall that tv4 in a Postman script is old code. Do not write it in anything new; reach for the jsonSchema assertion, and know the sandbox itself points the old name at a current replacement.

for a middle

Explain the shim trap: the identifier resolving proves the script runs, not that it is current. Name the replacement the sandbox gives and the argument-order difference between the two validate calls.

for a senior

Show how you would migrate a body of inherited scripts without creating always-green assertions, and why a validator call that cannot fail is a worse outcome than a failing build.

for a principal

Own the deprecation policy angle: portable artefacts outlive tooling versions, so compatibility shims are cheap to keep and expensive to trust. Decide how your team detects and retires legacy spellings.

## What `tv4` is in a Postman script `tv4` is a **legacy global** the Postman sandbox exposes to scripts. It is listed among the sandbox's deprecated libraries — the same set that holds `atob`, `btoa`, `crypto-js` and `backbone` — and the sandbox carries an explicit replacement mapping for each name. The replacement it names for `tv4` is `require('ajv')`. The sandbox's own type declarations say the same thing: the declaration of `tv4` is annotated *use `require('ajv')` instead*. The crucial reading is the one doctrine calls the shim trap: **an identifier that resolves is not evidence that it is current API.** `tv4` resolves in a Postman script. It is still not the spelling you write today. | Spelling | Standing | How you get it | |---|---|---| | `tv4` | legacy, deprecated | already a global in the script | | `require('ajv')` | current validator | required by name in the script | | `jsonSchema(schema)` | current assertion | chained off `pm.expect` or `pm.response.to.have` | ## The argument-order trap when porting This is the detail that actually bites during a migration, because both calls are named `validate` and both return truthy on success: ```javascript // legacy spelling: the DATA comes first tv4.validate({ alpha: true }, schema); // current validator: the SCHEMA comes first const Ajv = require('ajv'); new Ajv().validate(schema, { alpha: true }); ``` Swap them by accident and the call does not throw. It validates your data *as if it were a schema*, and an object with no recognised keywords constrains nothing, so the check passes on absolutely everything. A silently-always-green assertion is the worst possible failure mode for a test, and it is exactly what a careless port produces. ## The three routes and when to reach for each 1. **The `jsonSchema` assertion.** The normal answer. `pm.response.to.have.jsonSchema(schema)` parses the reply body and validates it, and the failure appears as an ordinary assertion failure in the run report. It is backed by Ajv, so you are not giving anything up by using the shorter spelling. 2. **`require('ajv')` directly.** For the cases the assertion does not cover — compiling a schema once and reusing the compiled function, or driving the validator yourself and doing something bespoke with the result. 3. **`tv4`.** Only in scripts you inherited and have not migrated yet. Nothing new should be written against it. ## Assertion or raw validator Both current routes end at the same engine, so the choice is about ergonomics rather than power: | Route | Reach for it when | |---|---| | `pm.expect(v).to.be.jsonSchema(s)` | you want a pass/fail assertion in the run report | | `require('ajv')` | you need the validator object itself | The direct route earns its keep in two narrow cases. `ajv.compile(schema)` returns a reusable validate function, which is worth having when one schema is checked many times in a single run. `ajv.compileAsync(schema)` exists for schemas that have to be assembled from more than one document, where a loader supplies the pieces. Everything else — the ordinary "does this reply look right" check — is shorter and more readable as the assertion. ## What a good answer sounds like - name it as **legacy**, not as "the schema library Postman uses"; - give the current spelling in the same breath — the sandbox itself points `tv4` at `require('ajv')`; - know that the first-class spelling for *asserting* shape is the `jsonSchema` assertion rather than a bare validator call, because an assertion failure is what makes a run report readable; - flag the argument-order flip as the concrete porting hazard. ## Why the shim exists at all Scripts are stored inside collection files, and those files are portable artefacts that outlive any given version of the tooling. Removing a global would break every collection that was ever written against it, so the sandbox keeps the old names resolvable and steers authors toward the new ones instead. That is a reasonable engineering trade, and it is why grepping a script for an identifier and finding it present tells you the script *runs* — never that the script is *current*.

  • Why is swapping the two arguments during a port more dangerous than an outright error?
    Because it does not throw. Passing data where a schema is expected means the validator sees an object with no recognised keywords, which constrains nothing, so the check passes on everything. You get a permanently green assertion that asserts nothing — far worse than a red build.
  • Why does the sandbox keep the old name resolvable instead of removing it?
    Scripts live inside collection files, which are portable artefacts that outlive any given version of the tooling. Deleting a global would break every collection ever written against it, so the old names stay resolvable while authors are steered toward the current spellings.

saying these in an interview costs you the question

  • Calls tv4 the schema library Postman uses today
  • Treats a resolving identifier as proof it is current API
  • Keeps the argument order when porting to the new validator
  • Assumes removing tv4 would break nothing in old collections
  • Writes a bare validator call instead of an assertion in tests