Skip to content

Commit

Permalink
Update to Elm 0.18 (#51)
Browse files Browse the repository at this point in the history
* Remove unused Elm package sporto/erl

* Update elm version and package dependencies in elm-package.json

* Mechanic changes to upgrade to Elm 0.18

- No more primes in variable names
- Arguments flipped for `andThen`
- Changes in core library functions, modules `Json.Decode` and `Task`
- No more Html.App

* For Elm 0.18 upgrade: Migrate from evancz/elm-http to elm-lang/http

We also now use lukewestby/elm-http-builder to replace our own helper
functions here.

* Fix type vagueness of function withExpectJsonApi

* Adopt new function names of etaque/elm-form

* Adopt new function names of debois/elm-mdl v8

See https://github.com/debois/elm-mdl/blob/v8/MIGRATION.md

* Type annotations in Config_*.elm

* Reimplement routing (Elm 0.18, without sporto/hop)

References:
https://github.com/evancz/url-parser/blob/2.0.1/examples/Example.elm

* Remove config parameter basePath

Implementation currently won't support any non-empty basePath.
May be added back again later if needed.

* Requests need 'Content-Type: application/vnd.api+json' in JSON API

The standard functions of elm-lang/http and lukewestby/elm-http-builder
to add a JSON body automatically set 'Content-Type: application/json' in
the header, which is not conforming to JSON API.
http://jsonapi.org/format/#introduction

* Show nicer and shorter notices in case of Http errors.

The need for this change comes with elm-lang/http, as a naive `toString`
approach may result in very long text here.

Also don't save the httpError in the model. We don't need it.

* Configure Travis CI to use Elm 0.18.0
  • Loading branch information
ThomasWeiser authored and Oliver Azevedo Barnes committed May 1, 2017
1 parent 30869fb commit 5d4790e
Show file tree
Hide file tree
Showing 8 changed files with 230 additions and 251 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ before_install:
fi
install:
- npm install -g elm@0.17.1
- npm install -g elm@0.18.0
- npm install
- mv $(npm config get prefix)/bin/elm-make $(npm config get prefix)/bin/elm-make-org
- printf '%s\n\n' '#!/bin/bash' 'echo "Running elm-make with sysconfcpus -n 2"' '$TRAVIS_BUILD_DIR/sysconfcpus/bin/sysconfcpus -n 2 elm-make-org "$@"' > $(npm config get prefix)/bin/elm-make
Expand Down
23 changes: 11 additions & 12 deletions elm-package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,16 @@
],
"exposed-modules": [],
"dependencies": {
"debois/elm-mdl": "7.6.0 <= v < 8.0.0",
"elm-community/result-extra": "2.0.0 <= v < 3.0.0",
"elm-lang/core": "4.0.5 <= v < 5.0.0",
"elm-lang/html": "1.1.0 <= v < 2.0.0",
"elm-lang/navigation": "1.0.0 <= v < 2.0.0",
"etaque/elm-simple-form": "4.0.0 <= v < 5.0.0",
"evancz/elm-http": "3.0.1 <= v < 4.0.0",
"evancz/url-parser": "1.0.0 <= v < 2.0.0",
"noahzgordon/elm-jsonapi": "2.0.2 <= v < 3.0.0",
"sporto/erl": "10.0.1 <= v < 11.0.0",
"sporto/hop": "6.0.0 <= v < 7.0.0"
"debois/elm-mdl": "8.1.0 <= v < 9.0.0",
"elm-community/result-extra": "2.2.0 <= v < 3.0.0",
"elm-lang/core": "5.1.1 <= v < 6.0.0",
"elm-lang/html": "2.0.0 <= v < 3.0.0",
"elm-lang/http": "1.0.0 <= v < 2.0.0",
"elm-lang/navigation": "2.1.0 <= v < 3.0.0",
"etaque/elm-form": "2.0.0 <= v < 3.0.0",
"evancz/url-parser": "2.0.1 <= v < 3.0.0",
"lukewestby/elm-http-builder": "5.1.0 <= v < 6.0.0",
"noahzgordon/elm-jsonapi": "2.2.1 <= v < 3.0.0"
},
"elm-version": "0.17.1 <= v < 0.18.0"
"elm-version": "0.18.0 <= v < 0.19.0"
}
64 changes: 36 additions & 28 deletions src/Api.elm
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module Api

import Result.Extra
import Http
import Task exposing (Task)
import HttpBuilder
import Json.Decode as Decode
import Json.Decode exposing (Decoder)
import Json.Encode as Encode
Expand Down Expand Up @@ -78,7 +78,6 @@ facebookAuthUrl =
let
facebookRedirectUri =
Config.baseRoot
++ Config.basePath
++ "/"
++ Config.facebookRedirectPath
in
Expand Down Expand Up @@ -160,7 +159,7 @@ type alias DecodedProposalAttributes =

decodeProposalAttributes : Decoder DecodedProposalAttributes
decodeProposalAttributes =
Decode.object5 DecodedProposalAttributes
Decode.map5 DecodedProposalAttributes
(Decode.at [ "title" ] Decode.string)
(Decode.at [ "body" ] Decode.string)
(Decode.at [ "support-count" ] Decode.int)
Expand All @@ -173,7 +172,7 @@ decodeParticipantAttributes =
Decode.at [ "name" ] Decode.string


encodeProposalInput : NewProposal -> String
encodeProposalInput : NewProposal -> Encode.Value
encodeProposalInput proposalInput =
JsonApi.Extra.encodeDocument
"proposal"
Expand All @@ -184,7 +183,7 @@ encodeProposalInput proposalInput =
[]


encodeSupportProposal : String -> String
encodeSupportProposal : String -> Encode.Value
encodeSupportProposal id =
JsonApi.Extra.encodeDocument
"support"
Expand Down Expand Up @@ -215,7 +214,7 @@ assembleSupport document =

decodeProposalSupportAttributes : Decoder ( Int, Bool )
decodeProposalSupportAttributes =
Decode.object2 (,)
Decode.map2 (,)
(Decode.at [ "support-count" ] Decode.int)
(Decode.at [ "supported-by-me" ] Decode.bool)

Expand All @@ -226,60 +225,69 @@ decodeProposalSupportAttributes =

authenticate : String -> (Msg -> a) -> Cmd a
authenticate authCode wrapMsg =
("{\"auth_code\": \"" ++ authCode ++ "\"}")
|> Api.Util.requestPost tokenEndpoint
|> JsonApi.Extra.withHeader "Content-Type" "application/json"
|> Api.Util.sendDefJson decodeToken
|> Task.perform AuthFailed GotAccessToken
tokenEndpoint
|> HttpBuilder.post
|> HttpBuilder.withJsonBody
(Encode.object [ ( "auth_code", Encode.string authCode ) ])
|> HttpBuilder.withExpect (Http.expectJson decodeToken)
|> HttpBuilder.toTask
|> Api.Util.attempt AuthFailed GotAccessToken
|> Cmd.map wrapMsg


getMe : String -> (Msg -> a) -> Cmd a
getMe accessToken wrapMsg =
meEndpoint
|> Api.Util.requestGet
|> HttpBuilder.get
|> Api.Util.withAccessToken accessToken
|> Api.Util.sendDefJsonApi assembleMe
|> Task.perform AuthFailed GotMe
|> Api.Util.withExpectJsonApi assembleMe
|> HttpBuilder.toTask
|> Api.Util.attempt AuthFailed GotMe
|> Cmd.map wrapMsg


createProposal : NewProposal -> String -> (Msg -> a) -> Cmd a
createProposal proposalInput accessToken wrapMsg =
encodeProposalInput proposalInput
|> Api.Util.requestPost newProposalEndpoint
newProposalEndpoint
|> HttpBuilder.post
|> Api.Util.withJsonApiBody (encodeProposalInput proposalInput)
|> Api.Util.withAccessToken accessToken
|> Api.Util.sendDefJsonApi assembleProposal
|> Task.perform ProposalCreationFailed ProposalCreated
|> Api.Util.withExpectJsonApi assembleProposal
|> HttpBuilder.toTask
|> Api.Util.attempt ProposalCreationFailed ProposalCreated
|> Cmd.map wrapMsg


supportProposal : String -> Bool -> String -> (Msg -> a) -> Cmd a
supportProposal id newState accessToken wrapMsg =
-- ToDo: Send DELETE request to remove support (if newState == False)
encodeSupportProposal id
|> Api.Util.requestPost supportProposalEndpoint
supportProposalEndpoint
|> HttpBuilder.post
|> Api.Util.withJsonApiBody (encodeSupportProposal id)
|> Api.Util.withAccessToken accessToken
|> Api.Util.sendDefJsonApi assembleSupport
|> Task.perform SupportProposalFailed ProposalSupported
|> Api.Util.withExpectJsonApi assembleSupport
|> HttpBuilder.toTask
|> Api.Util.attempt SupportProposalFailed ProposalSupported
|> Cmd.map wrapMsg


getProposal : String -> String -> (Msg -> a) -> Cmd a
getProposal id accessToken wrapMsg =
getProposalEndpoint id
|> Api.Util.requestGet
|> HttpBuilder.get
|> Api.Util.withAccessToken accessToken
|> Api.Util.sendDefJsonApi assembleProposal
|> Task.perform GettingProposalFailed GotProposal
|> Api.Util.withExpectJsonApi assembleProposal
|> HttpBuilder.toTask
|> Api.Util.attempt GettingProposalFailed GotProposal
|> Cmd.map wrapMsg


getProposalList : String -> (Msg -> a) -> Cmd a
getProposalList accessToken wrapMsg =
getProposalListEndpoint
|> Api.Util.requestGet
|> HttpBuilder.get
|> Api.Util.withAccessToken accessToken
|> Api.Util.sendDefJsonApi assembleProposalList
|> Task.perform GettingProposalListFailed GotProposalList
|> Api.Util.withExpectJsonApi assembleProposalList
|> HttpBuilder.toTask
|> Api.Util.attempt GettingProposalListFailed GotProposalList
|> Cmd.map wrapMsg
82 changes: 41 additions & 41 deletions src/Api/Util.elm
Original file line number Diff line number Diff line change
@@ -1,68 +1,68 @@
module Api.Util exposing (..)

import Result.Extra
import Task exposing (Task)
import Json.Encode as Encode
import Json.Decode as Decode
import Http
import HttpBuilder
import JsonApi
import JsonApi.Extra
import JsonApi.Decode


{-| Infix notation for Result.andThen. Makes andThen-chains look nicer.
-}
infixl 0 :>
(:>) : Result x a -> (a -> Result x b) -> Result x b
(:>) =
Result.andThen
flip Result.andThen


{-| Insert accessToken into Http header
{-| Convenience version of `Task.attempt` that performs Tasks that may fail.
That's the same as in `elm-lang/core 4.x` (Elm 0.17)
-}
withAccessToken : String -> Http.Request -> Http.Request
withAccessToken accessToken =
JsonApi.Extra.withHeader "Authorization" ("Bearer " ++ accessToken)
attempt : (e -> msg) -> (a -> msg) -> Task e a -> Cmd msg
attempt errorTagger successTagger task =
Task.attempt (Result.Extra.unpack errorTagger successTagger) task


{-| Build a GET request
{-| Insert accessToken into Http header
-}
requestGet : String -> Http.Request
requestGet url =
{ verb = "GET"
, headers = []
, url = url
, body = Http.empty
}
withAccessToken : String -> HttpBuilder.RequestBuilder a -> HttpBuilder.RequestBuilder a
withAccessToken accessToken =
HttpBuilder.withHeader "Authorization" ("Bearer " ++ accessToken)


{-| Build a POST request
{-| Insert a JSON value as the body of a RequestBuilder.
This will set the `Content-Type: application/vnd.api+json` header,
as required by JSON API standard.
-}
requestPost : String -> String -> Http.Request
requestPost url body =
{ verb = "POST"
, headers = []
, url = url
, body = Http.string body
}
withJsonApiBody : Encode.Value -> HttpBuilder.RequestBuilder a -> HttpBuilder.RequestBuilder a
withJsonApiBody jsonValue =
HttpBuilder.withBody <|
Http.stringBody "application/vnd.api+json" (Encode.encode 0 jsonValue)


{-| Send a Http request with default settings
and decode the response from a JSON API document
{-| Expect the response body to be a JsonApi Document.
-}
sendDefJsonApi :
withExpectJsonApi :
(JsonApi.Document -> Result String a)
-> Http.Request
-> Task Http.Error a
sendDefJsonApi assembleResponse request =
JsonApi.Extra.sendJsonApi assembleResponse Http.defaultSettings request

-> HttpBuilder.RequestBuilder ()
-> HttpBuilder.RequestBuilder a
withExpectJsonApi assembleResponse requestBuilder =
requestBuilder
|> HttpBuilder.withHeader "Accept" "application/vnd.api+json"
|> HttpBuilder.withExpect
(Http.expectJson
(JsonApi.Decode.document
|> Decode.andThen
(\document ->
case assembleResponse document of
Ok successValue ->
Decode.succeed successValue

{-| Send a Http request with default settings
and decode the response from JSON
-}
sendDefJson :
Decode.Decoder a
-> Http.Request
-> Task Http.Error a
sendDefJson decodeResponse request =
request
|> Http.send Http.defaultSettings
|> Http.fromJson decodeResponse
Err errorMessage ->
Decode.fail errorMessage
)
)
)
8 changes: 4 additions & 4 deletions src/Config_heroku.elm
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
module Config exposing (..)


baseRoot : String
baseRoot =
"https://participateapp.github.io"


basePath =
""


facebookRedirectPath : String
facebookRedirectPath =
"facebook_redirect"


facebookClientId : String
facebookClientId =
"1583083548592686"


apiUrl : String
apiUrl =
"https://participate-api.herokuapp.com"
11 changes: 4 additions & 7 deletions src/Config_local.elm
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
module Config exposing (..)


baseRoot : String
baseRoot =
-- "https://oliverbarnes.github.io"
"http://localhost:3000"


basePath =
-- "/participate"
""


facebookRedirectPath : String
facebookRedirectPath =
"facebook_redirect"


facebookClientId : String
facebookClientId =
"1583083701926004"


apiUrl : String
apiUrl =
-- "https://participate-api.herokuapp.com"
"http://localhost:4000"
Loading

0 comments on commit 5d4790e

Please sign in to comment.