Backend Integration
Basic elm Http.post json request to node.js express server
Live upcase server that returns error when input string is longer than 10 characters.
Server:
const express = require('express'),
jsonParser = require('body-parser').json(),
app = express();
// Add headers to work with elm-reactor
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', 'https://localhost:8000');
res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
res.setHeader('Access-Control-Allow-Credentials', true);
next();
});
app.post('/upcase', jsonParser, (req, res, next) => {
// Just an example of possible invalid data for an error message demo
if (req.body.input && req.body.input.length < 10) {
res.json({
output: req.body.input.toUpperCase()
});
} else {
res.status(500).json({
error: `Bad input: '${req.body.input}'`
});
}
});
const server = app.listen(4000, () => {
console.log('Server is listening at https://localhost:4000/upcase');
});
Client:
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import Http
import Json.Decode as JD
import Json.Encode as JE
main : Program Never Model Msg
main =
Html.program
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
}
-- MODEL
type alias Model =
{ output: String
, error: Maybe String
}
init : (Model, Cmd Msg)
init =
( Model "" Nothing
, Cmd.none
)
-- UPDATE
type Msg
= UpcaseRequest ( Result Http.Error String )
| InputString String
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
UpcaseRequest (Ok response) ->
( { model | output = response, error = Nothing }, Cmd.none )
UpcaseRequest (Err err) ->
let
errMsg = case err of
Http.Timeout ->
"Request timeout"
Http.NetworkError ->
"Network error"
Http.BadPayload msg _ ->
msg
Http.BadStatus response ->
case JD.decodeString upcaseErrorDecoder response.body of
Ok errStr ->
errStr
Err _ ->
response.status.message
Http.BadUrl msg ->
"Bad url: " ++ msg
in
( { model | output = "", error = Just errMsg }, Cmd.none )
InputString str ->
( model, upcaseRequest str )
-- VIEW
view : Model -> Html Msg
view model =
let
outDiv = case model.error of
Nothing ->
div []
[ label [ for "outputUpcase" ] [ text "Output" ]
, input [ type_ "text", id "outputUpcase", readonly True, value model.output ] []
]
Just err ->
div []
[ label [ for "errorUpcase" ] [ text "Error" ]
, input [ type_ "text", id "errorUpcase", readonly True, value err ] []
]
in
div []
[ div []
[ label [ for "inputToUpcase" ] [ text "Input" ]
, input [ type_ "text", id "inputToUpcase", onInput InputString ] []
]
, outDiv
]
-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions model =
Sub.none
-- HELPERS
upcaseSuccessDecoder : JD.Decoder String
upcaseSuccessDecoder = JD.field "output" JD.string
upcaseErrorDecoder : JD.Decoder String
upcaseErrorDecoder = JD.field "error" JD.string
upcaseRequestEncoder : String -> JE.Value
upcaseRequestEncoder str = JE.object [ ( "input", JE.string str ) ]
upcaseRequest : String -> Cmd Msg
upcaseRequest str =
let
req = Http.post "https://localhost:4000/upcase" ( Http.jsonBody <| upcaseRequestEncoder str ) upcaseSuccessDecoder
in
Http.send UpcaseRequest req