I'm trying to figure out how to process failed http responses in the fetch example in reason-react-example repo.
The following was my first idea (tinkering with the url):
Js.Promise.(
Fetch.fetch("https://dog.ceo/api/breeds/list")
|> then_(res => {
let ok = Fetch.Response.ok(res);
ok ?
Fetch.Response.json(res) :
Js.Exn.raiseError(Fetch.Response.statusText(res));
})
|> then_(json =>
json
|> Decode.dogs
|> (dogs => self.send(DogsFetched(dogs)))
|> resolve
)
|> catch(err => {
Js.log(err);
[%bs.raw {| console.log(err.response) |}]
Js.Promise.resolve(self.send(DogsFailedToFetch));
})
|> ignore
);
It's not working as I hoped. It turns out Fetch
rejects right away when the HTTP request fails with 404 for instance, which I didn't expect since it's not how the browser fetch API works. Moreover, when err
is logged it's TypeError: Failed to fetch
and the err.response
property is undefined.
My question is: how to process the error to get the status code and status text for example?
The problem is CORS. The server you're using will include an Access-Control-Allow-Origin: *
header with 2xx
responses, but not with 404
responses. So apparently you're only allowed to read successful responses from this server.
You should get some additional warnings or errors in the console that tells you something like:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://dog.ceo/api/breeds/listio. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
or
[Error] Origin null is not allowed by Access-Control-Allow-Origin.
[Error] Failed to load resource: Origin null is not allowed by Access-Control-Allow-Origin. (listio, line 0)
[Error] Fetch API cannot load https://dog.ceo/api/breeds/listio. Origin null is not allowed by Access-Control-Allow-Origin.
You can fix this, at least when just testing, by using no-cors
mode instead. With bs-fetch
you'd do:
Fetch.fetchWithInit(url, Fetch.RequestInit.make(~mode=Fetch.NoCORS, ()))