0

I am reading this tutorial https://www.stackbuilders.com/blog/nonsense-getting-started-with-reason-and-reason-react/. One of the problems I am facing is that api.noopschallenge.com is now dead. I replaced the API call to this https://random-word-api.herokuapp.com/word?number=20 This works but returns a Json Array. I have to convert the Json Array to list(string).

I modified the decodeWords function as

let decodeWord = (json: Js.Json.t) : list(string) => 
    switch(Js.Json.decodeArray(json)) {
      | None => []
      | Some(array) => Belt.Array.map(Js.Json.decodeString, array)
    };

But this gives me error

This has type: Js.Json.t => option(Js.String.t) But somewhere wanted: array('a)

How do I convert the Json Array to list(string)?

glennsl
  • 28,186
  • 12
  • 57
  • 75
Knows Not Much
  • 30,395
  • 60
  • 197
  • 373

2 Answers2

1

Two problems:

  1. You've switched the arguments to Belt.Array.map around.´array` should come first.
  2. Since decodeString returns an option(string) instead of just a string, you'll have to deal with the Nones somehow. Using Belt.Array.keepMap is a shorter way of just ignoring them.
let decodeWords = (json: Js.Json.t): list(string) =>
  switch (Js.Json.decodeArray(json)) {
  | None => []
  | Some(array) =>
    array->Belt.Array.keepMap(Js.Json.decodeString)->Belt.List.fromArray
  };

But using the Js.Json API directly is rather cumbersome. You might want to consider using a third-party json decoding library such as bs-json (disclaimer: authored by me) instead. Then it would be as simple as:

let decodeWords = Json.Decode.(list(string))

Or, if you still want it to return an empty list instead of raising an exception on decode failure:

let decodeWords = Json.Decode.(withDefault([], list(string)))
glennsl
  • 28,186
  • 12
  • 57
  • 75
  • 1
    This worked for me `let decodeWords = Json.Decode.(withDefault([], list(string)))` after adding the right bs-json dependency `"@glennsl/bs-json"` – Knows Not Much Dec 06 '22 at 05:29
0

I think I resolved it myself. but if you know of a better solution then please let me know

    let decodeWords = (json: Js.Json.t) : list(string) => 
      switch(Js.Json.decodeArray(json)) {
        | None => []
        | Some(array) => Belt.Array.reduce(array, [], (acc, value) => {
          switch(Js.Json.decodeString(value)) {
            | None => acc
            | Some(v) => [v, ...acc]
          }
       })
    };
glennsl
  • 28,186
  • 12
  • 57
  • 75
Knows Not Much
  • 30,395
  • 60
  • 197
  • 373