Closed gambogi closed 9 years ago
For templating, Shakespeare worked pretty well. It's not to hard to run it from behind servant, but we could also run it on a separate server easily (I think that was the original idea).
For flexibility, we should definitely serve static assets from nginx. We could use serveDirectory from behind servant or some other haskell server, but I think it will be easier to set up with nginx, and it would be easier to do something like make a static.eval.csh.rit.edu subdomain, if that's something we want to do (or something like eval.csh.rit.edu/static could work too).
What do you mean by routing? Like, the API routing?
Yeah, API routing.
Honestly though, I don't think we need a separate server for our html pages. It will be using essentially all the same functions as the JSON API layer but with an extra transformation before reaching the user. I don't see a reason to add a network call to the transform
By static assets I meant images and any css and javascript that we aren't templating. The shakespeare can definitely be run from the same server as the api. In the same vein, there is no reason why the frontend has to actually call the api at all, unless it is from the javascript on the client. Shakespeare can just call the pure functions that we associate with the routes directly.
Of course, if the html and the api are served from the same server, the api will have to be all under a /api/ path. I think this is better form anyway, but servant doesn't have faculties for serving different content based on content-type headers implicitly, so we don't really have a choice.
I think we're pretty violently in agreement then. Do you want to take that on? And by that, I mean just getting the basic pipelining done?
Why separate the API and HTML if they're just different views of the same content? Isn't that what "Accept: " headers are for?
:bike: :shed:
@gambogi Already started.
@ryansb I like the idea of having the URL and the HTTP method be the only things that define what information you are going to get in return. Although, the framework we are using to define the API (servant) can't serve different content based on the accept header implicitly anyway. It's designed to make json APIs.
@sdemos I see, well thanks for considering it. Too bad they don't support presentation based on the client.
@ryansb I agree that it would be better to have it keyed off the accept headers, and maybe we'll move to that in the future, but for now we will just serve them separately. Fortunately because our routes are created through combinators it doesn't need to result in any code duplication.
I still like the idea of separating the API and front-end servers. I feel like front-end routing should be handled by Yesod, not Servant. Using Yesod for the front-end routing gives you nice things like transparent session handling. In contrast, Servant isn't well suited for defining browser-facing routes, has no notion of a session, and will require a lot more boilerplate on our part to build the more complex UI features. What if we want to do something like long polling later on? Yesod already has that machinery, but we'd have to build that into the Servant handlers ourselves. A key advantage of Servant is that the client-side interaction can be automatically generated based on the type-level API specification, so that machinery is essentially done. Finally, I doubt that the more complex UI features will map one-to-one with API calls.
The most compelling argument is the elimination of any network communication between the front-end and API servers. There are a few ways we could achieve a similar effect. One would be to have the API and front-end talk over a local unix socket. This eliminates all the overhead of network communication except for syscalls. Another solution would be to write the API and front-end servers as two separate WAI applications that are run by the same executable. This way the front-end could simply call the API handlers directly.
@sdemos I'd argue that using something WAI-aware to serve static files is the most flexible. See:
https://hackage.haskell.org/package/wai-app-static
or perhaps,
For what it's worth, Servant added Content-Type-Aware serving in February
type MyApi = "books" :> Get '[JSON] [Book] -- GET /books
:<|> "books" :> ReqBody Book :> Post Book -- POST /books
:<|> "books" :> ReqBody Book :> Post '[JSON] Book -- POST /books with `Content-Type: application/json`
However, using Yesod to switch on Content-Type and having it pass the buck to Servant on API calls seems like the best of both worlds.
Addressed by #52
@gambogi @sdemos Set up framework/structure for: