Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update remoting to latest, docs for client #118

Merged
merged 7 commits into from
Jul 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Content/build.fsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ let npmTool = platformTool "npm" "npm.cmd"
let yarnTool = platformTool "yarn" "yarn.cmd"
//#endif

let install = lazy DotNet.install DotNet.Release_2_1_300
let install = lazy DotNet.install DotNet.Versions.Release_2_1_300

let inline withWorkDir wd =
DotNet.Options.lift install.Value
Expand Down Expand Up @@ -221,7 +221,8 @@ open Fake.Core.TargetOperators
==> "AppService"
//#endif

"InstallClient"
"Clean"
==> "InstallClient"
==> "RestoreServer"
==> "Run"

Expand Down
8 changes: 3 additions & 5 deletions Content/paket.dependencies
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,9 @@ group Server
//#if (!remoting && server != "suave")
nuget Fable.JsonConverter
//#elseif (remoting && server == "suave")
nuget Fable.Remoting.Server ~> 3.6
nuget Fable.Remoting.Suave ~> 2.7
nuget Fable.Remoting.Suave
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shall we float pin to a major version?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could, but it is not necessary afaik

//#elseif (remoting && server != "suave")
nuget Fable.Remoting.Server ~> 3.6
nuget Fable.Remoting.Giraffe ~> 2.7
nuget Fable.Remoting.Giraffe
//#endif
//#if (deploy == "azure")
nuget Microsoft.ApplicationInsights.AspNetCore ~> 2.2
Expand All @@ -35,7 +33,7 @@ group Client
nuget Fable.Elmish.React
nuget Fable.Elmish.HMR
//#if (remoting)
nuget Fable.Remoting.Client ~> 2.5.1
nuget Fable.Remoting.Client
//#endif
//#if (layout != "none")
nuget Fulma
Expand Down
68 changes: 42 additions & 26 deletions Content/src/Client/Client.fs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,18 @@ open Fulma
open Fulma.FontAwesome
#endif

type Model = Counter option

// The model holds data that you want to keep track of while the application is running
// in this case, we are keeping track of a counter
// we mark it as optional, because initially it will not be available from the client
// the initial value will be requested from server
type Model = { Counter: Counter option }

// The Msg type defines what events/actions can occur while the application is running
// the state of the application changes *only* in reaction to these events
type Msg =
| Increment
| Decrement
| Init of Result<Counter, exn>
| InitialCountLoaded of Result<Counter, exn>


#if (remoting)
Expand All @@ -32,39 +38,49 @@ module Server =
open Fable.Remoting.Client

/// A proxy you can use to talk to server directly
let api : ICounterProtocol =
Proxy.remoting<ICounterProtocol> {
use_route_builder Route.builder
}
let api : ICounterApi =
Remoting.createApi()
|> Remoting.withRouteBuilder Route.builder
|> Remoting.buildProxy<ICounterApi>()

#endif

// defines the initial state and initial command (= side-effect) of the application
let init () : Model * Cmd<Msg> =
let model = None
let cmd =
let initialModel = { Counter = None }
let loadCountCmd =
#if remoting
Cmd.ofAsync
Server.api.getInitCounter
Server.api.initialCounter
()
(Ok >> Init)
(Error >> Init)
(Ok >> InitialCountLoaded)
(Error >> InitialCountLoaded)
#else
Cmd.ofPromise
(fetchAs<int> "/api/init")
[]
(Ok >> Init)
(Error >> Init)
(Ok >> InitialCountLoaded)
(Error >> InitialCountLoaded)
#endif
model, cmd

let update (msg : Msg) (model : Model) : Model * Cmd<Msg> =
let model' =
match model, msg with
| Some x, Increment -> Some (x + 1)
| Some x, Decrement -> Some (x - 1)
| None, Init (Ok x) -> Some x
| _ -> None
model', Cmd.none
initialModel, loadCountCmd

// The update function computes the next state of the application based on the current state and the incoming events/messages
// It can also run side-effects (encoded as commands) like calling the server via Http.
// these commands in turn, can dispatch messages to which the update function will react.
let update (msg : Msg) (currentModel : Model) : Model * Cmd<Msg> =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I prefer the shorter 6-line version
I'll merge it but revert this change afterrwards

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, it was just my personal preference to do it this way 👌

match currentModel.Counter, msg with
| Some x, Increment ->
let nextModel = { currentModel with Counter = Some (x + 1) }
nextModel, Cmd.none
| Some x, Decrement ->
let nextModel = { currentModel with Counter = Some (x - 1) }
nextModel, Cmd.none
| _, InitialCountLoaded (Ok initialCount)->
let nextModel = { Counter = Some initialCount }
nextModel, Cmd.none

| _ -> currentModel, Cmd.none


let safeComponents =
let intersperse sep ls =
Expand Down Expand Up @@ -103,8 +119,8 @@ let safeComponents =
components ]

let show = function
| Some x -> string x
| None -> "Loading..."
| { Counter = Some x } -> string x
| { Counter = None } -> "Loading..."

#if (layout == "none")
let view (model : Model) (dispatch : Msg -> unit) =
Expand Down
22 changes: 13 additions & 9 deletions Content/src/Server/ServerGiraffe.fs
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,20 @@ let publicPath = Path.GetFullPath "../Client/public"
let port = 8085us

let getInitCounter () : Task<Counter> = task { return 42 }

let webApp : HttpHandler =
#if (remoting)
let counterProcotol =
{ getInitCounter = getInitCounter >> Async.AwaitTask }
// creates a HttpHandler for the given implementation
remoting counterProcotol {
use_route_builder Route.builder
}

let counterApi = {
initialCounter = getInitCounter >> Async.AwaitTask
}

let webApp =
Remoting.createApi()
|> Remoting.withRouteBuilder Route.builder
|> Remoting.fromValue counterApi
|> Remoting.buildHttpHandler

#else
let webApp =
route "/api/init" >=>
fun next ctx ->
task {
Expand All @@ -48,7 +52,7 @@ let webApp : HttpHandler =
}
#endif

let configureApp (app : IApplicationBuilder) =
let configureApp (app : IApplicationBuilder) =
app.UseDefaultFiles()
.UseStaticFiles()
.UseGiraffe webApp
Expand Down
22 changes: 10 additions & 12 deletions Content/src/Server/ServerSaturn.fs
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,18 @@ let publicPath = Path.GetFullPath "../Client/public"
//#endif
let port = 8085us

let getInitCounter () : Task<Counter> = task { return 42 }
let getInitCounter() : Task<Counter> = task { return 42 }

#if (remoting)
let counterApi = {
initialCounter = getInitCounter >> Async.AwaitTask
}

let webApp =
let server =
{ getInitCounter = getInitCounter >> Async.AwaitTask }
remoting server {
use_route_builder Route.builder
}
Remoting.createApi()
|> Remoting.withRouteBuilder Route.builder
|> Remoting.fromValue counterApi
|> Remoting.buildHttpHandler

#else
let webApp = scope {
Expand Down Expand Up @@ -62,7 +65,7 @@ let configureAzure (services:IServiceCollection) =
#endif
let app = application {
url ("http://0.0.0.0:" + port.ToString() + "/")
router webApp
use_router webApp
memory_cache
use_static publicPath
#if (!remoting)
Expand All @@ -71,11 +74,6 @@ let app = application {
#if (deploy == "azure")
service_config configureAzure
#endif
#if (remoting)
// sitemap diagnostic data cannot be inferred when using Fable.Remoting
// Saturn issue at https://github.com/SaturnFramework/Saturn/issues/64
disable_diagnostics
#endif
use_gzip
}

Expand Down
34 changes: 19 additions & 15 deletions Content/src/Server/ServerSuave.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
open System.Net

open Suave
open Suave.Files
open Suave.Successful
open Suave.Filters
open Suave.Operators

open Shared
Expand All @@ -28,31 +31,32 @@ let config =
homeFolder = Some publicPath
bindings = [ HttpBinding.create HTTP (IPAddress.Parse "0.0.0.0") port ] }

let getInitCounter () : Async<Counter> = async { return 42 }

let webApi : WebPart =
let getInitCounter() : Async<Counter> = async { return 42 }
#if (remoting)
let counterProcotol =
{ getInitCounter = getInitCounter }
// Create a WebPart for the given implementation of the protocol
remoting counterProcotol {
// define how routes are mapped
use_route_builder Route.builder
}
let counterApi = {
initialCounter = getInitCounter
}

let webApi =
Remoting.createApi()
|> Remoting.withRouteBuilder Route.builder
|> Remoting.fromValue counterApi
|> Remoting.buildWebPart
#else
Filters.path "/api/init" >=>
let webApi =
path "/api/init" >=>
fun ctx ->
async {
let! counter = getInitCounter()
return! Successful.OK (string counter) ctx
return! OK (string counter) ctx
}
#endif

let webApp =
choose [
webApi
Filters.path "/" >=> Files.browseFileHome "index.html"
Files.browseHome
path "/" >=> browseFileHome "index.html"
browseHome
RequestErrors.NOT_FOUND "Not found!"
#if (deploy == "azure")
] |> Azure.AI.withAppInsights Azure.AI.buildApiOperationName
Expand All @@ -65,4 +69,4 @@ Azure.tryGetEnv "APPINSIGHTS_INSTRUMENTATIONKEY"
]
#endif

startWebServer config webApp
startWebServer config webApp
9 changes: 4 additions & 5 deletions Content/src/Shared/Shared.fs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ module Route =
let builder typeName methodName =
sprintf "/api/%s/%s" typeName methodName

/// A type that specifies the communication protocol for client and server
/// Every record field must have the type : 'a -> Async<'b> where 'a can also be `unit`
/// Add more such fields, implement them on the server and they be directly available on client
type ICounterProtocol =
{ getInitCounter : unit -> Async<Counter> }
/// A type that specifies the communication protocol between client and server
/// to learn more, read the docs at https://zaid-ajaj.github.io/Fable.Remoting/src/basics.html
type ICounterApi =
{ initialCounter : unit -> Async<Counter> }
#endif