curl JSON requests: verify the body, Content-Type and actual HTTP method
By ON Lab · Sources checked November 8, 2026
When sending JSON with curl, verify three separate things: valid JSON body bytes, the request Content-Type and the actual HTTP method. Accept describes the response representation requested from the server. An X-HTTP-Method-Override header is a header value; it does not make curl change a POST into a PUT on the wire.
A historical reader received a 415 response while testing a Java application. Their command set Accept, sent inline data and requested POST with an override header, while the shown Java handler was mapped to PUT. We checked the current curl manual and reproduced the client-side boundaries against a local echo server. We did not run Spring, authenticate to an API or establish every cause of that application's response.
Put the sample body in a file first
{
"note": "demo",
"enabled": true
}
Save an original test payload as a new file such as payload.json. It must be a complete JSON value, including the braces for an object. Fields and types must match the actual test endpoint's contract; our small payload is not a promise that a Java configuration object accepts those fields.
A file keeps JSON quoting separate from the shell's argument parsing. A command that visually contains quote characters in a shell prompt does not prove that the server received valid JSON. Inspect the file with a JSON validator before changing several server settings at once.
Send the media type and preserve the file bytes
curl --header "Content-Type: application/json" --data-binary @payload.json http://127.0.0.1:8080/your-test-route
Use an authorized disposable test route. This example sends data using curl's normal POST behavior. It does not start a server or establish the correct route for your application.
The --data-binary choice matters when exact file bytes are part of the comparison. In our local test, --data with an @file source removed line breaks from the formatted sample, while --data-binary preserved it. Both could still represent valid JSON, but they were not byte-identical. Ordinary --data also used an application/x-www-form-urlencoded Content-Type by default in the observed request.
The JSON convenience option still needs valid input
curl --json @payload.json http://127.0.0.1:8080/your-test-route
The current manual documents --json as a convenience for binary data plus JSON Content-Type and Accept headers. It was added in curl 7.82.0; check curl --version before using it on an older machine. The explicit header and --data-binary form remains a useful comparison when the convenience flag is unavailable.
curl does not validate the supplied JSON syntax with this option. Our echo server received the literal text not-json when we passed it through --json, and its JSON parser rejected that body. The option selected how to send the data; it did not prove the payload conformed to JSON or to an application's schema.
Select the real method deliberately
curl --request PUT --json @payload.json http://127.0.0.1:8080/your-test-route
Use this only when PUT is the documented method for the intended test route. In our echo fixture, that command arrived as PUT. A separate command explicitly requesting POST while adding X-HTTP-Method-Override: PUT still arrived as POST with that header.
Some server middleware may interpret an override header, but that is server behavior which must be verified. The header alone is not evidence that curl transmitted PUT or that the original framework honored the override. Compare the actual request with the handler's method mapping instead of guessing from the header name.
What the six local cases showed
| Client case | Observed boundary |
|---|---|
| --data from the formatted file | Default form media type and changed newline bytes |
| Explicit JSON type with --data-binary | JSON request type and original file bytes |
| --json from the file | JSON request and response-preference headers |
| --request PUT with --json | Actual method PUT |
| POST with a PUT override header | Actual method POST plus the header |
| --json with invalid text | Unvalidated body transmitted; echo parser reported invalid JSON |
The server was deliberately an inspector that returned request details. It was not a model of Spring's route selection, message converters or media-type rejection. We closed that local server after the test. Successful transport to an echo endpoint cannot establish that a real application will accept the same request.
If the endpoint still rejects the request
- Confirm the exact route and documented method.
- Read the body bytes actually sent and validate the JSON.
- Inspect Content-Type separately from Accept.
- Confirm any method-override middleware rather than assuming it is active.
- Review the endpoint's accepted media types, schema and framework parsing with its own diagnostics.
A 415 response should not be turned into a claim that one client flag fixes every server. Keep the verified request shape separate from the still-unverified application configuration. For HTTP status versus curl process exit behavior, the HTTP failure and exit-code guide covers that different boundary.
Checked November 8, 2026 with curl 8.7.1 and a local six-case HTTP echo fixture. No original Java application, external API, authentication, production write or universal 415 remedy was tested.