What you’re describing is really quite easy to do in user land already:
module Response = {
type t
@send external json: t => promise<JSON.t> = "json"
}
type data = {
user: {
id: string,
},
}
external parseData: JSON.t => result<data, [> #ParseError]> = "parseData"
let toResult: promise<'v> => promise<
result<'v, [> #Exception(exn)]>,
> = async p => {
switch await p {
| exception e => Error(#Exception(e))
| r => Ok(r)
}
}
external fetch: string => promise<Response.t> = "fetch"
let main = async () => {
let? Ok(response) = await fetch("api/data")->toResult
let? Ok(json) = await response->Response.json->toResult
let? Ok(data) = json->parseData
Ok(data)
}
It compiles to a try/catch with await, so it caches promise errors.
But I guess the toResult function could be a good candidate for the stdlib indeed, even if it’s simple.