Customization
OpenAPI and Swagger type providers generate one or several API client types (depending on the value of IgnoreControllerPrefix). Each provided API client is a subclass of ProvidedApiClientBase, so you can control and customize HTTP calls.
type ProvidedApiClientBase(httpClient: HttpClient) =
member val HttpClient = httpClient with get, set
abstract member Serialize: obj -> string
abstract member Deserialize: string * Type -> objThe snippet shows only the most important parts of ProvidedApiClientBase. The full source includes default Serialize and Deserialize implementations built on System.Text.Json.
Key features:
- You can provide your own
HttpClientinstance during API client construction and fully control request execution (if you do not provide one, the type provider creates a default instance). SerializeandDeserializeare abstract methods. If the defaultJsonSerializerOptionsdo not fit your needs, override them and configureSystem.Text.Jsonas required.
Request interception
Since you control HttpClient, you can use outgoing request middleware, implement your own DelegatingHandler, and intercept all HTTP requests generated by the provided API client.
open System
open System.Net.Http
open SwaggerProvider
let [<Literal>] Schema = "https://petstore.swagger.io/v2/swagger.json"
type PetStore = OpenApiClientProvider<Schema, PreferAsync=true>
type LoggingHandler(messageHandler) =
inherit DelegatingHandler(messageHandler)
override __.SendAsync(request, cancellationToken) =
// Put a breakpoint here if you want to debug HTTP calls
printfn "[%A]: %A" request.Method request.RequestUri
base.SendAsync(request, cancellationToken)
[<EntryPoint>]
let main argv =
let baseAddress = Uri("https://petstore.swagger.io/v2/")
let handler1 = new HttpClientHandler (UseCookies = false)
let handler2 = new LoggingHandler(handler1)
use httpClient = new HttpClient(handler2, true, BaseAddress=baseAddress)
let client = PetStore.Client(httpClient)
async {
let pet = PetStore.Pet(Id = Some(24L), Name = "Shani")
do! client.AddPet(pet)
let! myPet = client.GetPetById(24L)
printfn "Waw, my name is %A" myPet.Name
}
|> Async.RunSynchronously
0Authentication
Authentication is a special case of request interception. Your custom DelegatingHandler is fully responsible for authentication data management (attach an authorization header, add authentication cookies, invalidate tokens, etc.).
type AuthHandler(messageHandler) =
inherit DelegatingHandler(messageHandler)
override __.SendAsync(request, cancellationToken) =
// Invalidate your token if it expired
request.Headers.Authorization <-
Headers.AuthenticationHeaderValue("Bearer", "Your OAuth token");
base.SendAsync(request, cancellationToken)If your token does not require invalidation, you can use HttpClient.DefaultRequestHeaders to add the Authorization header to all requests.
let baseAddress = Uri("https://petstore.swagger.io/v2/")
let handler = new HttpClientHandler (UseCookies = false)
use httpClient = new HttpClient(handler, true, BaseAddress=baseAddress)
httpClient.DefaultRequestHeaders.Authorization <-
Headers.AuthenticationHeaderValue("Bearer", "Your OAuth token")
let client = PetStore.Client(httpClient)Serialization
Serialization is also flexible. Define your own API client type as a subclass of the generated API client and override Serialize and Deserialize.
INFO
The serializer is configurable but not replaceable! The Type provider emits types with JsonPropertyNameAttribute on properties for seamless serialization.
open System
open SwaggerProvider
open System.Text.Json
open System.Text.Json.Serialization
let [<Literal>] Schema = "https://petstore.swagger.io/v2/swagger.json"
type PetStore = OpenApiClientProvider<Schema, PreferAsync=true>
let jsonSerializerSettings =
// nuget: System.Text.Json
let settings = JsonSerializerOptions(
//PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
// ...
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
)
// nuget: FSharp.SystemTextJson
JsonFSharpOptions.Default().AddToJsonSerializerOptions settings
settings
type MyApiClient() =
// inherit from provided API client
inherit PetStore.Client()
// Override default implementation of Serialize & Deserialize
override __.Serialize(value:obj): string =
JsonSerializer.Serialize(value, jsonSerializerSettings)
override __.Deserialize(value, retTy:Type): obj =
JsonSerializer.Deserialize(value, retTy, jsonSerializerSettings)
[<EntryPoint>]
let main argv =
// Instantiate your API client
let client = MyApiClient()
async {
let pet = PetStore.Pet(Id = Some(24L), Name = "Shani")
do! client.AddPet(pet)
let! myPet = client.GetPetById(24L)
printfn "Waw, my name is %A" myPet.Name
}
|> Async.RunSynchronously
0