I am trying to learn F# by creating an F# application with a repository to fetch Exercises for a future Gym-application.
I use SqlServer to store the data and am fetching the data using Fsharp.Data.Sql. The unit tests for this work well.
I am trying to expose the data through a web api using Giraffe, the problem is that i get back a list with the correct length but with empty objects inside.
Here is the context:
module Context
open FSharp.Data.Sql
let [<Literal>] dbVendor = Common.DatabaseProviderTypes.MSSQLSERVER
let [<Literal>] connectionString = "Server=DESKTOP-20JMHNK;Database=GymStrongDB;Trusted_Connection=True;"
let [<Literal>] indivAmount = 1000
let [<Literal>] useOptTypes = true
let [<Literal>] owner = "public, admin, references"
type sql =
SqlDataProvider<
dbVendor,
connectionString,
"",
"",
indivAmount,
useOptTypes,
owner>
let gymStrongContext = sql.GetDataContext()
Here is the Repository
namespace GymStrong.Repositories
open ...
module ExerciseRepository =
let ctx = gymStrongContext.Dbo
let getExercises =
ctx.Exercises |> Seq.toList
let getExercisesHandler : HttpHandler =
fun (next : HttpFunc) (ctx : HttpContext) ->
Successful.OK getExercises next ctx
And here is the relevant part from Program.fs
open ...
let webApp =
choose [
GET >=>
choose [
route "/" >=> text "Hello World"
route "/user" >=> mustBeLoggedIn >=> getLoggedInUser
route "/logout" >=> mustBeLoggedIn >=> logoutHandler
route "/exercises" >=> mustBeLoggedIn >=> getExercisesHandler
]
POST >=>
choose [
route "/register" >=> registerHandler
route "/login" >=> loginHandler
]
]
In the unit-tests, this works properly. The unit tests are written in C#.
When i consume the API through PostMan i get this response
[{},{}]
Which has the correct length since i have two exercises in the database, but the objects seem empty.
This might be useful to someone, so i will post it.
Both Giraffe and SqlDataProvider are doing what they should. The problem was that i thought that i could pass the provided type as a json-response in the API. That is wrong since the provided types are not real types and are "erased" (instead of Generated which is the type that i thought i was working with).
In order to fix this, i needed to map out the values to a "real" anemic DTO object and pass it as a response. Now i need to figure out if one can provide these anemic DTO-objects based on the entityTypes and have them be generated and usable from other assemblies.
Additional code:
In the repository/service
type exerciseDto = {
Id : string;
Name : string;
Description : string;
Owner : string;
Type : int;
}
let getExercises =
ctx.Exercises |> Seq.map(fun exercise -> exercise.MapTo<exerciseDto>()) |> Seq.toList
And in program.cs
let handlerWrapper action : HttpHandler =
fun (next : HttpFunc) (ctxHttp : HttpContext) ->
Successful.OK action next ctxHttp
let webApp =
choose [
GET >=>
choose [
route "/" >=> text "Hello World"
route "/user" >=> mustBeLoggedIn >=> getLoggedInUser
route "/logout" >=> mustBeLoggedIn >=> logoutHandler
route "/exercises" >=> mustBeLoggedIn >=> handlerWrapper getExercises
]
POST >=>
choose [
route "/register" >=> registerHandler
route "/login" >=> loginHandler
]
]
Hope this helps anyone save time in the future. It took me at least a few hours.