I\'m new to F# and stuck in understanding async in F# from the perspective of a C# developer. Say having the following snippet in C#:
Just my two cents. But my understanding is that we should be handling the HttpRequestException
when using EnsureSuccessStatusCode()
.
Below is the start of a module wrapping HttpClient
that will buffer the response of a URL into a string
and safely wrap in a Result<'a, 'b>
for improved fault tolerance.
module Http =
open System
open System.Net.Http
let getStringAsync url =
async {
let httpClient = new HttpClient()
// This can be easily be made into a HttpClientFactory.Create() call
// if you're using >= netcore2.1
try
use! resp = httpClient.GetAsync(Uri(url), HttpCompletionOption.ResponseHeadersRead) |> Async.AwaitTask
resp.EnsureSuccessStatusCode |> ignore
let! str = resp.Content.ReadAsStringAsync() |> Async.AwaitTask
return Ok str
with
| :? HttpRequestException as ex -> return ex.Message |> Error
}
You'll want to at least read and be aware of the established patterns in Http.fs if you're doing anything with HttpClient
in F#.
[See comments] TL;DR ... but Beware the Share. As noted by @pimbrouwers, it should be noted that you don't necessarily have to then use it though - subsetting and/or evolving your own set of helpers in your context can lead you to a better fitting abstraction (and bring you the benefits of the learning on the way).
To this point: It's considered idiomatic practice in F# to keep rarely used and/or overly specific helpers in a non-central location.
Here is a function that should do what you're looking for (note that you'll have to wrap the code in an asynchronous computation expression in order to use the let! syntax):
let getAsync (url:string) =
async {
let httpClient = new System.Net.Http.HttpClient()
let! response = httpClient.GetAsync(url) |> Async.AwaitTask
response.EnsureSuccessStatusCode () |> ignore
let! content = response.Content.ReadAsStringAsync() |> Async.AwaitTask
return content
}
Just use FSharp.Control.FusionTasks
and you will have clear syntax without |> Async.AwaitTask
like
let httpClient = new System.Net.Http.HttpClient ()
let getAsync (url:string) =
async {
let! response = httpClient.GetAsync url
response.EnsureSuccessStatusCode () |> ignore
let! content = response.Content.ReadAsStringAsync ()
return content
}
You can use async
:
let readString (url: Uri) = async {
let httpClient = new HttpClient();
let! response = httpClient.GetAsync(url) |> Async.AwaitTask
response.EnsureSuccessStatusCode() |> ignore
return! response.Content.ReadAsStringAsync() |> Async.AwaitTask
}