JSON isn't under-specified, you can tell if something's valid JSON just based on the rules here: http://www.json.org/json-en.html. The mapping of the JSON data model to the data models found in various languages is what's ambiguous. Which is not impacted by curl supporting JSON in the slightest:
- The `--json` option only adds a content-type header, it doesn't alter the transmitted data at all.
- The `--jp` option has a bespoke format that's not part of the JSON spec, and which doesn't actually depend on a specific data model, it's just string manipulation.
Numbers are the main thing I assumed you were talking about: the JSON spec is clear though, numbers can be arbitrarily long.
The problem is not with the JSON spec, the problem is when you are converting from one data model to another. Any program which claims to perfectly round-trip the JSON data-model should support arbitrarily long numbers, there's no ambiguity in the spec about that.
If you are only parsing JSON as a means to encode your own data-model, then there's no obligation to support arbitrary precision, but users should not expect to be able to round-trip arbitrary JSON data.
AFAICT, `--jp` doesn't do anything which would affect the length of supported numbers, even though it's generating JSON.
JSON lets you write numbers. They can have a sign, decimal part, and an exponent. The standard euphemistically describes this as:
> JSON is agnostic about the semantics of numbers. […] JSON instead offers only the representation of numbers that humans use: a sequence of digits. […] That is enough to allow interchange.
But can you encode/decode an arbitrary integer or a float? Probably not!
* Float values like Infinity or NaN cannot be represented.
* JSON doesn't have separate representation for ints and floats. If an implementation decodes an integer value as a float, this might lose precision.
* JSON doesn't impose any size limits. A JSON number could validly describe a 1000-bit integer, but no reasonable implementation would be able to decode this.
The result is that sane programs – that don't want to be at the mercy of whatever JSON implementation processes the document – might encode large integers as strings. In particular, integers beyond JavaScript's Number.MAX_SAFE_INTEGER (2^53 - 1) should be considered unsafe in a JSON document.
Another result is that no real-world JSON representation can round-trip “correctly”: instead of treating numbers as “a sequence of digits” they might convert them to a float64, in which case a JSON → data model → JSON roundtrip might result in a different document. I would consider that to be a problem due to underspecification.
The numbers was what I was mainly thinking of, so thanks for your exhausting enumeration of those problems.
Jason.org requires white space for empty arrays and objects while RFC 8259 does not (and I often see [] and {} in the wild).
A lot of packages de fact break the spec in other ways, such as ppl blatting python maps out rather than converting them to JSON so that the keys are quoted as ‘foo’ rather than “foo”. I’ve complained about this when trying to parse the stuff only to receive the response “it works for me so you must have a bug” from the pythonistas. This has happened in multiple projects.
TIL! Seems to be a quite confused topic as many things (it seems for example some java servers) even require it, but you do seem to be right, as JSON must always be utf8.
I know I've done the quoting dance before, while exploring an API in one project I resorted to using zsh heredocs to build the payload argument to avoid all quoting issues. I'm sure there is a better way already but it sounds nice to have this built into curl as its so common.
I have recently been trying a port of HTTPie in Rust, xh [0] (which is needlessly hard to find in a websearch). I am a Python guy, but love having single executable tools.
Happy to hear about xh, thanks for mentioning it. I recently ran into a problem where HTTPie didn't support HTTP/2, so I had to fall back to curl. The ticket for HTTP/2 in HTTPie is still open https://github.com/httpie/httpie/issues/692
Happy to see that xh supports HTTP/2 out of the box.
Ahh, I believe you're right. "PUT" would have been a better example, in that case. But I suppose getting the cURL syntax wrong helps my point that I find the cURL syntax confusing.
Which isn't too far from your desired outcome (notably, without relying on argument position for meaning). Although, I guess the argument that "curl is already installed on almost every server", sorta gets moot because I imagine it will take a while for most distros to move to the latest curl that will support --json/--jp
It's a lot easier for a distro to update a default utility than to add a new one though. I suspect having updated curl would happen faster than adding httpie to the list of default utilities.
The exact opposite is more likely true, depending on the nature of the change. A new utility has no current usage so there are no in-the-wild backwards compatibility concerns. The system python on redhat based distros was stuck at 2 for a long time because some of the sysadmin utilities relied on it and all those deps needs to be vetted or converted to either a newer python version or their own shipped version of the runtime that didn't use the general purpose python install.
There's a big difference between a bump to the latest curl version and a jump between two major versions of a language runtime. The Python 2->3 transition took years and many distros kept both versions.
Most dependencies get updated much more quickly. It wouldn't even shock me if this change got picked up mid-cycle.
Unhappily RedHat won't. Heck, RedHat has gone well out of their way to backport updated TLS handshakes (1.2 at least) to their 2013 version (7.29.0) of curl.
Python is a huge outlier in this case. Very rarely do you have a default tool that can't be upgraded, and this case was only because Python is an interpreted language.
Curl is a command line tool. As long as they only add new functionality, there is very little that prevents an upgrade.
Especially singe HTTPie is a python package. curl exists even in plenty of embedded systems, in many Docker base-images, etc.; but scripting runtimes like Python generally don't.
Except if it's an enterprisey distro, it won't get updated. Specifically RHEL 7 ships 7.29.0 and cherry-picks features (TLS handshakes) to backport to their nine-year-old version.
I wish this were the case. Unfortunately for us grownups that run stable/LTS distros, non-security updates like these don't usually make it to us for like 5 years or something.
It depends. How long did to take for bash4-isms to get adopted? Sometimes the update time for more basic utilities, for all systems can take a long time. (Apple switching to zsh doesn't help here.)
We are rolling a brand-new mini-language that integrates really well with the existing request building syntax, but also features stuff like JSON type-safety and amazing error messages for basic syntax errors.
It will probably be post 3.0, since the underlying HTTP interface we use (https://pypi.org/project/requests) does not support HTTP/2. We are currently discussing how to migrate from that to something like httpx, without causing any change of user-visible behavior.
-s: if HTTPie disables progress bar by default, that's just a different design choice, the advantage is in the eye of the beholder
--data '{"user...: likewise, HTTPie's default to JSON is a design choice. I wouldn't say the default is superior
-H "Content-Type...: likewise, if HTTPie adds this header by default, thats just getting in my way when I don't want that header
-X POST: you don't need to specify that in cURL if using --data
HTTPie does not support multi-valued keys in query strings (sending several field[]= for example). It is very annoying and, for consistency, I would rather use cURL (instead of mixing syntax with HTTPie).
For TLS we use proxy listening on 127.0.0.1, e.g., stunnel, sslsplit, haproxy, etc. This way we only ever have to type a single address and port, i.e., 127.1 80, or short alias for the hostname, e.g., echo 127.0.0.1 p >> /etc/hosts.
> Getting JSON syntax right, error free, by hand, in a terminal, is not easy.
you are right and I wonder why shells haven't done anything to address this. Fish might, actually. colorization isn't really useful in aiding comprehension, but colorization is good at giving an indicator that there is a parse error somewhere.
I was wondering, "Why not pipe output to JQ" up until I read this:
> A not insignificant amount of people on stackoverflow etc have problems to
send correct JSON with curl and to get the quoting done right, as json uses
double-qoutes by itself and shells don't expand variables within single quotes
etc.
But I definitely didn't remember how to handle the closing paren and closing quote correctly, and I had to google for an example just now. So I'm not allowed to say this is easy to remember :)
Some of the replies say this is a layer violation: HTTP doesn't care about JSON so curl shouldn't either. But you have to add Content-type and Accept headers when working in JSON, which I personally often forget, so I think this does make sense.
This is great. When a new user uses Darklang, we want them to be able to make JSON API requests quickly and easily, and there aren't great client-side tools for that that you can expect users to have installed. giving them a big long curl command is no fun, but `curl --json 'the-body' would be amazing`
> But aren't there also several command line utilities which already support JSON.
There are command line utilities which consume, query, or format json.
But aside from e.g. httpie (which is essentially a competitor to Curl), which "several command-line utilities" make authoring JSON easy and convenient?
Because if you check point (3), the link, and the paragraph before it, this is entirely about sending valid JSON (ideally with the correct headers).
In fact the second section of the link in question literally states:
> # JSON response
> Not particular handling. Pipe output to jq or similar.
JSON is used a lot, really a lot, with CURL. It's ubiquitous on the web. cURLs intention is to support all this common URL stuff. Adding JSON seems a natural fit to me.
But curl has so many features already, it's odd to say now is the time to stop adding more. There is even Socks4 proxy support, does anyone even use that now or ever?
When dealing with support on someones docker image, for me it's far better to have this in one utility. Yea, you can write a command with the current version, but cutting it down to -jp will be much easier.
I feel like if you only want to make a single JSON request, a simple curl invocation with the JSON data in single quotes or in a file should be enough. And if you make many different JSON requests, you're probably much better off with one of the alternative tools.
Related to the second point, I really wish more people put more time into creating tools for their testers. Shell/Ruby/Python/Perl scripts that are custom-made for the specific service they're testing and provides better UI. So that instead of a sequence of curl invocations, logins, and error-prone copy-pasting, people could just:
Sounds like this idea is limited to the curl tool and wouldn't add anything to libcurl, which is great. I'd prefer libcurl leaving JSON to other libraries.
I use bash variables inside JSON with curl all the time, which leads to string escape screw ups. I know there are alternatives that make testing REST + JSON easier, but since our software uses libcurl in production I prefer to test with curl to keep things consistent.
To everyone saying "just use tool x for this": the advantage of curl is that is so widely available.
For your development laptop you can install anything you want but more often than not you need to log into a EC2 instance, a Docker container you name it.
Curl is often pre installed or very easy to install. I know it's usually not an up to date version but as time goes by you will be able to rely on this feature on pretty much any machine.
I can see this being useful, but I'm not looking forward to the list of command line options being even longer. The output of "curl --help" on my system is already 212 lines long.
I wish the curl command was split such that different protocols had different commands. I REALLY don't want to see a list of FTP specific command line options whenever I'm just trying to look up a lesser-used HTTP option.
That said, this is really a minor gripe compared to just how useful curl has been for me over the years.
I'm already well past the stage of using moar/micro/[rip]grep to scan through curl's manpage and find what I need.
OTOH, if you ignore using curl to GET resources to download, >90% of my curl usage is slinging json, and often involves interpolating strings and hence copy-pasting, so this feature would be immediately useful to me.
Curl is kind of the swiss army knife of the web so I don't think a long manpage is out of line.
187 comments
[ 0.22 ms ] story [ 206 ms ] thread``` echo { "my": "json" } | http post localhost/endpoint ```
(not serious)
Because cURL is so ubiquitous, whatever Daniel implements may become the de facto standard.
- The `--json` option only adds a content-type header, it doesn't alter the transmitted data at all.
- The `--jp` option has a bespoke format that's not part of the JSON spec, and which doesn't actually depend on a specific data model, it's just string manipulation.
Also, —jp is actually generating a JSON.
The problem is not with the JSON spec, the problem is when you are converting from one data model to another. Any program which claims to perfectly round-trip the JSON data-model should support arbitrarily long numbers, there's no ambiguity in the spec about that.
If you are only parsing JSON as a means to encode your own data-model, then there's no obligation to support arbitrary precision, but users should not expect to be able to round-trip arbitrary JSON data.
AFAICT, `--jp` doesn't do anything which would affect the length of supported numbers, even though it's generating JSON.
> JSON is agnostic about the semantics of numbers. […] JSON instead offers only the representation of numbers that humans use: a sequence of digits. […] That is enough to allow interchange.
But can you encode/decode an arbitrary integer or a float? Probably not!
* Float values like Infinity or NaN cannot be represented.
* JSON doesn't have separate representation for ints and floats. If an implementation decodes an integer value as a float, this might lose precision.
* JSON doesn't impose any size limits. A JSON number could validly describe a 1000-bit integer, but no reasonable implementation would be able to decode this.
The result is that sane programs – that don't want to be at the mercy of whatever JSON implementation processes the document – might encode large integers as strings. In particular, integers beyond JavaScript's Number.MAX_SAFE_INTEGER (2^53 - 1) should be considered unsafe in a JSON document.
Another result is that no real-world JSON representation can round-trip “correctly”: instead of treating numbers as “a sequence of digits” they might convert them to a float64, in which case a JSON → data model → JSON roundtrip might result in a different document. I would consider that to be a problem due to underspecification.
Jason.org requires white space for empty arrays and objects while RFC 8259 does not (and I often see [] and {} in the wild).
A lot of packages de fact break the spec in other ways, such as ppl blatting python maps out rather than converting them to JSON so that the keys are quoted as ‘foo’ rather than “foo”. I’ve complained about this when trying to parse the stuff only to receive the response “it works for me so you must have a bug” from the pythonistas. This has happened in multiple projects.
curl --insecure --cookie test_cookie='{"test":"bob"}' https://localhost:8081/
Host: localhost:8081
Accept: /
Cookie: test_cookie={"test":"bob"}
User-Agent: curl/7.74.0
curl --insecure --cookie 'test_cookie={"test":"bob"};test_cookie2={"test2":"bob"}' https://localhost:8081/
For example, here's a JSONy POST request with cURL:
curl -s -H "Content-Type: application/json" -X POST https://api.ctl.io/v2/authentication/login --data '{"username":"YOUR.USERNAME","password":"YOUR.PASSWORD"}'
Here's that same request with HTTPie:
http POST https://api.ctl.io/v2/authentication/login username=YOUR.USERNAME password=YOUR.PASSWORD
[0] https://github.com/ducaale/xh
I alias it to http so it's memorable and the commands make more sense though.
Happy to see that xh supports HTTP/2 out of the box.
Most dependencies get updated much more quickly. It wouldn't even shock me if this change got picked up mid-cycle.
Curl is a command line tool. As long as they only add new functionality, there is very little that prevents an upgrade.
There's a happy medium, and we're not in it.
[1] https://github.com/curl/curl/wiki/JSON#--jp-part
You might be in luck since Nested JSON support is going to be star feature of our upcoming release. Here is a sneak peek:
$ http --offline --print=B pie.dev/post \ search[type]=client \ search[stars]:=50000 \ search[platforms][]=Web \ search[platforms][]=Desktop \ search[platforms][]=Mobile \ search[platforms][]=CLI
{ "search": { "platforms": [ "Web", "Desktop", "Mobile", "CLI" ], "stars": 50000, "type": "client" } }
We are rolling a brand-new mini-language that integrates really well with the existing request building syntax, but also features stuff like JSON type-safety and amazing error messages for basic syntax errors.
[1] https://github.com/Orange-OpenSource/hurl
Awesome name.
I can hand another dev a curl statement without having to worry if they have the requisite software to reproduce the call.
Also Postman, Insomnia, Sentry, & Swagger all support ability export to curl.
You can use the `name==value` query parameter syntax [0]:
Or simply: [0]https://httpie.io/docs/cli/querystring-parametershttps POST api.ctl.io/v2/authentication/login username=YOUR.USERNAME password=YOUR.PASSWORD
... interacting with APIs using cURL?
> I don’t find curl —jp a=b to be better than directly sending a payload on a HTTP resource
Getting JSON syntax right, error free, by hand, in a terminal, is not easy. The current equivalent of an eventual `curl --jp a=b` is
that's a lot of opportunities for getting it wrong.you are right and I wonder why shells haven't done anything to address this. Fish might, actually. colorization isn't really useful in aiding comprehension, but colorization is good at giving an indicator that there is a parse error somewhere.
> A not insignificant amount of people on stackoverflow etc have problems to send correct JSON with curl and to get the quoting done right, as json uses double-qoutes by itself and shells don't expand variables within single quotes etc.
It's about sanitized inputs.
Less sanitized and more correctly formatted. Writing literal JSON by hand at the CLI is not fun.
But aren't there also several command line utilities which already support JSON.
Why cram new stuff into such an industry standard tool?
There are command line utilities which consume, query, or format json.
But aside from e.g. httpie (which is essentially a competitor to Curl), which "several command-line utilities" make authoring JSON easy and convenient?
Because if you check point (3), the link, and the paragraph before it, this is entirely about sending valid JSON (ideally with the correct headers).
In fact the second section of the link in question literally states:
> # JSON response
> Not particular handling. Pipe output to jq or similar.
Infact you can run postman on the command line
https://learning.postman.com/docs/running-collections/using-...
Or you can write your own script in Python to do this.
I really don't like adding new functionality to standardized tools. It's just risky.
Make an extension, call it CURLson, but don't cram it into curl.
https://github.com/curl/curl/wiki/JSON
Wiki is a weird format to use for a proposal.
As a user I would not expect curl to have json functionality.
And as a developer I would prefer to have one codebase deal with http and another one with json.
Related to the second point, I really wish more people put more time into creating tools for their testers. Shell/Ruby/Python/Perl scripts that are custom-made for the specific service they're testing and provides better UI. So that instead of a sequence of curl invocations, logins, and error-prone copy-pasting, people could just:
I use bash variables inside JSON with curl all the time, which leads to string escape screw ups. I know there are alternatives that make testing REST + JSON easier, but since our software uses libcurl in production I prefer to test with curl to keep things consistent.
[ 0 ] https://github.com/rs/curlie
Uh oh, this looks like it would have the problems of yaml. The data type changes based on the provided string.
For your development laptop you can install anything you want but more often than not you need to log into a EC2 instance, a Docker container you name it.
Curl is often pre installed or very easy to install. I know it's usually not an up to date version but as time goes by you will be able to rely on this feature on pretty much any machine.
I wish the curl command was split such that different protocols had different commands. I REALLY don't want to see a list of FTP specific command line options whenever I'm just trying to look up a lesser-used HTTP option.
That said, this is really a minor gripe compared to just how useful curl has been for me over the years.
OTOH, if you ignore using curl to GET resources to download, >90% of my curl usage is slinging json, and often involves interpolating strings and hence copy-pasting, so this feature would be immediately useful to me.
Curl is kind of the swiss army knife of the web so I don't think a long manpage is out of line.