JSON Schema Validation

So far you've asserted on individual fields one at a time: check the status code, check id, check title. That works fine for a small response, but a real RecipeBox Recipe object has nested arrays, optional fields, and specific types for each key — writing a separate pm.expect() line for every one of them is tedious and still leaves gaps (what if ingredients comes back as a string instead of an array, and none of your field checks happen to catch it?). JSON Schema lets you describe the entire shape of a response once, then validate the whole thing against that description in a single assertion.

Why Field-by-Field Assertions Don't Scale

Field-by-field assertionsJSON Schema validation
One pm.expect() line per field — grows with every field you add to the Recipe modelOne schema, one assertion, covers the entire object
Easy to forget a field, or forget to check its typeThe schema is the single source of truth for required fields and types
Doesn't catch unexpected extra fields or wrong array item typesCan constrain array item shape, enums, and (optionally) reject unknown properties
Breaks silently one field at a time as the API evolvesBreaks loudly and precisely — the schema mismatch tells you exactly what changed

Writing a Schema for the Recipe Object

A RecipeBox Recipe has id, title, ingredients (an array of strings), steps (an array of strings), photoUri, category, prepMinutes, and isPublished. Here's a JSON Schema describing that shape, saved as a variable or a file you can reuse across requests:

{
  "type": "object",
  "required": ["id", "title", "ingredients", "steps", "category", "prepMinutes", "isPublished"],
  "properties": {
    "id": { "type": "number" },
    "title": { "type": "string" },
    "ingredients": {
      "type": "array",
      "items": { "type": "string" }
    },
    "steps": {
      "type": "array",
      "items": { "type": "string" }
    },
    "photoUri": { "type": ["string", "null"] },
    "category": { "type": "string" },
    "prepMinutes": { "type": "number", "minimum": 0 },
    "isPublished": { "type": "boolean" }
  }
}

Note photoUri allows "string" or "null" — a draft recipe with no photo yet is still a valid Recipe, so the schema should say so rather than forcing every recipe to have a photo.

Validating a Response Against the Schema

On the Get Recipe by ID request (GET {{baseUrl}}/recipes/42), paste the schema into a variable in the Tests tab and run it through pm.response.to.have.jsonSchema(), which Postman exposes using an Ajv-based validator under the hood:

var recipeSchema = {
  "type": "object",
  "required": ["id", "title", "ingredients", "steps", "category", "prepMinutes", "isPublished"],
  "properties": {
    "id": { "type": "number" },
    "title": { "type": "string" },
    "ingredients": { "type": "array", "items": { "type": "string" } },
    "steps": { "type": "array", "items": { "type": "string" } },
    "photoUri": { "type": ["string", "null"] },
    "category": { "type": "string" },
    "prepMinutes": { "type": "number", "minimum": 0 },
    "isPublished": { "type": "boolean" }
  }
};

pm.test("response matches the Recipe schema", function () {
  pm.response.to.have.status(200);
  pm.expect(pm.response.json()).to.be.jsonSchema(recipeSchema);
});

If a field is missing, has the wrong type, or a required key is absent, this single test fails with a message naming exactly which part of the schema didn't match — far more useful than five separate green/red checkmarks with no context connecting them.

Older Postman Versions and the tv4 Library

Older Postman sandbox versions exposed the tv4 library directly for schema validation. You may still see this pattern in older collections or tutorials:

var jsonData = pm.response.json();
var result = tv4.validate(jsonData, recipeSchema);

pm.test("response matches Recipe schema (tv4)", function () {
  pm.expect(result).to.be.true;
});

Current Postman versions favor pm.response.to.have.jsonSchema() (Ajv-based) since it gives clearer validation error messages and supports more of the JSON Schema specification. Prefer it for anything you're writing today; recognizing the tv4 pattern is mainly useful for reading existing collections.

Note: A schema check doesn't replace targeted assertions — it replaces the bulk of them. It's still worth asserting specific business values separately (e.g. "a newly created recipe's isPublished is false by default") since a schema only checks shape and type, not business logic.
Next: You've been running one request at a time in Postman's UI. The Collection Runner runs your whole collection — every request, in order — in one pass, optionally against a data file of multiple inputs.