# A configurable JSON parser in Elm

**URL:** <https://discourse.elm-lang.org/t/a-configurable-json-parser-in-elm/2708>\
**Category:** Show and Tell\
**Created:** [December 6, 2018, 3:08am UTC](https://discourse.elm-lang.org/t/a-configurable-json-parser-in-elm/2708 "2018-12-06T03:08:21Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![allenap](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/allenap/32/4037_2.png) [@allenap](https://discourse.elm-lang.org/u/allenap)\
**Post date:** [December 6, 2018, 3:08am UTC](https://discourse.elm-lang.org/t/a-configurable-json-parser-in-elm/2708/1 "2018-12-06T03:08:21Z")

</div>

# Package & docs

Check out [allenap/elm-json-decode-broken](https://package.elm-lang.org/packages/allenap/elm-json-decode-broken/latest/). It uses [elm/parser](https://package.elm-lang.org/packages/elm/parser/latest/) to construct the parser. I put “broken” in the name to make you think twice before using it, but also because it can parse “broken” JSON.

# Parsing invalid JSON

On the face of it I built something pointless: a JSON parser in Elm. After all, `Json.Decode` in [elm/json](https://package.elm-lang.org/packages/elm/json/latest/) makes use of [`JSON.parse`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse), which is native code, battle tested, fast. **But it won’t parse broken JSON**. In my particular case, that was JSON with strings containing carriage returns and new lines. These must be escaped in proper JSON, and `JSON.parse` and `Json.Decode.decodeString` rejected the data I needed to work with.

The right thing to do was talk to the people who were generating the invalid JSON and ask them to fix it, and I am in touch. In the meantime I use this parser to work with their data. I used the situation as an excuse to learn how to use elm/parser which was arguably more interesting than working on the end product.

# An example

Below is how I used it for my particular situation. The `parseAndDecode` function is almost a drop-in replacement for `Json.Decode.decodeString` (the error types are different). You can see the basic mechanism for creating a custom parser.

```elm
import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Broken as Broken
import Json.Encode as Encode
import Parser exposing ((|.), (|=), Parser)

relaxedStringUnescaped : Parser String
relaxedStringUnescaped =
    Parser.oneOf
        [ Broken.unescaped
        , Parser.symbol "\r" |> Broken.yields "\r"
        , Parser.symbol "\n" |> Broken.yields "\n"
        ]

relaxedStringLiteral : Parser String
relaxedStringLiteral =
    Broken.stringLiteral relaxedStringUnescaped Broken.escape

relaxedString : Parser Encode.Value
relaxedString =
    Parser.map Encode.string relaxedStringLiteral

relaxedStringConfig : Broken.Config
relaxedStringConfig =
    case Broken.defaultConfig of
        Broken.Config c ->
            Broken.Config { c | string = relaxedString }

parseAndDecode : Decoder a -> String -> Result String a
parseAndDecode decoder json =
    case Broken.parseWith relaxedStringConfig json of
        Ok value ->
            Decode.decodeValue decoder value
                |> Result.mapError Decode.errorToString

        Err error ->
            Err <| Parser.deadEndsToString error

```

---

<div class="post-metadata">

**Author:** ![system](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/1X/50a05e53677a2c3b47776d7abd0f113eb50193a1.png) [@system](https://discourse.elm-lang.org/u/system)\
**Post date:** [December 16, 2018, 3:08am UTC](https://discourse.elm-lang.org/t/a-configurable-json-parser-in-elm/2708/2 "2018-12-16T03:08:23Z")

</div>

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.
