On Jul 12, 2016, at 1:41 PM, John J. McDermott, CPLP <[email protected]> wrote:
>
> Let's say I have an app that can generate two kinds of output. It is a
> front-end to a database It can be used with a JSON interface or it can
> present HTML as a traditional web page.
Perfectly fine so far.
> I *could* add a /html element to the path to say "output as html" but it
> would seldom -- if ever -- be used. I *could* add a checkbox to the web form
> so it would return JSON but it is unlikely a normal person would want that.
Do you know a strong functional programming language? I don’t mean FP in the
way that JavaScript is a Scheme dialect and therefore FP, or even in the way
that Perl is FP as laid out in Dominus’ “Higher-Order Perl.” I mean FP as in
Haskell, the ML family, Erlang, etc.
These languages teach you the value of thinking of functions in the
mathematical sense, which is that any function called with a given set of
arguments should always return the same result. Another way of saying the same
thing is that functions should not have side effects.
It is impossible to avoid all side effects in any practical program not doing
pure mathematics, but we can minimize and restrict the scope of these side
effects by thinking hard about where the boundaries should be. Strong FP
languages sensitize you to this way of thinking.
In the context of this debate, the principles of tightly-scoped side effects
and referential transparency tell us that if you should not have a a Dancer
route that returns HTML in one context and JSON in another. Either the route
must differ somehow or the parameters must differ.
My preference is to put all JSON-returning Dancer routes under /api, then make
all other routes return HTML. (That’s a simplification. My current app also
has /pdf for the routes that return dynamically-generated PDFs, for example.)
Where the HTML-returning routes need data returned by the JSON API, either:
1. Call the internal JSON-returning route handler from the HTML route handler
and use its data to construct the HTML; or
2. Call back into the API from the client side via JS and construct HTML from
the returned JSON data there.
An example of alternative 1 is:
sub getSomeData { … used below … }
get '/foo' => { # because not under /api, returns HTML
# Do stuff here
# ...
# Okay, we’re ready to return our page
return template '/foo' => {
oneElement => getSomeData(param 'bar'),
anotherElement => $variableComputedAbove,
}
};
prefix '/api' => {
prefix '/some' => {
get '/data' => \&getSomeData
};
};
Here we have two routes, one returning HTML and one returning JSON, the first
of which is implemented in terms of the second. Because of Dancer's automatic
serializers, getSomeData() can return a normal Perl data structure that can
either be consumed directly by the template used in the HTML case or be
serialized to JSON for consumption on the client side via JS code.
Note the use of code references here to allow the HTML route handler to call
the JSON route handler.
You can read more about this style of development in a series of articles I
wrote for the fizzled Dancer 2015 Advent Calendar:
https://goo.gl/u900Ii
A lesser design principle is that, to the greatest extent practical, you should
push most of the code into the JSON side to reduce code duplication. The
HTML/JS client-side code can also consume JSON, but the JSON API has little use
for HTML.
To drag this back onto the topic of this particular thread, it is immaterial in
my view whether the values passed to the Dancer route come from the URL’s query
parameters, are defined as part of the route, or are passed in via a POST call
in the request body. Parameters are parameters, and a properly-written Dancer
route handler should return the same data regardless of the exact mechanism
used to pass those parameters.
_______________________________________________
dancer-users mailing list
[email protected]
http://lists.preshweb.co.uk/mailman/listinfo/dancer-users