How to call fetch API response object's json function

When init reason react example project , I change reason code to rescript code and when modify

React.useEffect0(() => {

open Js.Promise

//let fetch1 = make((~resolve, ~reject) => resolve(. 2))

fetch("https://dog.ceo/api/breeds/image/random/3")

    |> then_(response => response.json())

and compile result :

We’ve found a bug for you!
/mnt/f/Projects/meetingbook/src/FetchedDogPictures/FetchedDogPictures.res 18:39-42

16 ┆ //let fetch1 = make((~resolve, ~reject) => resolve(. 2))
17 ┆ fetch(“https://dog.ceo/api/breeds/image/random/3”)
18 ┆ |> then_(response => response.json)
19 ┆ |> then_(jsonResponse => {
20 ┆ setState(_previousState => LoadedDogs(jsonResponse[“message”]
))

The record field json can’t be found.

and How to call response json method and return a promise

So sorry,i’m chinese and my english is poor.

In functional languages you usually don’t call methods on objects like response.json(), but use functions which operate on some data structure: Fetch.Response.json(response).

I guess you’re using be-fetch?
Take a look at their example: https://github.com/reasonml-community/bs-fetch/blob/934389964e1005d4e37911c8324a6aeb7ce0a1b0/examples/reason_examples.re#L22 (this is in reason syntax)

1 Like

Hi woeps, i’m using original fetch https://fetch.spec.whatwg.org/#dom-global-fetch insteand of bs-fetch, i have solved this issue like this:

type response

@bs.send external getJSON: response => Js.Promise.t<'a> = “json”

open Js.Promise

//let fetch1 = make((~resolve, ~reject) => resolve(. 2))

fetch("https://dog.ceo/api/breeds/image/random/3")

    |> then_(res => res->getJSON)

Thank you for your help。

Hi, bs-fetch is the original Fetch API. It’s a package containing bindings, like the one you wrote by hand. One issue with your binding is that it’s not type-safe–the return type Js.Promise.t<'a> is too broad for the actual type, which is JSON. The return type should be Js.Promise.t<Js.Json.t>.

Hi, yawaramin, original fetch API’s json return type of Promise<any> https://fetch.spec.whatwg.org/#body-mixin so when i adjusted my code to your way, the compiler occur below error:

We’ve found a bug for you!
/mnt/f/Projects/meetingbook/src/FetchedDogPictures/FetchedDogPictures.res 23:12-26:13

21 ┆ fetch(“https://dog.ceo/api/breeds/image/random/3”)
22 ┆ |> then_(res => res->getJSON)
23 ┆ |> then_(jsonResponse => {
24 ┆ setState(_previousState => LoadedDogs(jsonResponse[“message”]
))
25 ┆ Js.Promise.resolve()
26 ┆ })
27 ┆ |> catch(_err => {
28 ┆ setState(_previousState => ErrorFetchingDogs);

This has type:
Js.Promise.t<Js.t<{…“message”: array} as 'a>> => Js.Promise.t

But somewhere wanted:
Js.Promise.t<Js.Json.t> => 'b

and I think is should be Js.Promise.t<'a>

Hi, the WhatWG spec doesn’t look correct to me … I am referring to Fetch API’s Response#json() method: https://developer.mozilla.org/en-US/docs/Web/API/Body/json

Once you have a Js.Json.t, it’s a ‘raw’ object that you have to decode into a your application’s domain type. (In ReScript a JSON object is not just the same thing as a JavaScript object, this is for type safety reasons.)

Decoding can be done with a library like Decco, which basically provides a macro that looks at the structure of a type definition and generates a decoder for it.

Example of a type with a decoder: https://github.com/yawaramin/fullstack-reason/blob/70a213e9280cd481d327250733d90693d7246e6c/shared/Shared__User.re#L2

Example of using the decoder: https://github.com/yawaramin/fullstack-reason/blob/70a213e9280cd481d327250733d90693d7246e6c/frontend/ShowBob.re#L15

1 Like

A JavaScript “any” type isn’t exactly the same as a ReScript 'a type. Although 'a does allow you to use “any” type, using 'a with an external binding will unsafely bypass type checking. I assume when the WhatWG spec says “any,” it really means “any JSON object.” There are JavaScript types that a Fetch json() method isn’t able to return.

In ReScript, the way you safely handle an external “any” type is to give it an opaque/abstract type and then use a function at runtime to safely cast it to the correct type. In fact, this is exactly what the Js.Json.t type is, and exactly what Decco does (along with other JSON decoding libraries). Js.Json.t essentially mean “any type that conforms to the JSON spec.”

This let-binding misses an expression …getting this

Probably would have been better to start a new thread after 2 years: with additional infos on what you are trying to achieve and a code-snippet of the code having the described error.
This way it would be easier to help.

But the shortest possible reprosucible code with your described error is this:

let x =

The error states, you forgot to define ,what the actual value (expression) of a let binding should be.

You could fix the example above by adding the missing part:

let x = 42