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

F# centric controller API #278

Closed
Alxandr opened this issue Apr 7, 2017 · 7 comments
Closed

F# centric controller API #278

Alxandr opened this issue Apr 7, 2017 · 7 comments
Labels

Comments

@Alxandr
Copy link

Alxandr commented Apr 7, 2017

Not strictly a blog question, but still feel it relates to the previous "issue" I opened, and that this is as good a communication channel as any (especially wrt that you can add code). Since you've obviously worked a good bunch with Web API and F#, and have made practices and found challenges, if you could imagine a F# first controller API, how would it look like? Basically, I'm asking how would you like to define your controllers (if you could)?

Currently my thinking for the "ultimate" controller goes something like this (note, I don't remember the correct attribute names, but it should be enough to paint the picture):

[<Controller; PathPrefix("/users")>]
module MyCtrls

[<HttpGet>]
let getUsers = (userService: UserService) () =
  Ok <| UserService.getUsers userService

[<HttpGet; Path("{id}")>]
let getUser = (userService: UserService) (id: int) =
  match UserService.findUser id userService with
  | None   -> NotFound
  | Some u -> Ok u

In this case, a "controller" (in the Web API/MVC sense) is a simple F# function taking two tuples. The first one is the DI arguments, the second one is model binding arguments. In cases where you would need access to the request body (or similar) I would return a HttpRequestMessage -> Async<MyResponseType> by way of a custom computational expression ala

[<HttpGet>]
let echo = () () = handler {
  let! body = Request.getBody
  return Raw body
}

or something like that. handler here is basically a combination of the state monad (holding the HttpContext), and the async monad, allowing you to use let! on both custom functions like the getBody above that operates on the state, as well as on Async values (for seamless API interop). What do you think? Do you have any suggestions? Improvements?

@Alxandr
Copy link
Author

Alxandr commented Apr 7, 2017

Oh, and BTW; if you have any good ideas on how to get a broader discussion on this, that'd too be awesome. I'm looking at implementing a "controller layer" or similar for F# in the new MvcCore, which will mostly be convenience stuff, but I need to land on an API first.

@ploeh
Copy link
Owner

ploeh commented Apr 19, 2017

I haven't given the topic that much thought, because I'm not about to develop a web library anyway.

At the highest level, I think about HTTP requests as essentially being a function that takes an HTTP request and returns an HTTP response; something like this: HttpRequest -> HttpResponse.

In order to develop a web app, one would have to supply a function with that type.

Routing, and so on, could be handled with active patterns, like this:

let respond = function
    | Post (Route "foo" ()) -> postFoo ()
    | Get (Route "foo/{id}" id) -> getFoo id
    | _ -> notFound

I'm not too fond of using attributes for those kinds of things, as they aren't programmable. They also strongly suggest that the web stack in question is a framework instead of a library, and I agree with Tomas Petricek that frameworks are evil.

I haven't looked much into Freya, but what little I've seen, it has an interesting programming model.

@ploeh ploeh added the question label Apr 19, 2017
@Alxandr
Copy link
Author

Alxandr commented Apr 20, 2017

To some point I agree with you, but the point here is a rather thin "bridge" between MVC/WebAPI and F#, making them easier to use while still keeping the features and ability to use libraries written for them. In other words it should not need a new ecosystem. Also, how would you create API documentation if your routes can only be analyzed testing them with all different URLs?

@ploeh
Copy link
Owner

ploeh commented Apr 22, 2017

Sorry, I misunderstood. Something like what you propose could work out fine for ASP.NET Web API. A module with functions that handle each type of request sounds good.

Regarding documentation, I write it by hand. I've yet to find a good way to automate such work for REST APIs, which is what I normally develop.

@Alxandr
Copy link
Author

Alxandr commented Apr 22, 2017

I would like it to work with Swashbuckle (and in general, it should support any filter attribute supported by AspNetCore.Mvc).

@ploeh
Copy link
Owner

ploeh commented Jun 29, 2017

Closing due to inactivity.

@ploeh ploeh closed this as completed Jun 29, 2017
@Alxandr
Copy link
Author

Alxandr commented Jun 29, 2017

Yep. That's fine. I'm also currently waiting for F# to work propperly with netcore 2.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants