Structured JSON reports: design an analysis contract that lasts

Give observations, recommendations, missing values, and partial results a predictable place in your response format.

GOOD DATA. GREAT STRUCTURE. — API Engineering illustration by AnalyzeAPI.com

Structured output connects analysis to action. A person may be able to interpret an informal paragraph, but an application needs predictable fields, meaningful states, and a way to detect invalid data. A useful JSON report does more than wrap prose in braces. It describes what was analyzed, what was found, which evidence supports the findings, and what the receiving system should do when information is missing.

This guide proposes a practical report design for analysis workflows. The examples are intentionally small so the contract remains easy to inspect. The response-format reference includes a downloadable schema, while the developer quickstart demonstrates reading the supplied sample files without requiring an account or a live analysis service.

Start with a clear envelope

Give every report a stable identifier, an analysis type, a schema version, and a status. These fields help consumers understand the document before interpreting its findings. Include a sample marker for illustrative data so a demonstration cannot easily be mistaken for a production measurement. Keep the target description separate from the report identifier.

Choose field names that communicate meaning without relying on hidden conventions. A field called status is useful only when its allowed values are documented. Decide whether partial completion is possible and how it differs from failure. A report envelope should let the application answer basic questions consistently, even when the detailed analysis varies across websites, keywords, repositories, and text.

Separate observations from recommendations

An observation describes the supplied evidence. A recommendation suggests a next step. Keep them distinct. “The provided document has no description element” is different from “write a description that summarizes the page.” When those statements are merged into one field, the consumer cannot easily distinguish what was detected from what was proposed.

A finding can contain an identifier, a readable title, evidence, and a recommended action. Where the evidence has a location, preserve it. That might be a document section, a repository path, or a record identifier. The location makes the result reviewable and supports interfaces that let a person inspect the source before acting.

Model missing information deliberately

Decide how unavailable values should appear. An omitted field, an explicit null, and a numeric zero mean different things. A zero measurement asserts something was measured and produced zero. It should not be used as a convenient replacement for information the collector never obtained.

JSON Schema's object reference explains that defining properties does not automatically make them required, and that required fields are declared separately. It also distinguishes a missing property from a property whose value is null. Use those rules intentionally. Your schema should express the states your application understands rather than letting accidental serialization choices define the contract.

Keep the first schema small

Start with the fields needed for the first real use case. For example, require the envelope and a findings array, then define a small finding object with an identifier, title, and evidence. Add optional context fields when they serve a documented purpose. Avoid inventing dozens of speculative fields merely because another dashboard might eventually want them.

A smaller schema is easier to validate, document, and evolve. It also gives reviewers a better chance of noticing ambiguity. If two developers interpret a field differently, fix the name or description before adding more structure. The goal is a shared contract, not an impressive-looking document that only its author can explain.

Decide how to handle extra properties

Some workflows should reject unexpected keys because the consumer depends on a tightly controlled shape. Others may need an extension area for provider-specific metadata. Make that decision explicit and test it. Do not assume every validator will infer the same behavior from a list of known fields, and avoid silently discarding unexpected data that might indicate an upstream error.

Validate in layers

First parse the JSON. Then validate its structure. Then apply domain checks that a general schema may not capture. A report can be syntactically valid and still refer to an unknown analysis type, an impossible count, or an unsupported claim. Structural validation is necessary for dependable parsing, but it is not a truth detector.

Keep validation errors actionable. Report which field failed and why, while avoiding exposure of sensitive input values in logs. Separate malformed JSON from a schema mismatch and from a domain-level inconsistency. Those conditions may require different fixes, and a single generic error makes them harder to investigate.

Avoid arbitrary scores without definitions

A numeric score is useful only when its meaning is documented. Explain the scale, the aggregation method, the underlying checks, and any missing observations. A score that mixes repository structure, SEO metadata, and writing quality into one number may be difficult to interpret even when every individual measurement is valid.

Prefer the underlying findings when they answer the question directly. If a report does include an aggregate, retain the components and their provenance. Do not represent a model's self-reported confidence as a calibrated probability without a separate basis for doing so. A precise-looking field should not create more certainty than the evidence supports.

Design partial and failed results

A batch may finish only some of its work. Represent that state explicitly with completed and unavailable items, along with the reason for each failure. Preserve useful results instead of either discarding everything or presenting the successful subset as a complete assessment. Consumers need enough information to decide whether to proceed, retry, or request review.

Keep errors separate from findings. An unavailable document is not evidence that the document lacks a title. A failed repository retrieval is not evidence that the repository has no tests. These distinctions seem simple, but they are easy to lose when a pipeline attempts to force every outcome into the same list of quality warnings.

Version changes with consumers in mind

Record a schema version and define how it relates to compatibility. Renaming a required field can break a consumer even if the new name is clearer. Adding a field may also affect a strict validator. Test changes against the clients that actually use the report instead of assuming that a small-looking edit is automatically safe.

Maintain a set of valid and invalid fixtures. Valid fixtures show the expected states, including partial completion. Invalid fixtures exercise missing fields, unexpected values, and malformed evidence objects. Use those fixtures in parser tests so the contract becomes something executable rather than documentation that slowly drifts away from the implementation.

Test the contract with a hand-written example

Before generating a large report, write one finding by hand and ask a second developer to consume it. Can they tell what was observed, where the evidence came from, and whether the action is mandatory or suggested? Then remove a required field, change a type, and introduce an unavailable value. The consumer should reject or handle each case deliberately. This exercise exposes vague semantics earlier than a large integration does. Keep the example as a fixture, and update it through the same review process as the schema whenever the contract changes.

Build interfaces from the same contract

Use the report fields to drive readable components: a scope summary, an evidence list, and a next-action section. Keep raw JSON available for developers without making it the only way to understand the result. A useful interface makes the distinction between observed facts, suggestions, and unavailable data visible to nontechnical readers as well.

Before connecting a live provider, test the complete consumer using the sample report library. Confirm the application handles success, partial output, and failure without inventing missing values. Continue with reliable integration patterns for the surrounding request flow. Good structured output is a clear agreement about meaning, not merely a convenient format for moving text between systems.

CONTINUE EXPLORING