Combine properties when decoding JSON

Hi folks,

I’m having trouble decoding a JSON object. The API I am talking to has two
properties that should be combined. I want to solve this in the decoding step
and not further down in my code.

This is the object I receive from the API:

{
    "video_id": "Mestkever",
    "video_extension": "mp4",
    "video_thumbnail": "Mestkever",
    ...
}

Both video_extension and video_thumbnail should be joined as strings with a
dot in between to get the full filename. Below is my current implementation. I
got it working, but it won’t scale. Adding more properties means adding more to
toDecoder. I cannot change the API so I have to solve the problem in our front-end application.

import Json.Decode exposing (Decoder, float, int, string)
import Json.Decode.Pipeline exposing (decode, required, resolve)

type alias Video =
    { id : String
    , filename : String
    }

decode : Decoder Video
decode =
    let
        toDecoder : String -> String -> String -> Decoder Video
        toDecoder id filename extension =
            JD.succeed (Video id (filename ++ "." ++ extension))
    in
    JD.succeed toDecoder
        |> required "video_id" JD.string
        |> required "video_thumbnail" JD.string
        |> required "video_extension" JD.string
        |> JDP.resolve

My gut tells me this should be an easy fix, but can’t figure it out. I’ve created this Ellie to show the implementation above: https://ellie-app.com/7nv8cBBmxRXa1.

How do I change the implementation so that I don’t have a toDecoder that I have to expand when adding more properties?

You could make a custom Decoder for the joined string part:

decode : Decoder Video
decode =
    JD.succeed Video
        |> JDP.required "video_id" JD.string
        |> JDP.custom videoFile


videoFile : Decoder String
videoFile =
    JD.succeed (\filename extension -> filename ++ "." ++ extension)
        |> JDP.required "video_thumbnail" JD.string
        |> JDP.required "video_extension" JD.string

or without using elm-json-decode-pipeline:

decode : Decoder Video
decode =
    JD.map2 Video
        (JD.field "video_id" JD.string)
        videoFile


videoFile : Decoder String
videoFile =
    JD.map2 (\filename extension -> filename ++ "." ++ extension)
        (JD.field "video_thumbnail" JD.string)
        (JD.field "video_extension" JD.string)
5 Likes

The solution is so easy :sweat_smile:. I over-complicated things. Thank you very much! :heart:

1 Like

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