Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Post a number as a JSON #2613

Closed
slaout opened this issue Dec 19, 2019 · 7 comments · Fixed by #4020
Closed

Post a number as a JSON #2613

slaout opened this issue Dec 19, 2019 · 7 comments · Fixed by #4020

Comments

@slaout
Copy link

slaout commented Dec 19, 2019

Hello,

When posting an object or array with axios, axios automatically sets the request content type to 'application/json', which is the common use case for APIs nowadays.

According to the README, "By default, axios serializes JavaScript objects to JSON.".

And according to the official JSON specification's right sidebar, a valid JSON stream can also be a primitive value (null, a boolean, a number or a string).

But axios.post(url, 42) will not send the request as content-type='application/json', but as 'application/x-www-form-urlencoded'.

For now, in our project, we are setting the content-type as 'application/json' manually when sending numbers or other primitives, and our server is able to parse this JSON without any explicit declaration.

Wouldn't it be better for axios to do this by default, as numbers are valid JSON, and axios states that it sends JSON by default?

I didn't file this as a feature request or a bug, as it may be intentional.
Or if it is not intentional, it may be difficult to change that behavior, as it would introduce a breaking change.

Best regards,
Sébastien.

@yasuf
Copy link
Collaborator

yasuf commented Dec 20, 2019

that's part of the default transformRequest, looks like it was on purpose, set the content-type as application/x-www-form-urlencoded, from our defaults.js. It's weird as you mention that it's set to form-urlencoded, if we make the change it would have to be on the 1.0.0 release, since this is a breaking change for some use cases. Doesn't seem urgent unless you can describe a use case for this, we have a few things to fix before this one. Thanks for looking into this!

@McNetic
Copy link

McNetic commented Jan 15, 2020

There are certainly use cases for this; it's perfectly valid to send primitives as JSON body. I just encountered the same problem.

As for the urgency; it is not that urgent as there is a workaround in available and it is a breaking change; however, according to the docs, axios should (by default) encode objects to JSON. This is obviously broken for primitive objects, and leads to unexpected behavior.

In fact, the concept to switch to application/x-www-form-urlencoded by simply using qs.stringify() is logically flawed, as it contradicts the default encoding to JSON for strings. I think this is a design flaw that should be adressed prior to releasing a 1.0.0.

@slaout
Copy link
Author

slaout commented Jan 22, 2020

I cannot find any blocking use case.

If you fix it for 1.0, here are more toughts, as we ran accross an interesting edge-case:

According to json.org, a valid JSON payload is one of these seven values:

  • object => { example: true }
  • array => [ 42, 43 ]
  • string => "foo"
  • number => -42
  • "true" => true
  • "false" => false
  • "null" => null

We should be able to send -42 as application/json, like said earlier.

The edge case is: when sending a string, we must send the string with begin and end double-quotes.
The request body must be "foo", and not foo.
Currently, axios sends foo, even when setting MIME type application/json, which also contradicts the JSON specification (foo should only be sent when using text/* MIME types).

On one hand, it should be fixed in axios.
On the other hand, our Java/Spring server endpoint is declared as:

@PostMapping("/bar")
public void bar(@requestbody String foo) { ... }

A String object is just expecting to parse a string content, and not a JSON-string: the server is NOT expecting to parse any begin and end double-quotes.
So, the current "non-complient" working of axios currently works for us, thanksfully, but only by chance.
If axios is "fixed", all backends must be aware to expect a JSON containing a string, and not expect only the content of a string.

What do you think about strings?

@blade-sensei
Copy link

blade-sensei commented Mar 18, 2021

Sorry. I didn't get it. My aim is to send raw data - number type in the body (in my case) I want to send a number, without the brackets for sure.

Its seems that changing the content type to 'application/x-www-form-urlencoded ' and using qs stringify it should work ?
or we also need a hack using AxiosTransformer ?
I tried both solutions, combined and separetely ...
let me show a quick code

.put(url, stringify(40)) -> set data to " " (void string) ..
// I also used a request interceptor 

const inte = (config: axios.AxiosRequestConfig) => {
  const trans: axios.AxiosTransformer = data => { 
    return stringify(40);
  };
 config.transformRequest = trans;
 return config;
};

@slaout
Copy link
Author

slaout commented Mar 18, 2021

No need for a transformer: just use this code:

axios.post(url, 42, {
  headers: { "Content-type": "application/json" },
});

Here, to send the number 42.
For a string, I think I remember Axios does not enclose it in quotes (to make it a real JSON value, and not just a text/plain string): but for our case, the backend server agreed to use the whole string (it would have included the quotes in the parsed value otherwise). This is one edge case of this primitive-JSON-value solution to be aware of. We since tend to prefer real JSON objects as request bodies.

@blade-sensei
Copy link

When you use number as body, you have this error.
data -> set to undefined..
well i will try with another http client then 😕

Capture d’écran 2021-03-18 à 11 33 33

can help -> https://npmdoc.github.io/node-npmdoc-axios/build/apidoc.html#apidoc.element.axios.defaults.adapter

jasonsaayman pushed a commit that referenced this issue Apr 19, 2021
…be passed directly as payload for encoding to JSON #2613, #61, #907 (#3688)

* Draft

* Added support for primitive types to be converted to JSON if the request Content-Type is 'application/json';
Added throwing SyntaxError if JSON parsing failed and responseType is json;
Added transitional option object;
Added options validator to assert transitional options;
Added transitional option `silentJSONParsing= true` for backward compatibility;
Updated README.md;
Updated typings;

* Fixed isOlderVersion helper;
Fixed typo;
Added validator.spec.js;

* Added forcedJSONParsing transitional option #2791

* `transformData` is now called in the default configuration context if the function context is not specified (for tests compatibility);

* Added `transitional.clarifyTimeoutError` to throw ETIMEDOUT error instead of generic ECONNABORTED on request timeouts;
Added support of onloadend handler if available instead of onreadystatechange;
Added xhr timeout test;
Fixed potential bug of xhr adapter with proper handling timeouts&errors (FakeXMLHTTPRequest failed to handle timeouts);
@jasonsaayman
Copy link
Member

Fixed please see #3688

mbargiel pushed a commit to mbargiel/axios that referenced this issue Jan 27, 2022
…be passed directly as payload for encoding to JSON axios#2613, axios#61, axios#907 (axios#3688)

* Draft

* Added support for primitive types to be converted to JSON if the request Content-Type is 'application/json';
Added throwing SyntaxError if JSON parsing failed and responseType is json;
Added transitional option object;
Added options validator to assert transitional options;
Added transitional option `silentJSONParsing= true` for backward compatibility;
Updated README.md;
Updated typings;

* Fixed isOlderVersion helper;
Fixed typo;
Added validator.spec.js;

* Added forcedJSONParsing transitional option axios#2791

* `transformData` is now called in the default configuration context if the function context is not specified (for tests compatibility);

* Added `transitional.clarifyTimeoutError` to throw ETIMEDOUT error instead of generic ECONNABORTED on request timeouts;
Added support of onloadend handler if available instead of onreadystatechange;
Added xhr timeout test;
Fixed potential bug of xhr adapter with proper handling timeouts&errors (FakeXMLHTTPRequest failed to handle timeouts);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants