-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathProgram.fs
140 lines (127 loc) · 7.09 KB
/
Program.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
module Examples.MinimalWebApp.Program
open FSharp.AspNetCore.Builder
open FsToolkit.ErrorHandling
open Microsoft.AspNetCore.Builder
open Microsoft.AspNetCore.Http
open Microsoft.AspNetCore.Mvc
open Microsoft.Extensions.DependencyInjection
open Microsoft.Extensions.Hosting
open Microsoft.Extensions.Logging
open ControllerHelpers
open Db
open Domain
open Dtos
open type StatusCodes
#nowarn "20" // Don't warn about unignored values.
type private Program = class end
let app configureBuilder =
webApp {
connectionString "SqlDb" SqlConnectionString
configurationValue "AppSettings:SqlCommandTimeout" SqlCommandTimeout
singleton Id.NewId
singleton typeof<IDataAccess> typeof<DataAccess>
logging (fun logging -> logging.AddConsole ())
services (fun services ->
services.AddEndpointsApiExplorer ()
services.AddSwaggerGen ())
buildWith configureBuilder
webApp (fun app ->
app.UseSwagger ()
app.UseSwaggerUI ())
get "/api/clowns" [
Status200OK, typeof<seq<Dtos.Get.Clown>>
Status500InternalServerError, typeof<ProblemDetails>
] (fun (logger : ILogger<Program>) (db : IDataAccess) ->
db.GetAll ()
|> AsyncResult.teeError (function
| Get.Many.DbExn e -> logger.LogError ("A database exception occurred when trying to get the clowns.", e)
| Get.Many.DbTimeout e -> logger.LogWarning ("A database timeout occurred when trying to get the clowns.", e))
|> AsyncResult.foldResult
(Seq.map Get.Clown.toDto >> Results.Ok)
(function
| Get.Many.DbExn _ -> Results.Problem "A database exception occurred."
| Get.Many.DbTimeout _ -> Results.Problem "A database timeout occurred.")
|> Async.StartAsTask
) (fun routeHandler ->
routeHandler.WithOpenApi (fun op -> op.Description <- "This endpoint gets clowns."; op)
routeHandler.AllowAnonymous ()
)
get "/api/clowns/{id}" [
Status200OK, typeof<Dtos.Get.Clown>
Status404NotFound, null
Status500InternalServerError, typeof<ProblemDetails>
] (fun (logger : ILogger<Program>) (db : IDataAccess) id ->
db.Get id
|> AsyncResult.teeError (function
| Get.One.NotFound -> ()
| Get.One.DbExn e -> logger.LogError ("A database exception occurred when trying to get the clown.", e)
| Get.One.DbTimeout e -> logger.LogWarning ("A database timeout occurred when trying to get the clown.", e))
|> AsyncResult.foldResult
(Get.Clown.toDto >> Results.Ok)
(function
| Get.One.NotFound -> Results.NotFound ()
| Get.One.DbExn _ -> Results.Problem "A database exception occurred."
| Get.One.DbTimeout _ -> Results.Problem "A database timeout occurred.")
|> Async.StartAsTask)
post "/api/clowns" [
Status201Created, typeof<Dtos.Get.Clown>
Status400BadRequest, typeof<ValidationProblemDetails>
Status409Conflict, typeof<string>
Status500InternalServerError, typeof<ProblemDetails>
] (fun (logger : ILogger<Program>) mkId (db : IDataAccess) clown ->
Create.Clown.toDomain (mkId ()) clown
|> AsyncResult.ofResult
|> AsyncResult.mapError ValidationErrors.ofList
|> AsyncResult.bind (db.Create >> AsyncResult.mapError IOError)
|> AsyncResult.teeError (function
| IOError (Create.DbExn e) -> logger.LogError ("A database exception occurred when trying to create the clown.", e)
| IOError (Create.DbTimeout e) -> logger.LogWarning ("A database timeout occurred when trying to create the clown.", e)
| IOError (Create.NameConflict _) | ValidationErrors _ -> ())
|> AsyncResult.foldResult
(Get.Clown.toDto >> fun clown -> Results.Created ($"/api/clowns/{clown.Id}", clown))
(function
| ValidationErrors es -> Results.ValidationProblem es
| IOError (Create.NameConflict existingId) -> Results.Conflict ($"There is an existing clown with ID {existingId} with the same name.")
| IOError (Create.DbExn _) -> Results.Problem "A database exception occurred."
| IOError (Create.DbTimeout _) -> Results.Problem "A database timeout occurred.")
|> Async.StartAsTask)
put "/api/clowns/{id}" [
Status200OK, typeof<Dtos.Get.Clown>
Status400BadRequest, typeof<ValidationProblemDetails>
Status404NotFound, null
Status409Conflict, typeof<string>
Status500InternalServerError, typeof<ProblemDetails>
] (fun (logger : ILogger<Program>) (db : IDataAccess) id clown ->
Update.Clown.toDomain id clown
|> AsyncResult.ofResult
|> AsyncResult.mapError ValidationErrors.ofList
|> AsyncResult.bind (db.Update >> AsyncResult.mapError IOError)
|> AsyncResult.teeError (function
| IOError (Update.DbExn e) -> logger.LogError ("A database exception occurred when trying to update the clown.", e)
| IOError (Update.DbTimeout e) -> logger.LogWarning ("A database timeout occurred when trying to update the clown.", e)
| IOError Update.NotFound | IOError (Update.NameConflict _) | ValidationErrors _ -> ())
|> AsyncResult.foldResult
(Get.Clown.toDto >> Results.Ok)
(function
| ValidationErrors es -> Results.ValidationProblem es
| IOError Update.NotFound -> Results.NotFound ()
| IOError (Update.NameConflict existingId) -> Results.Conflict ($"There is an existing clown with ID {existingId} with the same name.")
| IOError (Update.DbExn _) -> Results.Problem "A database exception occurred."
| IOError (Update.DbTimeout _) -> Results.Problem "A database timeout occurred.")
|> Async.StartAsTask)
delete "/api/clowns/{id}" [
Status204NoContent, null
Status500InternalServerError, typeof<ProblemDetails>
] (fun (logger : ILogger<Program>) (db : IDataAccess) id ->
db.Delete id
|> AsyncResult.teeError (function
| Delete.DbExn e -> logger.LogError ("A database exception occurred when trying to delete the clown.", e)
| Delete.DbTimeout e -> logger.LogWarning ("A database timeout occurred when trying to delete the clown.", e))
|> AsyncResult.foldResult
Results.NoContent
(function
| Delete.DbExn _ -> Results.Problem "A database exception occurred."
| Delete.DbTimeout _ -> Results.Problem "A database timeout occurred.")
|> Async.StartAsTask)
}
(app ignore).Run ()