rad
rad

Reputation: 1937

Playing with Type Provider and JSON API

I am trying to consume an API which return a JSON built as :

Team.player1 / player2 / player3... (the players are built as properties and not as an array)

I was thinking to use reflection to do it, but having hard time to get a player.

type Simple = JsonProvider<"sample.json">

let wbReq = "API-FOR-TEAM"    

let docAsync = Simple.Load(wbReq)

let allValues = FSharpType.GetRecordFields (docAsync.Team.Players.GetType())
let test = allValues
            |> Seq.map (fun p -> (p.GetValue(docAsync.Team.Players) as ?).Name) // HOW TO GET THE TYPED PLAYER HERE ?
            |> fun p -> printfn p

EDIT : I tried to use GetType and System.Convert.ChangeType

EDIT2 : Here is a simplified version of the JSON :

{
    "Team": {
        "id": "8",
        "players": {
            "17878": {
                "info": {
                    "idteam": 8,
                    "idplayer": 17878,
                    "note": 6
                }
            },
            "18507": {
                "info": {
                    "idteam": 8,
                    "idplayer": 18507,
                    "note": 5
                }
            }
        }
    }
}

Edit 3 :

I found an easy solution in C# (thanks to JSON.net and dynamic) but for learning purpose I would like to do the same in F# if someone wanna help :

        private static List<Player> Parse(string jsonString)
        {
            dynamic jsonObject = JsonConvert.DeserializeObject(jsonString);

            var players = ParseItems(jsonObject.Home.players);

            return players;
        }

        private static List<Player> ParseItems(dynamic items)
        {
            List<Player> itemList = new List<Player>();
            foreach (var item in items)
            {
                itemList.Add(new Player()
                {
                    idplayer = item.Value.info.idplayer,
                    lastName = item.Value.info.lastname,
                    note = item.Value.info.note
                });
            }
            return itemList;
        }

Upvotes: 3

Views: 284

Answers (1)

FoggyFinder
FoggyFinder

Reputation: 2220

You can mix JsonTypeProvider and parsing Json. For example:

[<Literal>]
let sample = """{
    "Team": {
        "id": "8",
        "players": {
            "17878": {
                "info": {
                    "idteam": 8,
                    "idplayer": 17878,
                    "note": 6
                }
            },
            "18507": {
                "info": {
                    "idteam": 8,
                    "idplayer": 18507,
                    "note": 5
                }
            }
        }
    }
}"""

type Player = {IdTeam:int; IdPlayer:int; Note:int}

type Simple = JsonProvider<sample>
let docAsync = Simple.GetSample()

let json = docAsync.Team.Players.JsonValue

let parseInfo (json:JsonValue) = 

    let id_team = (json.GetProperty "idteam").AsInteger()
    let id_player = (json.GetProperty "idplayer").AsInteger()
    let note = (json.GetProperty "note").AsInteger()

    {IdTeam = id_team; IdPlayer = id_player; Note = note}

let players = 
    json.Properties()
    |> Array.map(fun (_,x) -> x.GetProperty "info")
    |> Array.map (parseInfo)

players
|> Array.iter (printfn "%A")

Upvotes: 1

Related Questions