I have a fair amount of experience building web apps with React but want to learn Elm. I've been banging my head against an HTTP request issue for a couple days now.
I'm running an Elm app at localhost:8080 and my supporting API at localhost:8081. Whenever I make an HTTP request (I've tried both GET and POST requests) I get a NetworkError. I've been looking into Elm JSON decoders and think it's possible that this is where my problem exists but I've tried sending simple strings from my server and using the Decode.string decoder in my Elm app and I still get the NetworkError.
Here's what my code looks like currently:
Commands.elm
module Commands exposing (..)
import Models exposing (..)
import Msg exposing (..)
import Http
import Json.Decode as Decode
import Json.Encode as Encode
createTempUser : Model -> Cmd Msg
createTempUser model =
let
tempUserBody =
[ ( "firstname", Encode.string model.firstname )
, ( "lastname", Encode.string model.lastname )
, ( "phone", Encode.string model.phone )
]
|> Encode.object
|> Http.jsonBody
url =
myAPIUrl ++ "/endpoint"
contentType = Http.header "Content-type" "text/plain"
post =
Http.request
{ method = "POST"
, headers = [contentType]
, url = url
, body = tempUserBody
, expect = Http.expectJson decodeApiResponse
, timeout = Nothing
, withCredentials = False
}
in
Http.send Msg.TempUserCreated post
decodeApiResponse : Decode.Decoder ApiResponse
decodeApiResponse =
Decode.map4 ApiResponse
(Decode.at ["status"] Decode.int)
(Decode.at ["message"] Decode.string)
(Decode.at ["created"] Decode.int)
(Decode.at ["error"] Decode.string)
myAPIUrl : String
myAPIUrl = "http://localhost:8081"
Models.elm
module Models exposing (..)
type alias ApiResponse =
{ status: Int
, message: String
, created: Int
, error: String
}
Msg.elm
module Msg exposing (..)
import Navigation exposing (Location)
import Models exposing (..)
import Http
type Msg
= ChangeLocation String
| OnLocationChange Location
| CreateTemporaryUser
| TempUserCreated ( Result Http.Error ApiResponse )
Update.elm
module Update exposing (..)
import Msg exposing (Msg)
import Models exposing (..)
import Routing exposing (..)
import Commands exposing (..)
import Navigation
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
Msg.ChangeLocation path ->
( { model | changes = model.changes + 1 }, Navigation.newUrl path )
Msg.OnLocationChange location ->
( { model | error = "", route = parseLocation(location) }, Cmd.none )
Msg.CreateTemporaryUser ->
( model, createTempUser model )
Msg.TempUserCreated (Ok res) ->
update (Msg.ChangeLocation signupCodePath) { model | httpResponse = toString(res) }
Msg.TempUserCreated (Err err) ->
( { model | error = toString(err) }, Cmd.none )
Chrome's Network devtools show the response as this
{"status":200,"message":"Successfully inserted temporary
user","created":1518739596447,"error":""}
I think this may be all the relevant code but if there's more you need to see I'll make an update including the requested code. I'll admit that I don't have a full understanding of the Elm Json.Decode library but I was under the impression that if this was where the issue was I would get an UnexpectedPayload Error that included additional context.
@Sidney and @SimonH,
Thank you for looking into this for me, I feel bad because this wasn't an Elm issue after all.
The solution ended up using a CORS middleware on the server to add the 'Access-Control-Allow-Origin' header. The server was still responding with a 200 status and even included the entire successful response body but this resulted in a failure in Elm's Http Result.
Thank you again for your time and thought!
For a quick solution while developing you can use the CORS everywhere extension for firefox and add the following to your whitelist in the extension preferences:
/^https?...localhost:8888\//i
For chrome you can probably use this extension
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With