F# Guide — HTTP: Making Web Requests
In this tutorial, you will learn about F# Guide. We cover key concepts, practical examples, and best practices to help you master this topic.
F# HTTP programming uses .NET's HttpClient for modern async HTTP operations and FSharp.Data HTTP utilities for simpler request-response patterns with JSON integration.
What You'll Learn
- Using HttpClient in F#
- Async HTTP requests
- JSON API integration
- Authentication and headers
- Error handling for HTTP
Why It Matters
HTTP is the foundation of web API communication. Durga Antivirus Pro uses HTTP for cloud signature updates and API integration.
Real-World Use
REST API clients, web scraping, microservice communication, and cloud service integration.
flowchart LR
A["HTTP"] --> B["HttpClient"]
B --> C["Async Requests"]
C --> D["JSON APIs"]
D --> E["Error Handling"]
A:::current --> B
style A fill:#2563eb,stroke:#2563eb,color:#fff
style B fill:#dbeafe,stroke:#2563eb,color:#1e40af
style C fill:#dbeafe,stroke:#2563eb,color:#1e40af
style D fill:#dbeafe,stroke:#2563eb,color:#1e40af
style E fill:#f1f5f9,stroke:#94a3b8,color:#64748b
Basic HttpClient
open System.Net.Http
let httpClient = new HttpClient()
let getString url = task {
let! response = httpClient.GetStringAsync(url)
return response
}
// Usage
let html = getString "http://example.com" |> Async.AwaitTask |> Async.RunSynchronously
Async HTTP with FSharp.Data
open FSharp.Data
// Simple HTTP request
let html = Http.RequestString("http://example.com")
// With headers
let result = Http.RequestString(
"http://api.example.com/data",
headers = ["Authorization", "Bearer token"],
httpMethod = "GET"
)
POST Requests
open System.Net.Http
open System.Text
let postJson url jsonContent = task {
let content = new StringContent(jsonContent, Encoding.UTF8, "application/json")
let! response = httpClient.PostAsync(url, content)
let! responseBody = response.Content.ReadAsStringAsync()
return responseBody
}
// Usage
let response = postJson "http://api.example.com/users" """{"name":"Alice","email":"a@example.com"}"""
HTTP with FSharp.Data
open FSharp.Data
// GET with JSON response
let weather = Http.RequestString("https://api.weather.gov/points/45.52,-122.68",
headers = ["User-Agent", "F# App"])
)
// POST with JSON
let postResult = Http.Request(
"http://api.example.com/users",
body = TextRequest """{"name":"Alice"}""",
httpMethod = "POST",
headers = ["Content-Type", "application/json"]
)
Authentication
// Basic auth
let basicAuth username password =
let credentials = sprintf "%s:%s" username password
let encoded = System.Convert.ToBase64String(Encoding.UTF8.GetBytes(credentials))
sprintf "Basic %s" encoded
let requestWithAuth = task {
httpClient.DefaultRequestHeaders.Authorization <-
System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", "mytoken")
let! response = httpClient.GetStringAsync("http://api.example.com/protected")
return response
}
Error Handling
let safeHttpGet url = task {
try
let! response = httpClient.GetAsync(url)
if response.IsSuccessStatusCode then
let! content = response.Content.ReadAsStringAsync()
return Ok content
else
return Error (sprintf "HTTP %d: %s" (int response.StatusCode) response.ReasonPhrase)
with
| :? HttpRequestException as ex ->
return Error (sprintf "Request failed: %s" ex.Message)
| :? TaskCanceledException ->
return Error "Request timed out"
}
Common Mistakes
1. Not disposing HttpClient
Create and dispose HttpClient properly. Use use client = new HttpClient() or reuse a single instance.
2. Blocking on async calls
Calling .Result or .Wait() blocks threads. Use let! in async/task CEs.
3. Ignoring status codes
Always check response.IsSuccessStatusCode before reading content.
4. No timeout handling
Set a timeout: httpClient.Timeout <- TimeSpan.FromSeconds(30).
5. Not handling network errors
Network failures throw exceptions. Always wrap HTTP calls in try-with.
Practice Questions
1. How do you make a GET request in F#?
Use HttpClient.GetStringAsync or Http.RequestString from FSharp.Data.
2. How do you send JSON in a POST request?
Create a StringContent with JSON string and application/json content type.
3. How do you add authentication headers?
Set httpClient.DefaultRequestHeaders.Authorization or pass headers in the request.
Challenge: Write an async function that fetches data from a paginated API and returns all results.
FAQ
{{< faq question="Should I use HttpClient or FSharp.Data.Http?" >} HttpClient is the modern standard with full async support. FSharp.Data.Http is simpler for quick scripts. {{< /faq >}}
{{< faq question="How do I handle redirects?" >}
HttpClient follows redirects by default. Disable with Handler.AllowAutoRedirect = false if needed.
{{< /faq >}}
{{< faq question="Can I download files with HTTP?" >}
Yes. Use httpClient.GetByteArrayAsync for binary data or httpClient.GetStreamAsync for streaming.
{{< /faq >}}
{{< faq question="How do I set custom headers?" >} Set on DefaultRequestHeaders for all requests or pass per-request headers with HttpRequestMessage. {{< /faq >}}
{{< faq question="Is there a way to mock HTTP in tests?" >}
Yes. Use HttpClient with a mock HttpMessageHandler for Unit Testing.
{{< /faq >}}
Mini Project
Build a GitHub API client:
open System.Net.Http
open System.Text.Json
type GitHubUser = { login: string; name: string; public_repos: int }
let client = new HttpClient()
client.DefaultRequestHeaders.UserAgent.ParseAdd("FSharp-App")
let getUser username = task {
let! json = client.GetStringAsync($"https://api.github.com/users/{username}")
let user = JsonSerializer.Deserialize<GitHubUser>(json)
return user
}
// Usage
let user = getUser "dotnet" |> Async.AwaitTask |> Async.RunSynchronously
printfn "%s has %d repos" user.name user.public_repos
What's Next
Now that you understand HTTP clients, explore unit testing in F#.
| Topic | Description | Link |
|---|---|---|
| F# Testing | Unit testing | {{< ref "26-testing" >}} |
| F# .NET Interop | C# interop | {{< ref "27-net-interop" >}} |
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro