F# API #18
@ -3,16 +3,27 @@
|
|||||||
module MyPrayerJournal.Handlers
|
module MyPrayerJournal.Handlers
|
||||||
|
|
||||||
open Giraffe
|
open Giraffe
|
||||||
|
open System
|
||||||
|
|
||||||
/// Handle 404s from the API, sending known URL paths to the Vue app so that they can be handled there
|
module Error =
|
||||||
let notFound : HttpHandler =
|
|
||||||
fun next ctx ->
|
open Microsoft.Extensions.Logging
|
||||||
let vueApp () = htmlFile "/index.html" next ctx
|
|
||||||
match true with
|
/// Handle errors
|
||||||
| _ when ctx.Request.Path.Value.StartsWith "/answered" -> vueApp ()
|
let error (ex : Exception) (log : ILogger) =
|
||||||
| _ when ctx.Request.Path.Value.StartsWith "/journal" -> vueApp ()
|
log.LogError (EventId(), ex, "An unhandled exception has occurred while executing the request.")
|
||||||
| _ when ctx.Request.Path.Value.StartsWith "/user" -> vueApp ()
|
clearResponse >=> setStatusCode 500 >=> json ex.Message
|
||||||
| _ -> (setStatusCode 404 >=> json ([ "error", "not found" ] |> dict)) next ctx
|
|
||||||
|
/// Handle 404s from the API, sending known URL paths to the Vue app so that they can be handled there
|
||||||
|
let notFound : HttpHandler =
|
||||||
|
fun next ctx ->
|
||||||
|
let vueApp () = htmlFile "/index.html" next ctx
|
||||||
|
match true with
|
||||||
|
| _ when ctx.Request.Path.Value.StartsWith "/answered" -> vueApp ()
|
||||||
|
| _ when ctx.Request.Path.Value.StartsWith "/journal" -> vueApp ()
|
||||||
|
| _ when ctx.Request.Path.Value.StartsWith "/user" -> vueApp ()
|
||||||
|
| _ when ctx.Request.Path.Value = "/" -> vueApp ()
|
||||||
|
| _ -> (setStatusCode 404 >=> json ([ "error", "not found" ] |> dict)) next ctx
|
||||||
|
|
||||||
|
|
||||||
/// Handler helpers
|
/// Handler helpers
|
||||||
@ -20,7 +31,6 @@ let notFound : HttpHandler =
|
|||||||
module private Helpers =
|
module private Helpers =
|
||||||
|
|
||||||
open Microsoft.AspNetCore.Http
|
open Microsoft.AspNetCore.Http
|
||||||
open System
|
|
||||||
|
|
||||||
/// Get the database context from DI
|
/// Get the database context from DI
|
||||||
let db (ctx : HttpContext) =
|
let db (ctx : HttpContext) =
|
||||||
@ -80,7 +90,7 @@ module Journal =
|
|||||||
fun next ctx ->
|
fun next ctx ->
|
||||||
match user ctx with
|
match user ctx with
|
||||||
| Some u -> json ((db ctx).JournalByUserId u.Value) next ctx
|
| Some u -> json ((db ctx).JournalByUserId u.Value) next ctx
|
||||||
| None -> notFound next ctx
|
| None -> Error.notFound next ctx
|
||||||
|
|
||||||
|
|
||||||
/// /api/request URLs
|
/// /api/request URLs
|
||||||
@ -116,8 +126,8 @@ module Request =
|
|||||||
let! req = db.TryJournalById reqId u.Value
|
let! req = db.TryJournalById reqId u.Value
|
||||||
match req with
|
match req with
|
||||||
| Some rqst -> return! (setStatusCode 201 >=> json rqst) next ctx
|
| Some rqst -> return! (setStatusCode 201 >=> json rqst) next ctx
|
||||||
| None -> return! notFound next ctx
|
| None -> return! Error.notFound next ctx
|
||||||
| None -> return! notFound next ctx
|
| None -> return! Error.notFound next ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
/// POST /api/request/[req-id]/history
|
/// POST /api/request/[req-id]/history
|
||||||
@ -140,8 +150,8 @@ module Request =
|
|||||||
|> db.AddEntry
|
|> db.AddEntry
|
||||||
let! _ = db.SaveChangesAsync ()
|
let! _ = db.SaveChangesAsync ()
|
||||||
return! created next ctx
|
return! created next ctx
|
||||||
| None -> return! notFound next ctx
|
| None -> return! Error.notFound next ctx
|
||||||
| None -> return! notFound next ctx
|
| None -> return! Error.notFound next ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
/// POST /api/request/[req-id]/note
|
/// POST /api/request/[req-id]/note
|
||||||
@ -163,8 +173,8 @@ module Request =
|
|||||||
|> db.AddEntry
|
|> db.AddEntry
|
||||||
let! _ = db.SaveChangesAsync ()
|
let! _ = db.SaveChangesAsync ()
|
||||||
return! created next ctx
|
return! created next ctx
|
||||||
| None -> return! notFound next ctx
|
| None -> return! Error.notFound next ctx
|
||||||
| None -> return! notFound next ctx
|
| None -> return! Error.notFound next ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
/// GET /api/requests/answered
|
/// GET /api/requests/answered
|
||||||
@ -172,7 +182,7 @@ module Request =
|
|||||||
fun next ctx ->
|
fun next ctx ->
|
||||||
match user ctx with
|
match user ctx with
|
||||||
| Some u -> json ((db ctx).AnsweredRequests u.Value) next ctx
|
| Some u -> json ((db ctx).AnsweredRequests u.Value) next ctx
|
||||||
| None -> notFound next ctx
|
| None -> Error.notFound next ctx
|
||||||
|
|
||||||
/// GET /api/request/[req-id]
|
/// GET /api/request/[req-id]
|
||||||
let get reqId : HttpHandler =
|
let get reqId : HttpHandler =
|
||||||
@ -183,8 +193,8 @@ module Request =
|
|||||||
let! req = (db ctx).TryRequestById reqId u.Value
|
let! req = (db ctx).TryRequestById reqId u.Value
|
||||||
match req with
|
match req with
|
||||||
| Some r -> return! json r next ctx
|
| Some r -> return! json r next ctx
|
||||||
| None -> return! notFound next ctx
|
| None -> return! Error.notFound next ctx
|
||||||
| None -> return! notFound next ctx
|
| None -> return! Error.notFound next ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
/// GET /api/request/[req-id]/complete
|
/// GET /api/request/[req-id]/complete
|
||||||
@ -196,8 +206,8 @@ module Request =
|
|||||||
let! req = (db ctx).TryCompleteRequestById reqId u.Value
|
let! req = (db ctx).TryCompleteRequestById reqId u.Value
|
||||||
match req with
|
match req with
|
||||||
| Some r -> return! json r next ctx
|
| Some r -> return! json r next ctx
|
||||||
| None -> return! notFound next ctx
|
| None -> return! Error.notFound next ctx
|
||||||
| None -> return! notFound next ctx
|
| None -> return! Error.notFound next ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
/// GET /api/request/[req-id]/full
|
/// GET /api/request/[req-id]/full
|
||||||
@ -209,8 +219,8 @@ module Request =
|
|||||||
let! req = (db ctx).TryFullRequestById reqId u.Value
|
let! req = (db ctx).TryFullRequestById reqId u.Value
|
||||||
match req with
|
match req with
|
||||||
| Some r -> return! json r next ctx
|
| Some r -> return! json r next ctx
|
||||||
| None -> return! notFound next ctx
|
| None -> return! Error.notFound next ctx
|
||||||
| None -> return! notFound next ctx
|
| None -> return! Error.notFound next ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
/// GET /api/request/[req-id]/notes
|
/// GET /api/request/[req-id]/notes
|
||||||
@ -221,7 +231,7 @@ module Request =
|
|||||||
| Some u ->
|
| Some u ->
|
||||||
let! notes = (db ctx).NotesById reqId u.Value
|
let! notes = (db ctx).NotesById reqId u.Value
|
||||||
return! json notes next ctx
|
return! json notes next ctx
|
||||||
| None -> return! notFound next ctx
|
| None -> return! Error.notFound next ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
/// POST /api/request/[req-id]/snooze
|
/// POST /api/request/[req-id]/snooze
|
||||||
@ -239,6 +249,6 @@ module Request =
|
|||||||
|> db.UpdateEntry
|
|> db.UpdateEntry
|
||||||
let! _ = db.SaveChangesAsync ()
|
let! _ = db.SaveChangesAsync ()
|
||||||
return! setStatusCode 204 next ctx
|
return! setStatusCode 204 next ctx
|
||||||
| None -> return! notFound next ctx
|
| None -> return! Error.notFound next ctx
|
||||||
| None -> return! notFound next ctx
|
| None -> return! Error.notFound next ctx
|
||||||
}
|
}
|
||||||
|
@ -15,21 +15,26 @@ module Configure =
|
|||||||
open Giraffe.TokenRouter
|
open Giraffe.TokenRouter
|
||||||
open MyPrayerJournal
|
open MyPrayerJournal
|
||||||
|
|
||||||
|
/// Set up the configuration for the app
|
||||||
|
let configuration (ctx : WebHostBuilderContext) (cfg : IConfigurationBuilder) =
|
||||||
|
cfg.SetBasePath(ctx.HostingEnvironment.ContentRootPath)
|
||||||
|
.AddJsonFile("appsettings.json", optional = true, reloadOnChange = true)
|
||||||
|
.AddJsonFile(sprintf "appsettings.%s.json" ctx.HostingEnvironment.EnvironmentName, optional = true)
|
||||||
|
.AddEnvironmentVariables()
|
||||||
|
|> ignore
|
||||||
|
|
||||||
/// Configure dependency injection
|
/// Configure dependency injection
|
||||||
let services (sc : IServiceCollection) =
|
let services (sc : IServiceCollection) =
|
||||||
sc.AddAuthentication()
|
sc.AddAuthentication()
|
||||||
.AddJwtBearer ("Auth0",
|
.AddJwtBearer("Auth0",
|
||||||
fun opt ->
|
fun opt ->
|
||||||
opt.Audience <- "")
|
opt.Audience <- "")
|
||||||
|> ignore
|
|> ignore
|
||||||
()
|
()
|
||||||
|
|
||||||
/// Response that will load the Vue application to handle the given URL
|
|
||||||
let vueApp = fun next ctx -> htmlFile "/index.html" next ctx
|
|
||||||
|
|
||||||
/// Routes for the available URLs within myPrayerJournal
|
/// Routes for the available URLs within myPrayerJournal
|
||||||
let webApp =
|
let webApp =
|
||||||
router Handlers.notFound [
|
router Handlers.Error.notFound [
|
||||||
subRoute "/api/" [
|
subRoute "/api/" [
|
||||||
GET [
|
GET [
|
||||||
route "journal" Handlers.Journal.journal
|
route "journal" Handlers.Journal.journal
|
||||||
@ -55,31 +60,44 @@ module Configure =
|
|||||||
/// Configure the web application
|
/// Configure the web application
|
||||||
let application (app : IApplicationBuilder) =
|
let application (app : IApplicationBuilder) =
|
||||||
let env = app.ApplicationServices.GetService<IHostingEnvironment> ()
|
let env = app.ApplicationServices.GetService<IHostingEnvironment> ()
|
||||||
let log = app.ApplicationServices.GetService<ILoggerFactory> ()
|
|
||||||
match env.IsDevelopment () with
|
match env.IsDevelopment () with
|
||||||
| true ->
|
| true -> app.UseDeveloperExceptionPage ()
|
||||||
app.UseDeveloperExceptionPage () |> ignore
|
| false -> app.UseGiraffeErrorHandler Handlers.Error.error
|
||||||
| false ->
|
|> function
|
||||||
()
|
| a ->
|
||||||
|
a.UseAuthentication()
|
||||||
|
.UseStaticFiles()
|
||||||
|
.UseGiraffe webApp
|
||||||
|
|> ignore
|
||||||
|
|
||||||
app.UseAuthentication()
|
/// Configure logging
|
||||||
.UseStaticFiles()
|
let logging (log : ILoggingBuilder) =
|
||||||
.UseGiraffe webApp
|
let env = log.Services.BuildServiceProvider().GetService<IHostingEnvironment> ()
|
||||||
|
match env.IsDevelopment () with
|
||||||
|
| true -> log
|
||||||
|
| false -> log.AddFilter(fun l -> l > LogLevel.Information)
|
||||||
|
|> function l -> l.AddConsole().AddDebug()
|
||||||
|> ignore
|
|> ignore
|
||||||
|
|
||||||
|
|
||||||
module Program =
|
module Program =
|
||||||
|
|
||||||
|
open System.IO
|
||||||
|
|
||||||
let exitCode = 0
|
let exitCode = 0
|
||||||
|
|
||||||
let CreateWebHostBuilder args =
|
let CreateWebHostBuilder args =
|
||||||
WebHost
|
let contentRoot = Directory.GetCurrentDirectory ()
|
||||||
.CreateDefaultBuilder(args)
|
WebHostBuilder()
|
||||||
|
.UseKestrel()
|
||||||
|
.UseContentRoot(contentRoot)
|
||||||
|
.UseWebRoot(Path.Combine (contentRoot, "wwwroot"))
|
||||||
|
.ConfigureAppConfiguration(Action<WebHostBuilderContext, IConfigurationBuilder> Configure.configuration)
|
||||||
.ConfigureServices(Configure.services)
|
.ConfigureServices(Configure.services)
|
||||||
|
.ConfigureLogging(Configure.logging)
|
||||||
.Configure(Action<IApplicationBuilder> Configure.application)
|
.Configure(Action<IApplicationBuilder> Configure.application)
|
||||||
|
|
||||||
[<EntryPoint>]
|
[<EntryPoint>]
|
||||||
let main args =
|
let main args =
|
||||||
CreateWebHostBuilder(args).Build().Run()
|
CreateWebHostBuilder(args).Build().Run()
|
||||||
|
|
||||||
exitCode
|
exitCode
|
||||||
|
Loading…
Reference in New Issue
Block a user