uben
uben

Reputation: 1491

In Elm, a GET request can't have a body, or is it?

Http.request seems to ignore body when the method is GET

init : () -> ( Model, Cmd Msg )
init _ =
    ( Loading
    , Http.request
        { method = "GET"
        , headers = []
        , url = "http://127.0.0.1"
        , body = Http.stringBody "text/plain" "Hello World!"
        , expect = Http.expectWhatever Sent
        , timeout = Nothing
        , tracker = Nothing
        }
    )

The sent request has no body (when inspected with browser development tool). ๐Ÿค”

init : () -> ( Model, Cmd Msg )
init _ =
    ( Loading
    , Http.request
        { method = "POST" {- CHANGED TO POST -}
        , headers = []
        , url = "http://127.0.0.1"
        , body = Http.stringBody "text/plain" "Hello World!"
        , expect = Http.expectWhatever Sent
        , timeout = Nothing
        , tracker = Nothing
        }
    )

But when the method is changed to "POST", it works ! The body contains "Hello World!". ๐Ÿคจ

The API I try to communicate with requires an application/json body in a GET request. Help me ๐Ÿ˜ญ !

PS: Here is what the documentations says:

emptyBody : Body

Create an empty body for your Request. This is useful for GET requests and POST requests where you are not sending any data.

Which is not clear, because it can be interpreted in two different ways:

This is useful for GET requests and { POST requests where you are not sending any data } .

Or:

This is useful for { GET requests and POST requests } where you are not sending any data.

Upvotes: 3

Views: 189

Answers (2)

8n8
8n8

Reputation: 1382

Elm actually does add the body to the request, but the browser doesn't send it.

To see this, compile this Elm program:

module Main exposing (main)

import Platform
import Http

main =
    Platform.worker
        { init = \() -> ((), Http.request
            { method = "GET"
            , headers = []
            , url = "https://catfact.ninja/fact"
            , body = Http.stringBody "text/plain" "hi"
            , expect = Http.expectWhatever (\_ -> ())
            , timeout = Nothing
            , tracker = Nothing
            })
        , update = \() () -> ((), Cmd.none)
        , subscriptions = \() -> Sub.none
        }

without optimisation flags to get an index.html file. Part of this file is:

        var xhr = new XMLHttpRequest();
        xhr.addEventListener('error', function() { done($elm$http$Http$NetworkError_); });
        xhr.addEventListener('timeout', function() { done($elm$http$Http$Timeout_); });
        xhr.addEventListener('load', function() { done(_Http_toResponse(request.expect.b, xhr)); });
        $elm$core$Maybe$isJust(request.tracker) && _Http_track(router, xhr, request.tracker.a);

        try {
            xhr.open(request.method, request.url, true);
        } catch (e) {
            return done($elm$http$Http$BadUrl_(request.url));
        }

        _Http_configureRequest(xhr, request);

        request.body.a && xhr.setRequestHeader('Content-Type', request.body.a);
        xhr.send(request.body.b);

If you open this file in the browser and step through this part of it in the debugger, you can see that Elm actually does put the given body "hi" in the request.body.b value, passed to xhr.send.

But if you then look in the Network tab in the browser console, you can see that the request doesn't contain a body.

So this is the browser stripping out the body with GET requests, not Elm.

Upvotes: 4

glennsl
glennsl

Reputation: 29106

According to the HTTP specification, GET should not have a body. See for example its description on MDN, which says:

Note: Sending body/payload in a GET request may cause some existing implementations to reject the request โ€” while not prohibited by the specification, the semantics are undefined. It is better to just avoid sending payloads in GET requests.

Upvotes: 7

Related Questions