I'm writing an asynchronous HTTP API client module/library. To make everything as DRY as possible, I'm trying to compose every HTTP API call from separate parts that make an API call, bottom-up: building a request, getting a response, reading a response into string buffer, parsing JSON contents of that string buffer into an object.
So far I have this code:
module ApiUtils =
// ... request builder fns omitted ...
let getResponse<'a> (request : Net.WebRequest) =
request.AsyncGetResponse()
let readResponse (response : Net.WebResponse) =
use reader = new StreamReader(response.GetResponseStream())
reader.AsyncReadToEnd()
let getString = getResponse >> (Async.flatMap readResponse)
let parseJson<'T> responseText : 'T =
Json.JsonConvert.DeserializeObject<'T> responseText
let getJson<'T> = getString >> (Async.map parseJson<'T>)
And, as you can see, I've extended the Async module with my own additions:
module Async =
let map f m =
async {
let! v = m
return f v
}
let flatMap f m =
async {
let! v = m
return! f v
}
The goal I am trying to achieve is to build a module with functions that I can use in async
blocks, to take all the advantage of computation expression syntax. I was wondering if I am doing it right, if I'm choosing the right names, etc. I have very little to no formal functional programming education, and sometimes I'm not even sure I know what I'm doing.