Skip to content

Instantly share code, notes, and snippets.

@zeejers
Last active July 16, 2023 02:01
Show Gist options
  • Save zeejers/5d5974eccfaf5e9e61c7ae3a660f216d to your computer and use it in GitHub Desktop.
Save zeejers/5d5974eccfaf5e9e61c7ae3a660f216d to your computer and use it in GitHub Desktop.
F# Api Client Wrapper Using FSharp.Data.Http
open FSharp.Data
open System
open System.Text
type HttpRequestConfig =
{ url: string option
query: (string * string) list option
headers: (string * string) seq option
method: string option
body: HttpRequestBody option
timeout: int option }
type HttpRequestError =
{ Message: string
StatusCode: int
RequestConfig: HttpRequestConfig }
type Client(credentials: Credentials) =
let mutable _username = credentials.username
let mutable _password = credentials.password
let mutable _region = credentials.region
member this.logPrefix = $"Client [{_username}]:"
member this.apiUrl =
match _region with
| EU -> regionURL EU
| UK -> regionURL UK
| CA -> regionURL CA
| _ -> regionURL US
member this.authHeader =
$"{_username}:{_password}"
|> Encoding.UTF8.GetBytes
|> System.Convert.ToBase64String
member this.getHeaders =
[ "Content-Type", "application/json"; "Authorization", this.authHeader ]
member this.apiRequest
(
resource: string,
httpRequestConfig: HttpRequestConfig
) : Async<Result<HttpResponse, HttpRequestError>> =
let url =
httpRequestConfig.url
|> Option.map (fun x -> $"{x}/{resource}")
|> Option.defaultValue $"{this.apiUrl}/{resource}"
let query = httpRequestConfig.query |> Option.defaultValue []
let httpMethod = httpRequestConfig.method |> Option.defaultValue "GET"
let body = httpRequestConfig.body |> Option.defaultValue (TextRequest "")
async {
try
let! res =
Http.AsyncRequest(
url,
headers = this.getHeaders,
query = query,
httpMethod = httpMethod,
body = body
)
return Ok res
with ex ->
printfn "%s" ex.Message
let response: HttpRequestError =
{ StatusCode = 0
Message = ex.Message
RequestConfig = httpRequestConfig }
return Error response
}
// === USAGE EXAMPLE ===
let client = Client(getCredentials args)
let requestConfig: HttpRequestConfig =
{ url = Some "https://dummyjson.com/users"
method = Some "POST"
query = Some [ ("Limit", "10"); ("Skip", "5") ]
body = None
headers = None
timeout = None }
let response = this.apiRequest ("users", requestConfig) |> Async.RunSynchronously
@zeejers
Copy link
Author

zeejers commented Jul 16, 2023

I wanted to take a stab at making a pattern for an F# client that simplified my API calls and provided a consistent response interface using Result. This is my work in progress.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment