How to Test JSON APIs Without Writing Code
No script needed to sanity-check an API response. Format it, validate the shape, read errors against RFC 9457, and keep good samples as fixtures.
Most API testing advice starts with "write a script" or "set up a test framework". That is the right end state for a real project, but it skips the first 80% of the job: understanding what the API actually returned. Before you reach for Postman collections or pytest, there is a faster loop that takes about thirty seconds per response and needs nothing installed.
The workflow below is the one worth doing on every unfamiliar endpoint before you commit to automating it: make the payload readable, check the shape rather than trusting the status code, read the error body against the standard it claims to follow, and keep the samples that looked right.
Step 1: Make the response readable
Paste the raw response body into the JSON Formatter. It validates the payload and re-indents it, which immediately answers two questions: is this valid JSON at all, and what is the shape of the data? If the formatter reports an error, read the message carefully - most "the API is broken" reports turn out to be a truncated body or a missing closing brace. When you need the formal grammar, the syntax rules come from RFC 8259, the IETF JSON specification.
A habit worth building: format the response before you look at it. A 500-character one-liner hides problems that a properly indented tree shows instantly, like an array nested one level deeper than the docs claim. And when the payload is large, pull out just the fields you care about with the JSONPath Query tool instead of scrolling through the whole body.
Step 2: Check the structure, not just the status code
A 200 response with the wrong shape is still a bug. Once the payload is readable, compare it against the documented schema. If your API publishes a JSON Schema - the vocabulary itself is documented at json-schema.org - run the response through the JSON Schema Validator and fix the mismatch at the source instead of patching it in every client.
If the call itself is what you want to inspect, skip the copy-paste cycle and send it directly: the HTTP API Tester lets you pick a method, add headers and a JSON body, and see the real status code, response headers, and pretty-printed body - no CORS errors, because the request is proxied from the edge.
Changed between deploys? When the same endpoint returns different data than it did last week, run the two responses through the JSON Diff tool to see exactly which fields moved instead of eyeballing two blobs side by side.
No schema? Then check the boring things manually: are the field names
consistent (camelCase everywhere, not mixed with snake_case)? Are dates in
one format? Is null used for missing values, or is the field
absent? Those inconsistencies are what break frontends weeks later.
Step 3: Read the error body like a spec
The happy path is the easy half. Errors are where APIs quietly disagree with their own documentation, and most teams never test them - which is exactly why they fail in production, at the moment someone needs the message most. If the API returns a structured error body, you can check it against a published standard instead of guessing what the fields mean.
The IETF standardised that body shape in
RFC 9457, "Problem Details for HTTP APIs"
(July 2023, which obsoletes the older RFC 7807), carried under the media
type application/problem+json. A conforming error object
carries five standard members:
| Member | Type | What it carries | What to verify |
|---|---|---|---|
type | string (URI) | Identifies the problem type; defaults to about:blank when absent. | Stable and resolvable - and it is the field your client branches on. |
status | number | The HTTP status code the origin server generated for this occurrence. | Matches the actual status line of the response. |
title | string | A short, human-readable summary of the problem type. | Does not change from occurrence to occurrence. |
detail | string | A human-readable explanation specific to this occurrence. | Focuses on helping the client correct the problem; leaks no internals. |
instance | string (URI) | Identifies this specific occurrence of the problem. | Present, so support and logs can point at one event. |
The checking rule that catches the most bugs: branch on
type, never on title or detail.
Both of those are written for humans, may be localised, and are allowed to
change between occurrences - the spec is explicit that consumers must use
the type URI as the primary identifier and should not parse
detail for machine-readable information. Anything a program
needs to act on belongs in an extension member, such as a
invalid-params array or a balance field.
In practice the check looks like this: format the error body first (a
surprising share of "our API returns problem+json" claims fail that very
first test), compare the status member against the real HTTP
status line, and confirm the type URI actually resolves to
documentation rather than a placeholder domain.
"status": 400 - but the HTTP status line said 200? That is the bug.
"type": "about:blank" - generic, no extra semantics beyond the status code.
"type": "https://api.example.com/problems/out-of-credit" - actionable. Step 4: Know which contract the API claims
"Check the response against the docs" is only useful once you know which document is authoritative. Four different specifications get called "the API schema" in casual conversation, and they answer different questions. Pin down which one your API actually implements before treating any mismatch as a bug:
| Specification | What it pins down | The question it answers |
|---|---|---|
| OpenAPI Specification 3.1.0 | Endpoints, parameters, request and response schemas for an HTTP API. | Does this endpoint exist, and does it accept this shape? |
| JSON:API v1.1 | A full convention for request and response documents; media type application/vnd.api+json. | Are resources, relationships, and pagination shaped the agreed way? |
| JSON Schema 2020-12 | The structure of a single JSON document; media type application/schema+json. | Is the shape of this one payload correct? |
| RFC 9457 | The error document format; media type application/problem+json. | How are failures reported, and can a client act on them? |
An API can implement all four at once, and the mismatch is usually at a
boundary between them: the field is present in the OpenAPI document but
missing from the live response, or the JSON:API envelope is perfect while
its errors array ignores the problem-details format. Both are
genuine documentation bugs worth reporting. Validate the sample against the
schema with the
JSON Schema Validator;
if the mismatch survives validation and the endpoint is genuinely doing
what you documented, the document is what needs fixing.
For the status-code side of the contract, the reference is RFC 9110, "HTTP Semantics" (June 2022, Internet Standard 97), which defines what each class of status code means - 4xx is the client's request, 5xx is the server's failure, and a body that disagrees with either is a finding, not a style question.
Step 5: Convert samples for your tools
The same response usually needs to end up in a different format: CSV for a spreadsheet, YAML for a config file, XML for a legacy consumer. The JSON to CSV and JSON to YAML converters do this without you hand-writing a mapping, and the JSON to XML converter covers the legacy side. They also double as a sanity check: if the conversion produces nonsense, your mental model of the data is probably wrong.
Step 6: Turn a sample into a fixture
When a response looks right, save it. A small library of real API samples - one happy path, one error shape, one empty result - is the fastest way to start a test suite later, and it forces you to actually read the error responses, which are the ones nobody ever tests. Capture the request alongside the response so the fixture is reproducible rather than a mystery blob:
curl -s https://api.example.com/v1/orders/42 \
-H "Accept: application/json" \
-o fixtures/orders-42-happy.json When you do automate, the cURL to Code Converter turns a request captured from browser devtools into Python, JavaScript, Go, or PHP code, so the call you verified by hand becomes the call in your test suite. Start with the samples, not with a framework: the fixtures tell you exactly which assertions are worth writing.
The 60-second pass, in order
- Format the body - is it valid JSON at all, and what shape is it?
- Compare it against the schema - is the structure right, not just the status code?
- If it is an error, check
type,status,title,detail, andinstanceinstead of reading the message. - Ask which contract applies: OpenAPI, JSON:API, JSON Schema, or RFC 9457.
- Diff against yesterday's sample when anything looks unfamiliar.
- Save the response as a fixture before you close the tab.
The workflow in one paragraph
Format it, validate it against the schema, read the error body against the standard it claims, convert a copy for whatever consumer needs it, and keep the good samples as fixtures. All of it happens in the browser, so you can paste sensitive-looking response data without worrying about where it is going. When the API is stable enough that you are repeating the same checks ten times a day, that is the signal to automate - and by then you will know exactly which assertions matter.
Related reading
- How to Write Test Cases (with Examples and a Template) - once an endpoint behaves, the next job is turning what you learned into test cases someone else can run: steps, data, and expected results.
- How to Generate Realistic Test Data for QA - once you have a library of good API samples, this guide shows how to turn them into believable fixtures instead of clean-room test data.
- Debugging Network Issues: DNS, SSL, and Headers - when the response never arrives or the status code makes no sense, the problem is usually below the payload, in the network plumbing.
- What is Regression Testing? Techniques and Checklist - the endpoint you just verified will change again; this is how to decide what to re-run when it does.