Last active
August 29, 2015 14:13
-
-
Save ToJans/838903975aa2e9baf001 to your computer and use it in GitHub Desktop.
my ideal F# web framework; a brain dump
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hmmz this might not compile probably; I'm assuming I'm mixing up both Haskell and F# concepts...