ladjs / superagent

Ajax for Node.js and browsers (JS HTTP client). Maintained for @forwardemail, @ladjs, @spamscanner, @breejs, @cabinjs, and @lassjs.
https://ladjs.github.io/superagent/
MIT License
16.58k stars 1.33k forks source link

Is it possible to send a boolean or number via send()? #1637

Closed benfrancis closed 2 years ago

benfrancis commented 2 years ago

I'm using superagent in an integration test via chai-http and need to send a JSON boolean in the body of a PUT request , without an object wrapper (i.e. true as opposed to {x:'true'}).

chai
    .request(server)
    .put(`/foo`)
    .send(true);

In older versions of JSON a string, number or boolean on its own wouldn't be valid JSON, but in recent versions it is.

The integration test is written in TypeScript and the types for superagent provided by DefinitelyTyped define the data argument of the send() method to be string | object. That means that a number or boolean is not allowed.

I understand that the maintainer of this package doesn't support TypeScript, which is fine, but I'd like to understand whether sending a boolean or number value on its own is supported by superagent. If it is then I will file an issue against the DefinitelyTyped repo to update the type definition so that it will be allowed.

benfrancis commented 2 years ago

Reading through the source I see that there are no tests which send() a boolean or number, and it looks like only objects and arrays are accepted as a valid JSON text by send().

Please note that since RFC 7158 in 2013, strings, numbers and the literal values true, false and null have been a valid "JSON text" on their own.

See https://datatracker.ietf.org/doc/html/rfc8259#section-2 :

A JSON text is a serialized value. Note that certain previous specifications of JSON constrained a JSON text to be an object or an array. Implementations that generate only objects or arrays where a JSON text is called for will be interoperable in the sense that all implementations will accept these as conforming JSON texts.

Is there a way to work around this, or does this need to be a feature request?

benfrancis commented 2 years ago

Ah, I think I figured out a workaround.

It isn't well documented, but from reading more of the source it looks like you can explicitly tell superagent that a request body is JSON, then provide it a string to parse as JSON rather than an object. That will satisfy TypeScript and bypass superagent's automatic content type detection. Phew.

  await superagent
    .request(server)
    .put(`/foo`)
    .type('json')
    .send(JSON.stringify(true));
}