Open pikajude opened 8 years ago
+1 for mimeRenderM
and leaving the m
abstract.
@pikajude Have you seen servant-lucid?
Also,
No separation of logic and presentation.
I think that's a red herring. You can always separate them if you want to. Formal templating languages are always trying to find the sweet spot between logic and presentation. But it's a very hard spot to find, because it depends a lot on the problem at hand. I personally think it's too diverse for a framework to make that call categorically.
@3noch Sorry, I'm afraid I don't understand your responses. The whole point of this post was that I want to separate them and I can't unless I'm willing to use either unsafePerformIO
or compile-time IO.
I'm certainly open to the idea that separation of logic and presentation is unnecessary, but I would like to have the choice, at least.
@pikajude Sorry for the confusion! I agree with you that it's important to separate logic from presentation. However, I was responding to your objections to using blaze-html or lucid. You claim that they do not allow you to separate logic from presentation. My claim is that they actually pose no threat to separating logic and presentation. The only difference is that they do not necessarily separate logic and presentation. However, you are still quite capable of employing the separation yourself: simply refrain from embedding logic in your templates.
For example, in lucid you could be tempted to not separate logic as is common in PHP apps:
template = html_ $ body_ $
ul_ $
forM_ [1..10] $ \item -> do
queryResult <- liftIO (runComplexQueryFor item)
li_ queryResult
main = serve template
But because you have the full abstracting power of Haskell at your fingertips, there's no reason you can't refactor this to enforce better separation:
template items = html_ $ body_ $
ul_ $
forM_ items li_
main = do
queryResults <- forM_ [1..10] runComplexQueryFor
serve (template queryResults)
what about servant-ede https://github.com/alpmestan/servant-ede ?
@freezeboy Don't know what else to add about it.
@3noch I do agree that a certain degree of separation is certainly possible when using blaze or lucid, though whether you can avoid embedding logic in your templates depends on how you define what a "template" is in the first place. In this particular case, the "template" is not something I would expect Web Developer Smith, who might be collaborating with me on a servant project, to be able to maintain without learning Haskell syntax and how to debug the errors that GHC spits out.
This is a little tricky, semantically. By allowing mimeRenderM
to do IO, we are essentially saying there isn't necessarily a pure function from the a
to the a
rendered as a particular mime type, which I think is problematic conceptually, even if helpful in practice. Indeed, this may have negative consequences, such as documentation generating different timestamps for samples for the same object if part of the IO
being done involves looking up the time.
From that perspective, TH or a variation on servant-ede
s approach is in fact the right solution, since what we want is a function that is pure but takes an extra param (the contents of the template file), but with mimeRenderM
we allow for much more. In particular, I think we could provide a TH function that generates a datatype of e.g. TemplateFiles '["file1.tmp", "file2.tmp"]
, and which contains as values the contents of those files, which then the API is free to use. This improves on servant-ede
by not involving unsafePerformIO
and by statically ensuring the API only uses templates we know about, and needn't involve significantly longer compilation times since the TH
stage would only involve reading files, not processing them.
I think (for reasons similar to those mentioned by @3noch ) that it's a little unfair to dismiss lucid
and blaze-html
generally - they just have different trade-offs. So if no one objects, I'll change the title of the ticket to HTML templating with external files
so as to make clear we're not taking a general stance of the merits of e.g. ede
, mustache
, and heist
vs. blaze-html
and lucid
.
Can I use servant-lucid if I already have an html template (file) and a few html pages? And how?
@jjmornim Not sure servant-lucid
can do something for you. I know that blaze-html
comes with a program that turns HTML pages into the equivalent blaze-html
code. You might want to modify it to output lucid
code instead?
@pikajude the unsafePerformIO
in servant-ede
isn't too bad really. I'm however convinced my solution there isn't optimal, as the "compiled template store" is behind an MVar, which costs a little bit, on every request. What I would need, I think, is to use the recent Context
machinery to make the template store available to the MimeRender
instance. So instead of allowing IO in MimeRender
, I'd just need an extra arg. OTOH, with streaming request/response bodies, multipart upload and templating use cases, it looks like we really might want to think about allowing IO in rendering code...?
I spent the last day or so looking into ways to render HTML templates with Haskell and combine those with servant, and came away unsatisfied. All the solutions I found required a potentially objectionable workaround.
mimeRender
doesn't allow IO.servant-ede
works around this by usingunsafePerformIO
, which is definitely potentially objectionable.My gut feeling is that
MimeRender
is just not powerful enough to let users use a templating engine, but since I'm not an expert on the internals or architecture of servant I'd welcome some input on my assessment. Ideally I would likemimeRender
maybe to beProxy ct -> a -> EitherT ServantErr IO ByteString
, or for another functionmimeRenderM
to be added to the typeclass and by default implemented in terms ofmimeRender
.Thoughts?