Git Product home page Git Product logo

http's Introduction

HTTP

Make HTTP requests in Elm. Talk to servers.

I very highly recommend reading through The Official Guide to understand how to use this package!

Examples

Here are some commands you might create to send HTTP requests with this package:

import Http
import Json.Decode as D

type Msg
  = GotBook (Result Http.Error String)
  | GotItems (Result Http.Error (List String))

getBook : Cmd Msg
getBook =
  Http.get
    { url = "https://elm-lang.org/assets/public-opinion.txt"
    , expect = Http.expectString GotBook
    }

fetchItems : Cmd Msg
fetchItems =
  Http.post
    { url = "https://example.com/items.json"
    , body = Http.emptyBody
    , expect = Http.expectJson GotItems (D.list (D.field "name" D.string))
    }

But again, to really understand what is going on here, read through The Official Guide. It has sections describing how HTTP works and how to use it with JSON data. Reading through will take less time overall than trying to figure everything out by trial and error!

http's People

Contributors

eeue56 avatar evancz avatar gdamjan avatar marocchino avatar rl-king avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

http's Issues

Expect and the "Accept:" header

Motivation

Our Rails back-end uses the Accept HTTP request header to determine what to send back to clients. It defaults to sending HTML unless told otherwise.

When we make a HTTP request that expects a JSON response, if the user's authentication session has expired, here's what happens:

  • Rails detects this and sends a 401 response
  • Because it did not see an Accept header, it defaults to sending back HTML - a fully rendered "You need to log in" HTML page
  • Because the Elm request expected a JSON response, it tries to run a JSON decoder on this HTML, which of course blows up because HTML is not JSON

In the NoRedInk/elm-rails package, we explicitly set the Accept header on all JSON requests to application/json, which prevents this.

However, sometimes we use other packages that do HTTP, and if they do not set this header, and we don't remember to override it to set it properly, we end up with production bugs when users are not authenticated.

Proposal

Http.Body stores a String for what Content-Type header should be set in the request. Http.jsonBody uses this to set Content-Type: application/json on any request that has a JSON body.

Http.Expect could similarly store a String for what Accept header should be set in the request. Http.expectJson could use this to set Accept: application/json on any request that expects a JSON response.

This would address this problem for anyone using elm/http with Rails or other servers that use the Accept header to make decisions about what format to use for responses.

Must `Request` be an opaque type?

I was looking at my package rgrempel/elm-http-decorators to see what needed to be updated for the new version of http. Two of the functions are now obsolete, because http now itself does what they did. The third function addCacheBuster, needs some changes. Here's a link to the implementation, for reference:

https://github.com/rgrempel/elm-http-decorators/blob/1.0.2/src/Http/Decorators.elm#L64-L93

Basically, it takes the send function from Http and wraps it so that a cache-busting parameter gets added to the URL. As currently implemented, this involves taking a Request as a parameter, extracting the URL, constructing a new Request with a modified URL, and then passing it along to the "real" send function.

The difficulty, of course, is that Request is now an opaque type. Thus, if I ask for a Request in my function signature, I can't extract the URL.

The obvious workaround, of course, is to not ask for a Request as a parameter. Instead, I can ask for the various things that make up a request (I suppose I would more or less copy the structure of RawRequest), and then use that to construct a request (by passing it to the request function, after making the necessary modifications).

That would clearly work, but it would be awkward.

Of course, the elegance (or lack thereof) of my little function makes no difference in the big scheme of things, and would be no good reason (by itself) to change anything. However, I'm wondering whether there might be other use cases that would benefit if Request were less opaque. At the moment, given a Request, there is nothing you can do to "analyze" it. It seems possible that there would be other useful convenience functions of the form Request a -> Request a, which the opacity of Request makes, well, awkward.

Of course, I understand that there are sometimes very good reasons to have opaque types.

Are Task requests rare?

(I don't know this is the right place to ask this question. Please redirect to discourse if needed.)

The doc comment on Http.task says:

Just like request, but it creates a Task. This makes it possible to pair your HTTP request with Time.now if you need timestamps for some reason. This should be quite rare.

However, I don't get why using tasks should be rare. (Or, does "This" point the use of Time.now?) So, some notes about the thoughts behind it would help.

Context

We have many API requests in the codebase at work. Like this.

module Api.Request exposing (..)

getFoo : String -> Task Http.Error Foo
postFoo : Foo -> Task Http.Error Foo
...

The reason of having Task based API is that we often have to combine requests.

  • Task.map2 or Task3 to combine multiple requests to initiate each page
    • Ideally, this should be done in parallel.
  • Task.andThen to chain requests
    • For example, getFoo fooId |> Task.andThen (\foo -> getBar foo.barId)

All the functions return Task by default so we can avoid calling toTask so often (which happened when I used Request based API in 1.0.0).

I guess the answer of my question is something like:

  • HTTP requests should not be sent very frequently (chatty API is an anti pattern)
  • UI should show each data respectively (object-based UI design)
  • Server should give optimized API for each page

They might be true, but our development cannot always do things right. Seeing labels like "should not" or "rare" is a kind of fear when we are deeply depending on the feature, because it sometimes means "this feature will be removed soon".

Edit:
Another context: I'm writing an explanation of Task in my book and it says "Task is useful to chain HTTP requests" with some examples.

SSCCE - Arraybuffer / Blob / XHR in IE

Related to #56 . Here is a small repro for generating the InvalidStateError in IE (I'm testing against IE11 latest update).

This code downloads bytes from an xhr using expectBytes response. Under the covers, the xhr generates an array buffer that is passed to new Blob in Kernel code at File.Download.bytes.

Here is the code with the error:

import Browser
import Bytes exposing (Bytes)
import Bytes.Decode as Decode
import File.Download as Download
import Html exposing (..)
import Html.Events exposing (onClick)
import Http exposing (Error(..), Response(..))

type Msg
    = Download
    | DownloadComplete (Result Http.Error Bytes)

type alias Model =
    Maybe Bytes

resolve : Response Bytes -> Result Error Bytes
resolve response =
    case response of
        BadUrl_ url ->
            Err (BadUrl url)

        Timeout_ ->
            Err Timeout

        NetworkError_ ->
            Err NetworkError

        BadStatus_ metadata _ ->
            Err (BadStatus metadata.statusCode)

        GoodStatus_ _ body ->
            Ok body

downloadBytes : Cmd Msg
downloadBytes =
    Http.get
        { url = "https://media.giphy.com/media/dUQakUPAZw1EY/200w_d.gif"
        , expect = Http.expectBytesResponse DownloadComplete resolve
        }

init : {} -> ( Model, Cmd Msg )
init _ =
    ( Nothing, downloadBytes )

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        Download ->
            Maybe.map (\bytes -> ( model, Download.bytes "gracias.gif" "image/gif" bytes )) model
                |> Maybe.withDefault ( model, Cmd.none )

        DownloadComplete result ->
            case result of
                Ok bytes ->
                    ( Just bytes, Cmd.none )

                Err e ->
                    ( model, Cmd.none )

view : Model -> Html Msg
view model =
    Maybe.map (always (button [ onClick Download ] [ text "download bytes" ])) model
        |> Maybe.withDefault (text "Downloading file.")

main : Program {} Model Msg
main =
    Browser.element
        { init = init
        , update = update
        , view = view
        , subscriptions = always Sub.none
        }

Error screenshot.

screen shot 2019-02-12 at 9 30 17 am

`Http.post` can't handle responses with empty bodies

... because it takes a Json.Decode.Decoder and - correctly - I can't write such a decoder that will succeed on an empty string.

One can use Http.request and eg expect = Http.expectStringResponse (\_ -> Ok ()).

However I'd suggest that it's not unusual for a POST to return an empty body, and so it would be a good thing if the convenience function could be made convenient for that case.

(Same would be true of the put and delete methods proposed in #9).

What do you think?

Headers now lowercase in Chrome 60

With Chrome 60, I've been bitten by the fact that all headers names are now lowercase. This means
doing:

Dict.get "Content-Type" response.headers

does not work reliably anymore. It seems to be a trend that will be implemented in the other browsers
because of HTTP/2.

To make sure it works on all browsers, does adding a call to .toLowerCase() in Native/Http.js parseHeaders() function would be a good idea? It would certainly break applications but this is
already the case with the new Chrome 60 anyway.

No docs on CORS

There's no examples on how to fix CORS issues or examples of headers generally. The docs have one example and then point to a few different sources with more examples, but the only place that has a complete API listing is the previous (deprecated) elm-http package. It would be nice if there were a full API listing for this package. As a new entrant to the language I have little idea on what syntax to use - a missing comma or semicolon can mean the difference between the package working or not of course.

For `PUT` requests, `Response.url` is `undefined` for IE 11 and Edge <= 13

We saw this in production against
IE 11, Edge 12, Edge 13, seems fixed on Edge 14
on
Windows 7, 8.1, and Windows 10,

Here's a test case:
https://github.com/michaelglass/repro-ie-put-bug/

The result of the Debug.log in the test case above yields:

{ status = { code = 200, message = "" }
, headers = Dict.fromList [("\ncontent-type","application/json; charset=utf-8")]
, url = <internal structure>
, body = "{\"updatedAt\":\"2018-04-05T08:48:49.587Z\"}" 
}

grabbing the output of the raw xhr request from toResponse(xhr) yields:

{
   0: <Unable to get property 'message' of undefined or null reference>,
   __proto__: { },
   DONE: 4,
   HEADERS_RECEIVED: 2,
   LOADING: 3,
   msCaching: "auto",
   onabort: null,
   onerror: null,
   onload: null,
   onloadend: null,
   onloadstart: null,
   onprogress: null,
   onreadystatechange: null,
   ontimeout: null,
   OPENED: 1,
   readyState: 4,
   response: "{"updatedAt":"2018-04-05T08:51:32.200Z"}",
   responseBody: <String expected>,
   responseText: "{"updatedAt":"2018-04-05T08:51:32.200Z"}",
   responseType: "text"
}

I couldn't get Ellie to work with IE11 but the bug reproduces fine from elm reactor.

(tagging @stoeffel as he helped here)

Feature request: Type alias for the argument to Http.request

Can we have a type alias for the argument going to Http.request?

Current:

request : { method : String, headers : List Header, url : String, body : Body, expect : Expect a, timeout : Maybe Time, withCredentials : Bool } -> Request a

Requested:

-- Sugestions for better namings are welcome
type alias Configuration =
    { method : String
    , headers : List Header
    , url : String
    , body : Body
    , expect : Expect a
    , timeout : Maybe Time
    , withCredentials : Bool
    }

request : Configuration -> Request a

Because now i have two choices:

  1. Put the whole record in all the functions that want to receive and return that record.

  2. Make an alias myself. But the issue is that i have one request handlers that use that. And also multiple interceptors that use that record. Creating the alias in the handler gives me circular dependencies. So the only option is to move the type alias into an other file where they both depend on.

I think it does make sense to create the alias in this package

Failed xhr.open gives BadUrl, but may be caused by security restrictions

I wrote a little Elm (0.18.0) app that plays with the giphy.com api. It works within the browser. But while moving it to cordova (android) I received the message "badUrl: ..." for a good url.
I inserted in https://github.com/elm-lang/http/blob/master/src/Native/Http.js at
try { xhr.open(request.method, request.url, true); } catch (e) { return callback(_elm_lang$core$Native_Scheduler.fail({ ctor: 'BadUrl', _0: request.url })); }
an alert( e );
This unveiled the real cause. In my case it was a problem with the "Content Security Police".

I think "badUrl" is too generic and can be misleading. Is there any good way to incorporate the "real" cause?

Http.Progress not working when the content is gzipped

If the content is not gzipped, the progress bar seems to work fine on all the browsers I have tested so far. But if the server sends it as gzip, only Firefox works¹.

This appears to be a XHR spec issue, for what I understood, chrome and others browsers does not implement tracking progress when the content is gzipped because the specs are unclear whether the value of the content-length header should be after-decoding or before-decoding.

Tests can be done in this link: https://pablohirafuji.github.io/elm-http-progress-example/

Http.request's weird behavior

Http.request
            { method = verb
            , headers =
                [ (header "Accept" "application/json")
                , (header "Content-Type" "application/json")
                ]
            , url = Config.endpointUrl
            , body = Http.jsonBody <| params
            , expect = expectJson decoder
            , timeout = Nothing
            , withCredentials = False
            }

When I have "application/json" for both "Accept" and "Content-Type" headers. The request I got has two "application/json" for Content-Type header

encodeURIComponent can throw errors

I ran into a runtime error when I tried to include 🍝�👳 in URL. It was my mistake but I think it should be BadUrl error in this case.

Uncaught URIError: URI malformed
    at encodeURIComponent (<anonymous>)
    at encodeUri (index.js:10938)
    at Function.func (index.js:22317)
    at A2 (index.js:92)
    at search (index.js:38236)
    at index.js:13466
    at index.js:16
    at A2 (index.js:93)
    at Function.func (index.js:13533)
    at A4 (index.js:104)

https://github.com/elm-lang/http/blob/99c00a2dac21dda1d4954515c79e6f28e431573f/src/Native/Http.js#L8

  • OS: Windows 7
  • Browser: Chrome 56
  • Elm: 0.18.0
  • elm-lang/http: 1.0.0

XMLHttpRequest `response` property doesn't exist in IE9

The response property as used here:

https://github.com/elm-lang/http/blob/master/src/Native/Http.js#L154

was only added to IE10 according to https://msdn.microsoft.com/en-us/library/hh872881(v=vs.85).aspx

This results in a "Given an invalid JSON" error, or "This is not valid JSON!" in master at

https://github.com/elm-lang/core/blob/master/src/Elm/Kernel/Json.js#L149

as string will be undefined.

I'm not sure about the correct solution, especially with streaming or large payloads, but I've confirmed that in my simple case of a small JSON response, manually changing the generated JS to use responseText makes it work in IE9.

Edit: I should add that this is tested in IE11 in IE9 "document mode".

No longer possible to tunnel binary data as text

With evancz/elm-http I was able to access binary data without it being mangled by means of the overrideMimeType hack - SSCCE here. I no longer seem to be able to do this in elm 0.18 - failing SSCCE here. In each case I am trying to load this small MIDI file, served up with Apache. I am using 64-bit Linux and the latest Chromium browser.

These two examples give different results when displaying the (decoded) data. They differ at the first truly binary value which is greater than FF (in this example, byte 23).

In particular, this line of javascript has now vanished in the implementation of http:

// ask for a specific MIME type for the response
	if (settings.desiredResponseType.ctor === 'Just')
	{
		req.overrideMimeType(settings.desiredResponseType._0);
	}

'GET' requests don't seem to include body

I am integrating an application with ElasticSearch, and the search query API relies on sending the query in a JSON body attached to a get request (see https://www.elastic.co/guide/en/elasticsearch/reference/current/query-filter-context.html for some examples).

I have been able to query the API this way from the command line using curl, and from Ruby using RestClient. When I try to do the same with Elm http the payload seems to get lost (I have checked the http request in Wireshark and compared it to the same request sent via Ruby).

The code used to set up the get request is shown below. The same code works as expected when I change the GET to POST, so I have a short term work around. Is dropping the payload on a GET request intended behaviour, or am I doing something wrong?

Http.request
{ method = "GET"
, headers = [ Http.header "Accept" "application/json" ]
, url = "https://(url here)/_search"
, body = Http.jsonBody jsonBodyValue
, expect = Http.expectJson SetProducts elasticSearchProductListDecoder
, timeout = Nothing
, tracker = Nothing
}

The send functions and returns a response, but the contents of the response is the same as when there is intentionally no query payload.

Runtime exception when empty header name is given

Steps to reproduce:

  • Put header "" "something" in headers list for any Http request
module Main exposing (main)

import Browser
import Html exposing (Html, button, div, text)
import Html.Events exposing (onClick)
import Http


type alias Model =
    {}


init : () -> ( Model, Cmd Msg )
init _ =
    ( {}
    , Http.request
        { method = "GET"
        , headers = [ Http.header "" "something" ]
        , url = "https://www.example.com"
        , body = Http.emptyBody
        , expect = Http.expectWhatever (always NoOp)
        , timeout = Nothing
        , tracker = Nothing
        }
    )


type Msg
    = NoOp


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        NoOp ->
            ( model, Cmd.none )


view : Model -> Html Msg
view model =
    div [] []


main : Program () Model Msg
main =
    Browser.element
        { init = init
        , view = view
        , update = update
        , subscriptions = always Sub.none
        }

Result (runtime exception)

Uncaught SyntaxError: Failed to execute 'setRequestHeader' on 'XMLHttpRequest': '' is not a valid HTTP header field name.

On the other hand, empty "value" does not cause exception.

Expected behavior/Proposal

What I actually wanted was, conditionally adding/not adding a Http.header based on a variable like so:

...
, headers =
    [ case fooBar of
        Foo str ->
            Http.header "foo" str
        Bar ->
            Http.header "" ""
    , ...
    ]
...

but as it turned out it ends up in a runtime exception.

  • At least we should not leak runtime exception, so Http.header "" "something" should either:
    • not compile
    • not try to setRequestHeader() at runtime (effectively none for header)

The latter could be useful since it can be used paired with if or case inside Lists, like I wanted to do.

As for my intent, for now we can just wrap it in a List for the same effect:

...
, headers =
    case fooBar of
        Foo str ->
            [ Http.header "foo" str ]
        Bar ->
            []
    , ...
    ]
...

No method for creating fileParts from non-File types

The https://github.com/elm/file package provides methods for downloading strings and bytes as files, but similar methods are not included with this package. This makes it difficult for an application to generate files that can be posted with Http.multipartBody.

Expected behavior would be to shortcut these (UX-poor) steps:

  1. File.Download.bytes (have user download file)
  2. File.Select.file (have user select the same file)
  3. Http.filePart (create a file part)
  4. Http.post (post to server)

The net result of the above steps is essentially nothing more than attaching a name to a Blob, resulting in a File. Similar steps would be used for string data.

One possible solution might be to add a function:
bytesPartToFilePart : String -> Part -> Part
to explicitly name a bytes blob.

A second solution might be to add functions to go directly from strings and bytes to file bodies.

I am proposing this change as I feel it is a relatively simple change that will open up a large variety of HTTP-based storage options for future Elm applications. I am personally exploring decentralized application file storage via IPFS and have hit a few walls from not having this feature.

Method to add header to existing request

I can't find a way to add a header to an existing request. I've got a situation where I need to add a JWT header to all of my requests for logged in users. The straightforward solution seems to be creating a version of send that adds the new header to each request and then calls Http.send. However, it doesn't seem possible to add headers to existing requests.

Am I missing something in the current API? Is what I'm asking for a bad idea?

Expose mapExpect

Upgrading to 0.18 I found some code a coworker wrote reusing one request and Task.mapping the response to make another useful HTTP-related function. I see that you have Http.Internal.Response.map and mapExpect in the Native code; black-boxing Request is fine, but being able to operate inside it when necessary would be nice. Or perhaps expectAndThen or mapAfter?

Document withCredentials

request takes a record containing withCredentials, but the documentation does not give any indication as to what a value of True or False means.

Methods for building PUT and DELETE requests?

We have Http.get and Http.post. Can we have Http.delete and Http.put as well?

I'd contend that these are common enough on REST APIs that these methods are worth their place though of course it's true that I can always fall back to Http.request.

Happy to send a pull request, if you're open to this.

More information about NetworkError

I found cross-origin request returns NetworkError, but this error could be more concrete. I was about to try turning on wifi...

Browser shows some helpful message in console (that end users never see).

XMLHttpRequest cannot load http://package.elm-lang.org/packages/elm-lang/http/1.0.0/Http.
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://elm-lang.org' is therefore not allowed access.

How can we get this information?

Add a FilePart tag to the Http.Part type and a filePart function to make one

I recently wrote some code to upload an image file, selected with an <input type='file'> element. Creating that element and processing a change event from it is easy to do in elm/http. What's harder is posting the contents.

I did it with a custom element and a patch to XMLHttpRequest.send(), to enable binary data if it sees a header that looks like an image (otherwise, a binary string gets converted to UTF-8, mangling some of its single bytes into two bytes). That's done by the CustomElement.FileListener module in billstclair/elm-custom-element, and its corresponding site/js/file-listener.js JavaScript file.

It would be much nicer to send the file using the standard mechanism for that, FormData.append with the File object inside the <input type='file'> element. That would enable large uploads, instead of loading the entire file into memory as my custom element does. And user code would be pure Elm.

The API would be very simple.

Change the Part type, by adding a FilePart option:

type Part
  = StringPart String String
  | FilePart String String

Add a filePart function, whose second String arg is the <id> of the <input type='file' id='<id>'> element.

filePart : String -> String -> Part
filePart =
  FilePart

Elm.Kernel.Http.multipart would have to change to recognize a FilePart, and look up the input element, ensure that it's of type file, grab it's files property, and call formData.append() for each File element of that array.

I'm happy to do this, and submit it as a pull request, but only if somebody on the Elm team assures me that it's likely to be accepted.

How to handle Server-side redirects?

When a user is unauthenticated, I'd like to use the server to redirect to a login page.
On remote http requests, the login page is returned in the response instead.
Is there a way to handle this?

Thanks!

Http.cancel cancelling subsequent requests

Quick Summary:

When a variable using Task.perform or Task.attempt is created in the update function, Http.cancel cancels http request in next update loop.

SSCCE

https://ellie-app.com/6kdQ4HXVJ2ga1

module Main exposing (main)

import Browser
import Html exposing (text)
import Http
import Json.Decode
import Task
import Time

sequentialCmds : Cmd Msg -> List (Cmd Msg) -> Cmd Msg
sequentialCmds cmd cmds =
    case cmds of
        [] ->
            cmd

        first :: others ->
            Cmd.batch
                [ cmd
                , Task.perform (\_ -> SequentialCmds first others) (Task.succeed ())
                ]


init : Cmd Msg
init =
    sequentialCmds (Http.cancel getBrassicaOleraceaTracker)
        [ getBrassicaOleracea ]


type Msg
    = GotBrassicaOleracea (Result Http.Error Json.Decode.Value)
    | SequentialCmds (Cmd Msg) (List (Cmd Msg))
    | DoSomething


update : Msg -> Cmd Msg
update msg =
    case msg of
        GotBrassicaOleracea _ ->
            Cmd.none

        SequentialCmds cmd cmds ->
            sequentialCmds cmd cmds

        DoSomething ->
            Cmd.none


main : Program () () Msg
main =
    Browser.element
        { init = \_ -> init |> Tuple.pair ()
        , view = \_ -> text ""
        , update =
            \msg _ ->
                update msg
                    |> doSomething
                    |> Tuple.pair ()
        , subscriptions = \_ -> Sub.none
        }


performImmediately : msg -> Cmd msg
performImmediately msg =
    Task.perform (\_ -> msg) (Task.succeed ())


doSomething : Cmd Msg -> Cmd Msg
doSomething cmd =
    let
        doSomethingCmd : Cmd Msg
        doSomethingCmd =
            Task.perform (always DoSomething) (Task.succeed ())
    in
    cmd

getBrassicaOleraceaTracker : String
getBrassicaOleraceaTracker =
    "getBrassicaOleraceaTracker"


getBrassicaOleracea : Cmd Msg
getBrassicaOleracea =
    Http.request
        { method = "GET"
        , headers = []
        , url = "https://en.wikipedia.org/api/rest_v1/page/summary/Brassica_oleracea"
        , body = Http.emptyBody
        , expect = Http.expectJson GotBrassicaOleracea Json.Decode.value
        , timeout = Nothing
        , tracker = Just getBrassicaOleraceaTracker
        }
  • Elm: 0.19 and elm-0.19.1-beta-1-mac
  • Browser: Google Chrome and Safari
  • Operating System: MacOS (compilers and ellie), Ubuntu 18.04 (ellie)

Additional Details

Variables with other types of cmds such as Cmd.none do not cause this issue, which can be tested by changing the value of doSomethingCmd to Cmd.none.

Http.Error not caught for invalid protocol in Firefox

I was trying to verify my error branch is working PageLoaded (Err _) so I intentionally used an invalid protocol: "htp".

✔️ In Chrome it's caught in the error branch as expected.
❌ In Firefox it throws a JavaScript error: "A network error occurred."

Here's my SSCCE: https://ellie-app.com/brMS86CJwa1/2.

Firefox 56.0 (64-bit)
Ubuntu 17.04
Elm 0.18

Checklist

  • ✅ Does your title concisely summarize the problem?
    I hope so. I'm fairly new to Elm so my terminology might be a bit off.
  • ✅ Did you include a minimal, reproducible example? Is it an SSCCE?
    Yes, https://ellie-app.com/brMS86CJwa1/2.
  • ✅ What OS and browser are you using? What versions?
    Ubuntu 17.04 and Firefox 56.0 (64-bit)
  • ✅ What version of Elm are you using?
    0.18

Handling custom errors in 2.0.0

Hello there,

At my job, we are experiencing some difficulties switching to v2.0.0 as we are trying to provide our requests different return messages according to the http status of the response. Because now the Http.Error BadStatus only provides the http code, we cannot get further data from the response. We are trying to pattern-match the http status and catch the response directly with the function expectStringResponse but it seems a bit complicated.

So why not directly exposing the response through BadStatus anymore ?
And do some of you have examples of how to easily handle custom errors through the new API ?

Thanks for reading, please forgive my english :)

Wrapped decode error in BadPayload is malformed

I have found an issue when the decoder of expectJson fails.

A SCE (Short Correct Example) is at: https://gist.github.com/emtenet/88bb8b62689caad725314e510ef85972

It gives Json.Decode.Fail "FAIL" to Http.get. The problem with the example is you need to refer to a valid JSON file and need the appropriate cross-origin policies to be setup...

As far as I understand, the following line:
https://github.com/elm/http/blob/beta-1.0.0/src/Elm/Kernel/Http.js#L108
is wrapping the decode failure as a BadPayload error but with a missing A2 produces a function rather than a Http.Error

Port the original Http.url API to this project.

Hi, could you please port the original Http.url API to here?

I am using the following code as a workaround:

url : String -> List ( String, String ) -> String
url baseUrl query =
    case query of
        [] ->
            baseUrl

        _ ->
            let
                queryPairs =
                    query |> List.map (\( key, value ) -> Http.encodeUri key ++ "=" ++ Http.encodeUri value)

                queryString =
                    queryPairs |> String.join "&"
            in
                baseUrl ++ "?" ++ queryString

ArrayBuffer / Blob constructor conflict

We have a situation where we fetch binary data with http, then prompt the user, then use Download.bytes to allow the user to save the file.

In IE11, using expectBytesResponse yields InvalidStateException b/c Blobs cannot be initialized from array buffers. This is because expectBytesResponse sets xhr.responseType = 'arraybuffer'.

Run this in IE11 to see the Blob constructor issue in isolation.
new Blob( new ArrayBuffer([123]), { type: 'application/*' } );

We were able to solve the problem by creating a new expect factory function like this.

expectBlobResponse : (Result x a -> msg) -> (Http.Response Bytes -> Result x a) -> Http.Expect msg
expectBlobResponse toMsg toResult =
    Elm.Kernel.Http.expect "blob" identity (toResult >> toMsg)

We really don't want people to use Elm.Kernel inside of their application code so I'm gonna submit a PR to add this to the library.

Please let me know what you think. :)

`multipartBody` does not set the boundary in the Content-Type header

Code to reproduce this can be found here:
https://gist.github.com/crazymykl/3463ceddf89986b46821933b1bc0a11a

When running this program, a POST request is sent with the Content-Type header set to multipart/form-data. It needs to be set to multipart/form-data; boundary={the generated delimiter}.

I chose the Slack API for the SSCCE because it explicitly sends error: "invalid_form_data. I would expect this request to instead give error: "not_authed", since we don't send a token.

Expose Internal.RawRequest (and maybe a 'defaultRequestFields')

When trying to create a new request from scratch, it sure would be nice to have a type I can use to define a function called defaultRequestFields so that I don't have to enumerate all the fields of the request in every function that builds a different kind of request. Turns out that type is Http.Internal.RawRequest! 😃

Also, if we expose that type, why not also expose a method called defaultRequestFields so that if I want to create a new request all I have to do is:

buildRequestWithCredentials : String -> Request String
buildRequestWithCredentials url =
  request
    { defaultRequestFields
    | withCredentials = True,
    , url = url
    }

Or if I have my own default Request fields, I can say:

defaultRequestFields : RawRequest
defaultRequestFields =
  let
    defaultFields = Http.defaultRequestFields
  in
    { defaultFields
    | withCredentials = True
    , expect = Http.expectJson decoder
    }

(And then replace the URL as needed)

Add examples for handling BadStatus Http.Error with Response Body

Hi, folks!
We have our Elm app where the server sends to us some objects with validation errors in them with BadStatus.
Previously we handled response body from BadStatus Http.Error. But after contract change in elm/http (previously evancz/elm-http), we can't figure out how to get it correctly.

P.S. We're using Http.task, so seems we can't add there expect field to get additional info, cause it exists only on Http.request

Example where parallel requests may be ideal

As proposed in #28, I would like to gather examples of where parallel requests are ideal. This issue is also discussed on Discourse.

In my case I want to fetch multiple xkcd comics in parallel. I have a function that generates a list of the N most recent xkcds by fetching the current one, and making a list of ids starting with the current one's. Then I can map that list of ids to requests that fetch the actual xkcd comic.

Currently, this is implemented using Task.sequence. But obviously, there would be a huge performance boost if there was a way to execute all requests in parallel. And it would be tough to do it with separate Cmds, because I would need to know when the last response has finished, which means somehow counting how many have already come back.

As for the error handling problem: I imagine a function Http.parallel : List Http.Request -> Task Http.Error (List Http.Response) (where Http.Request can't be a Cmd, I guess, but basically what Http.get or Http.request would return). Because those Http.Responses encode all possible errors, I can then choose how to deal with them. In my case I will probably ignore them. For example:

evaluateResponses : List Http.Response -> List Xkcd
evaluateResponses responses =
    List.foldl (\response evaluated ->
        case response of
            Http.GoodStatus_ meta body ->
                evaluated ++ [
                    -- Returns an Xkcd
                    Xkcd.parseBody body
                 ]

            -- Ignore errors
            _ ->
                evaluated

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.