{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://example.local/allrecipes-recipe.schema.json",
  "title": "Allrecipes-style recipe record",
  "description": "One file per classic Allrecipes URL ID: {id}.json. Fields follow schema.org Recipe as published in page JSON-LD, plus the canonical numeric URL id. This schema is a format spec, not a license to scrape allrecipes.com.",
  "type": "object",
  "required": ["id", "url", "name"],
  "additionalProperties": true,
  "properties": {
    "id": {
      "type": "integer",
      "description": "Canonical numeric ID from /recipe/{id}/{slug}/. Do not use the CMS data-doc-id."
    },
    "url": {
      "type": "string",
      "format": "uri",
      "description": "Canonical recipe URL."
    },
    "name": { "type": "string" },
    "description": { "type": ["string", "null"] },
    "author": {
      "oneOf": [
        { "type": "string" },
        {
          "type": "object",
          "properties": {
            "@type": { "type": "string" },
            "name": { "type": "string" }
          }
        }
      ]
    },
    "datePublished": { "type": ["string", "null"] },
    "dateModified": { "type": ["string", "null"] },
    "image": {
      "oneOf": [
        { "type": "string" },
        { "type": "array", "items": { "type": "string" } },
        { "type": "object" }
      ]
    },
    "prepTime": { "type": ["string", "null"], "description": "ISO-8601 duration, e.g. PT20M" },
    "cookTime": { "type": ["string", "null"], "description": "ISO-8601 duration" },
    "totalTime": { "type": ["string", "null"], "description": "ISO-8601 duration" },
    "recipeYield": {
      "oneOf": [
        { "type": "string" },
        { "type": "array", "items": { "type": "string" } },
        { "type": "null" }
      ]
    },
    "recipeCategory": {
      "oneOf": [
        { "type": "string" },
        { "type": "array", "items": { "type": "string" } }
      ]
    },
    "recipeCuisine": {
      "oneOf": [
        { "type": "string" },
        { "type": "array", "items": { "type": "string" } }
      ]
    },
    "keywords": {
      "oneOf": [
        { "type": "string" },
        { "type": "array", "items": { "type": "string" } }
      ]
    },
    "recipeIngredient": {
      "type": "array",
      "items": { "type": "string" }
    },
    "recipeInstructions": {
      "type": "array",
      "items": {
        "oneOf": [
          { "type": "string" },
          {
            "type": "object",
            "properties": {
              "@type": { "type": "string" },
              "name": { "type": "string" },
              "text": { "type": "string" },
              "url": { "type": "string" }
            }
          }
        ]
      }
    },
    "nutrition": {
      "type": "object",
      "properties": {
        "@type": { "const": "NutritionInformation" },
        "calories": { "type": ["string", "number"] },
        "carbohydrateContent": { "type": "string" },
        "cholesterolContent": { "type": "string" },
        "fatContent": { "type": "string" },
        "fiberContent": { "type": "string" },
        "proteinContent": { "type": "string" },
        "saturatedFatContent": { "type": "string" },
        "sodiumContent": { "type": "string" },
        "sugarContent": { "type": "string" }
      }
    },
    "aggregateRating": {
      "type": "object",
      "properties": {
        "@type": { "const": "AggregateRating" },
        "ratingValue": { "type": ["number", "string"] },
        "ratingCount": { "type": ["integer", "string"] },
        "reviewCount": { "type": ["integer", "string"] },
        "bestRating": { "type": ["number", "string"] },
        "worstRating": { "type": ["number", "string"] }
      }
    },
    "video": { "type": ["object", "array", "null"] },
    "source": {
      "type": "object",
      "description": "Provenance for this file.",
      "properties": {
        "site": { "type": "string" },
        "extractedAt": { "type": "string", "format": "date-time" },
        "idSpace": {
          "type": "string",
          "enum": ["classic-recipe-id", "cms-doc-id"],
          "description": "classic-recipe-id = /recipe/{id}/{slug}/. cms-doc-id = newer /{slug}-{docId} editorial URLs."
        }
      }
    }
  }
}
