Skip to content

Instantly share code, notes, and snippets.

@ToJans
Last active August 29, 2015 14:13
Show Gist options
  • Save ToJans/838903975aa2e9baf001 to your computer and use it in GitHub Desktop.
Save ToJans/838903975aa2e9baf001 to your computer and use it in GitHub Desktop.
my ideal F# web framework; a brain dump
// these series of types define the api of the app
type Command =
| Add of CreateNewTodo
| Clear
| Delete of Guid
| Update of Guid * PatchTodo
}
and Query =
| Get of Guid
| List
and Request =
| Command of Command
| Query of Query
and CreateNewTodo = {
Title:string
Order: int option
}
and PatchTodo = {
Title: string option
Order: int option
Completed: int option
}
// create some kind of builder for the routing...
// this would map the httprequest to the types and parse extra request data etc (can be lazy)
// no idea how this would work
let todoRoutes = route {
match Http.verb(request),Http.pathSegments(request) with
| Http.Get, ["todo",id] -> return! Query Get id
| Http.Get, ["todo"] -> return! Query List
| Http.Delete,["todo"] -> return! Command Clear
| Http.Post, ["todo"] -> return! Command Add Http.parse<CreateNewTodo>(request)
| Http.Put, ["todo",id] -> return! Command Update id Http.parse<PatchTodo>(request)
| Http.Delete,["todo",id] -> return! Command Delete id
| _ -> // What should I return here? Don't want to wrap all other statements with a `Some`
}
/// the type itself
type Todo = {
Id: Guid
Url: string
Order: int option
Title: string
Completed: bool
}
let newTodoFromCommand (x: CreateNewTodo) =
let id = Guid.NewGuid ()
{ Id = id
Url = sprintf "http://localhost:7000/%A" id
Order = x.Order
Title = x.Title
Completed = false }
let initialstate = new Map<Guid, Todo>
let freyaHandler = new FreyaHandler(initialstate,todoRoutes)
// this computation expression would contain a `state` and `command`
// if there is no valid command it shouldn't be invoked
// returns a tuple containing the new state and the result.
// handling would be async by default
freyaHandler {
return! match input with
| Command Add createNewTodo ->
let newtodo = newTodoFromCommand createNewTodo
(Map.add newtodo.id newtodo state,newtodo)
| Command Clear ->
(Map.empty state,())
| Commmand Delete id ->
(Map.remove id state,())
| Command Update id (patchTodo: PatchTodo) ->
let maybefold folder option state = Option.fold folder state option
let changedTodo =
Map.find id state
|> maybefold (fun state value -> {state with Title = value}) patchTodo.Title
|> maybefold (fun state value -> {state with Order = value}) patchTodo.Order
|> maybefold (fun state value -> {state with Completed = value}) patchTodo.Completed
(Map.add id changedTodo state, changedTodo)
| Query Get id -> (state, Map.tryFind id state)
| Query List -> (state, Map.toList state)
}
@ToJans
Copy link
Author

ToJans commented Jan 15, 2015

Hmmz this might not compile probably; I'm assuming I'm mixing up both Haskell and F# concepts...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment