24

I have to interact with an API that takes parameters from the body of a GET request. I know this might not be the best idea, but it is the way the API was built.

When I try building a query with XMLHttpRequest, it looks like the payload is simply not sent. You can run this and look in the network tab; the request is sent, but there is no body (tested in latest Chrome and Firefox):

const data = {
  foo: {
    bar: [1, 2, 3]
  }
}
const xhr = new XMLHttpRequest()
xhr.open('GET', 'https://my-json-server.typicode.com/typicode/demo/posts')
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8')
xhr.send(JSON.stringify(data))

Libraries such as axios are built on XMLHttpRequest, so they are not working either...

Is there any way to achieve this in JavaScript?

Ivar
  • 6,138
  • 12
  • 49
  • 61
Andrei Savin
  • 2,350
  • 4
  • 26
  • 40

1 Answers1

27

No, it is not possible to send a GET request with a body in JavaScript.

it looks like the payload is simply not sent

That is correct. This is defined in the specification:

The send(body) method must run these steps:

...

  1. If the request method is GET or HEAD, set body to null.

Also a request via the Fetch API does not allow a body. From the specification:

  1. If either init["body"] exists and is non-null or inputBody is non-null, and request’s method is GET or HEAD, then throw a TypeError.

The best would be if the API could be fixed.

If that is not possible, you could add a server-side script that you can use as a proxy that passes the requests to the API. You can than call this script with a GET request with the data in the URL instead of the body or using a POST request with a body. This script then can make the GET request with a body (as long as the chosen language supports it).

Ivar
  • 6,138
  • 12
  • 49
  • 61
  • Thank you for the explanation. A server-side proxy is a great suggestion. – Andrei Savin Feb 21 '19 at 16:37
  • 35
    Not to anger the HTTP gods but, for the record, in 2019, this spec seems dumb. I often find myself wanting to send some payload along with a request. It's possible that the payload is very large so I don't want it to be in the URL. Semantically, I'm conducting a GET request ("Give me something. Here are details of what I want. Don't create anything.") and this spec requires me to make it a POST/PUT request or use some other hackery. – John Carrell Dec 18 '19 at 16:10
  • 2
    @JohnCarrell The HTTP spec actually does not forbid it: "A payload within a GET request message has no defined semantics; sending a payload body on a GET request might cause some existing implementations to reject the request." https://tools.ietf.org/html/rfc7231#section-4.3.1 – Sergey May 06 '20 at 14:56
  • @Sergey It has (AFAIK) always been _allowed_ but in earlier versions of the specs [it "_SHOULD_" be ignored](https://stackoverflow.com/a/983458/479156). – Ivar May 06 '20 at 15:09
  • 2
    I have argued that these frameworks are broken for over a decade. REST > HTTP. If I want to Represent that I want to GET some data given certain parameters, and those parameters are either not appropriate for a Querystring either because of serialization simplicity, size, charset, security, or any other reason, I should be able to pass those parameters with a Body to a `GET` endpoint. It is not RESTfully correct to request data (even if based on parameters) by calling `PUT` or `POST`. (Not that you can't expect those to return data after their respective add/update action(s)). – Suamere Oct 10 '20 at 23:14
  • 3
    `The best would be if the API could be fixed.` - The API isn't broken. The frameworks consuming it are. – Suamere Oct 10 '20 at 23:16
  • 1
    The trouble using the body of a GET request to describe a query is that, for historical reasons, the body is not considered by caches. A GET request describing a query then "poisons" any caches the request flowed through such that subsequent GET attempts, with a different body, will return the original result. The observed behaviour of the API then becomes dependent on the network topology. It's a defect waiting in the wings. – eisenpony Feb 10 '22 at 01:59
  • Compare to a POST, which cannot be cached, made to a /query endpoint that "creates" a new query. Best practice might be to return a new address and require a GET, but many APIs will just return the result in anticipation. – eisenpony Feb 10 '22 at 02:03