F#: Accessing ASP.NET WebAPI

Intro

In this post, I document my understanding of how an F# client can interface with ASP.Net Web API.

Web API (aka: The Server)

The following is my controller:

namespace FnTrade.Server.Controllers
open System
open System.Collections.Generic
open System.Linq
open System.Net.Http
open System.Web.Http
open FnTrade.Server.Models

type TransactionController() =
    inherit ApiController()

    let values = [| { AccountId = "Bizmonger"; Symbol = "TSLA"; Qty = 5  }
                    { AccountId = "Bizmonger"; Symbol = "MSFT"; Qty = 10 }
                    { AccountId = "Scarface" ; Symbol = "ROK" ; Qty = 2  } |]

    member x.Post (shares:Shares) = x.Ok shares

    member x.Get() = values

    member x.Get (id:string) = 
        values |> Array.filter (fun x -> x.AccountId.ToLower() = id.ToLower())

The following is the entity that my controller will work with:

namespace FnTrade.Server.Models

open Newtonsoft.Json

[<CLIMutable>]
type Shares = { 
    AccountId : string
    Symbol    : string
    Qty       : int 
}

C# Style (Old School)

The following would represent the type that I would need to deserialize to:

type Share = { 
    AccountId : string
    Symbol    : string
    Qty       : int 
}

C# is the old school way of accessing data from a REST service.

The following code demonstrates the legacy technique of a Read All:

[<Test>]
let ``WebAPI call for everything`` () =
    
    let client = new HttpClient()
    client.BaseAddress <- Uri("http://localhost:48213/");
    client.DefaultRequestHeaders.Accept.Add(MediaTypeWithQualityHeaderValue("application/json"));

    let response = client.GetAsync("api/transaction").Result;
    if response.IsSuccessStatusCode
    then let result = response.Content.ReadAsStringAsync().Result
         let share = JsonConvert.DeserializeObject<seq<Share>>(result);
         ()
    else failwith "Something bad happened"

The following code demonstrates the legacy technique for accessing data using an argument:

[<Test>]
let ``WebAPI call with argument`` () =
    
    let client = new HttpClient()
    client.BaseAddress <- Uri("http://localhost:48213/");
    client.DefaultRequestHeaders.Accept.Add(MediaTypeWithQualityHeaderValue("application/json"));

    let response = client.GetAsync("api/transaction/bizmonger").Result; // Appended argument
    if response.IsSuccessStatusCode
    then let result = response.Content.ReadAsStringAsync().Result
         let share = JsonConvert.DeserializeObject<seq<Share>>(result);
         ()
    else failwith "Something bad happened"

Type Provider (New School)

F#’s Type Provider is the “cool way” to interface with ASP.NET Web API.

The following is the “cool way” to perform a Read-All:

[<Test>]
let ``Type Provider call for everything`` () =

    Repository.Load "http://localhost:48213/api/transaction"
    |> Array.toList
    |> List.map(fun x -> { AccountId= x.AccountId
                           Symbol=    x.Symbol
                           Qty=       x.Qty })

    |> should equal [{ AccountId = "Bizmonger"; Symbol = "TSLA"; Qty = 5  }
                     { AccountId = "Bizmonger"; Symbol = "MSFT"; Qty = 10 }
                     { AccountId = "Scarface" ; Symbol = "ROK" ; Qty = 2  }]

The following is the “cool way” to perform a Read when supplying an argument:

[<Test>]
let ``Type Provider call with argument`` () =

    let accountId = "bizmonger"
    Repository.Load (sprintf "%s%s" "http://localhost:48213/api/transaction/" accountId)
    |> Array.toList
    |> List.map(fun x -> { AccountId= x.AccountId
                           Symbol=    x.Symbol
                           Qty=       x.Qty })

    |> should equal <| [{ AccountId = "Bizmonger"; Symbol = "TSLA"; Qty = 5  }
                        { AccountId = "Bizmonger"; Symbol = "MSFT"; Qty = 10 }]

Unfortunately, I did not find a “cool way” to post data to a REST server

[<Test>]
let ``WebAPI post`` () =

    let entity = { AccountId = "Bizmonger"; Symbol = "TSLA"; Qty = 5 }
    let json = JsonConvert.SerializeObject(entity)
    let content = new StringContent(json)
    content.Headers.ContentType <- new MediaTypeHeaderValue("application/json")
    
    let client = new HttpClient()
    client.BaseAddress <- Uri("http://localhost:48213/api/");
    let response = client.PostAsync("Transaction", content).Result;
    
    response.IsSuccessStatusCode |> should equal true
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s