Last active
October 28, 2020 00:11
-
-
Save ianrussellsoftwarepark/7f86ea9bddd25c56c495a7a683358b33 to your computer and use it in GitHub Desktop.
Functional wrapper for HttpClient
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let getResponse body (cookie: string option) (client:HttpClient) = | |
task { | |
return! | |
Http.createPostRequest Url | |
|> withBody (RequestBody.Xml body) | |
|> fun req -> | |
match cookie with | |
| Some c -> withCookie c req | |
| _ -> req | |
|> Http.execute client | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace HttpClient.FSharp | |
// See https://dev.to/jhewlett/creating-a-functional-wrapper-in-f-5hgp for original version | |
open System | |
open System.Net.Http | |
open System.Threading.Tasks | |
open FSharp.Control.Tasks.V2.ContextInsensitive | |
open HelperModule | |
open System.Collections.Generic | |
type HttpMethod = | |
| Post | |
| Put | |
| Delete | |
| Get | |
module HttpMethod = | |
let value method = | |
match method with | |
| Post -> System.Net.Http.HttpMethod.Post | |
| Put -> System.Net.Http.HttpMethod.Put | |
| Delete -> System.Net.Http.HttpMethod.Delete | |
| Get -> System.Net.Http.HttpMethod.Get | |
[<RequireQualifiedAccess>] | |
type RequestBody = | |
| Json of string | |
| Xml of string | |
| Form of IDictionary<string, string> | |
module RequestBody = | |
let value body = | |
match body with | |
| RequestBody.Json json -> new StringContent(json, System.Text.Encoding.UTF8, "application/json") :> HttpContent | |
| RequestBody.Xml xml -> new StringContent(xml, System.Text.Encoding.UTF8, "text/xml") :> HttpContent | |
| RequestBody.Form data -> new FormUrlEncodedContent(data |> List.ofSeq) :> HttpContent | |
type Request = { | |
Url : string | |
Method : HttpMethod | |
Timeout : TimeSpan option | |
Headers : (string * string) list | |
Body : RequestBody option | |
Query : (string * string) list | |
} | |
[<AutoOpen>] | |
module Request = | |
let withTimeout timeout request = | |
{ request with Timeout = Some timeout } | |
let withBody body request = | |
{ request with Body = Some body } | |
let withHeader header request = | |
{ request with Headers = header :: request.Headers } | |
let withAuthorization input request = | |
{ request with Headers = ("Authorization", input) :: request.Headers } | |
let withCookie input request = | |
{ request with Headers = ("Cookie", input) :: request.Headers } | |
let withQueryParam param request = | |
{ request with Query = param :: request.Query } | |
type Response = { | |
StatusCode : int | |
Body : string | |
Headers : (string * string) list | |
} | |
module Http = | |
let createRequest method url = | |
{ | |
Url = url | |
Method = method | |
Timeout = None | |
Headers = [] | |
Body = None | |
Query = [] | |
} | |
let createGetRequest = createRequest Get | |
let createPostRequest = createRequest Post | |
module Url = | |
let private encodeUrlParam param = | |
System.Uri.EscapeDataString param | |
let appendQueryToUrl (url : string) query = | |
match query with | |
| [] -> url | |
| query -> | |
url | |
+ if url.Contains "?" then "&" else "?" | |
+ String.concat "&" [ for k, v in List.rev query -> encodeUrlParam k + "=" + encodeUrlParam v ] | |
let execute (httpClient:HttpClient) (request:Request) : Task<Response> = | |
task { | |
request.Timeout | |
|> Option.iter (fun t -> httpClient.Timeout <- t) | |
let fullUrl = Url.appendQueryToUrl request.Url request.Query | |
use requestMessage = new HttpRequestMessage(request.Method |> HttpMethod.value, fullUrl) | |
request.Headers | |
|> List.iter requestMessage.Headers.Add | |
request.Body | |
|> Option.iter (fun b -> | |
let body = RequestBody.value b | |
requestMessage.Content <- body) | |
use! response = httpClient.SendAsync(requestMessage) | |
HttpUtil.ensureSuccessStatusCode response | |
let! body = response.Content.ReadAsStringAsync() | |
return | |
{ | |
StatusCode = int response.StatusCode | |
Body = body | |
Headers = [for (KeyValue (k, v)) in response.Headers -> (k, String.concat "," v)] | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment