
Intercooler.js – Making AJAX as easy as anchor tags - cx1000
https://github.com/LeadDyno/intercooler-js
======
DSteinmann
This has been reposted so many times by the author and by others that I can't
help but finally ask.

What's the point? This would lead to your API being comprised of blocks of
HTML which are probably only useable for one product. Why not just use REST +
JSON? It would take no more than five minutes to set up client-side rendering,
and you could even make it attribute-based like this with barely any more
effort. Is it really not worth spending the extra five minutes it takes to set
things up in a way that is reusable and standard? All I see is piles of legacy
code being generated where it hurts most - in the backend.

This took me 10 minutes to cook up. It would have taken about three if I
hadn't forgotten the jQuery and Handlebars APIs. This allows you to POST to a
JSON API using two attributes. Untested of course, but you get the idea:

    
    
        Example: <button ic-post-to="/api/resource" ic-template="#a-handlebars-template" />
    
        $('[ic-post-to]').click((button) => {
            fetch($(button).attr('ic-post-to')), { method: 'post' })
            .then((result) => {
                let templateText = $($(button).attr("ic-template")).html();
                let template = Handlebars.compile(templateText);
                let resultHtml = template(result);
                $(button).replaceWith(resultHtml);
            });
        });

~~~
andybak
> This would lead to your API being comprised of blocks of HTML which are
> probably only useable for one product.

Because for probably the majority of developers there IS only one product.

Here's what I think is happening. A bunch of us are working on websites that
need to scale across multiple users and adapt to multiple clients and will
have to grow and pivot as the business needs change. And they've learnt the
hard way about building scalable systems.

But what is going horribly wrong is that their war stories and best practices
and tools and processes are being used by a bunch of us who will never face
those problems. And we're paying the price in terms of complexity for problems
we aren't ever going to face.

If you're building a SaaS for a startup that might reasonably expect
exponential growth, unfortunately your advice is being taken to heart by
people building blogs and small web-shops and we're seeing some terrible
technical decisions being made because everyone wants to do things 'right'.

We need a healthy dose of YAGNI drilled into people. Whatever happened to
progressive enhancement? It still suits the vast majority of web projects
perfectly well.

~~~
carsongross
That's a great response Andy.

I'd also say that JSON APIs either tend to get tuned for specific UX needs or
become more and more expressive. The first option calls into question the
general, reusable nature of the API, and the second introduces security issues
in an untrusted computing environment[1].

I typically split out the JSON API for my system from the web application
proper so that my web application needs don't screw up the public API of the
system. They end up being two separate concerns with different shapes,
authentication methods, etc.

[1] - [http://intercoolerjs.org/2016/02/17/api-churn-vs-
security.ht...](http://intercoolerjs.org/2016/02/17/api-churn-vs-
security.html)

~~~
joesb
This is where things like GraphQL come in.

~~~
ryanbrunner
Customers aren't going to use GraphQL for a public API, so you've just added
another (micro) service to talk to the GraphQL server and translate it into a
more traditional REST API (or the other way around if you want your internals
to be REST). Also, you've pretty much forced an entire ecosystem of complexity
onto your front end.

And then you've added a ton of complexity, bringing us full circle.

Based on the parent comments, we're talking about simple websites where
serving HTML through AJAX is an effective approach. In the name of "purity",
you've introduced JSON APIs, GraphQL, (most likely) React and Relay, more
complex deployment with multiple services, probably a complex front-end
buildchain, and who knows what else.

~~~
lmm
> Customers aren't going to use GraphQL for a public API

Why not?

~~~
ryanbrunner
Right now this isn't feasible. People are used to REST APIs, and the tooling
and documentation (particularly outside of use with React and Relay) for
GraphQL isn't where it needs to be for it to be feasible for a customer-facing
API.

------
cx1000
Honestly it feels like intercooler.js is building in functionality that should
exist in HTML in the first place. For example, the unintuitive "href" tag
sends a GET request, and POST requests are only sent with forms and buttons.
What about PUT, PATCH, OPTIONS, or DELETE? According to
[http://softwareengineering.stackexchange.com/a/211790](http://softwareengineering.stackexchange.com/a/211790),
"At this point, it seems that the main reason why there is no support for
these methods is simply that nobody has taken the time to write a
comprehensive specification for it."

Intercooler.js makes them seem a little more "built in" to html, which I like.

~~~
naasking
GET and POST are technically all you need, ie. "get representation of
operation X", and "apply operation X to these arguments". It's a simple lambda
calculus.

The other methods are merely optimisations to these core operations, and
hence, entirely optional.

~~~
lomnakkus
That's only true if you ignore the fact that operations in HTTP have
_semantics_ attached. (Or at least that was the intent. The reality is
probably that they actually don't in practice. Plus, as others in this thread
point out: The semantics may not actually make any sense.)

~~~
naasking
What semantics can't be captured by only GET and POST?

~~~
lomnakkus
I was thinking about meta-level semantics, i.e. semantics that apply to _all_
HTTP/REST-based systems, not just one's own special snowflake :).

EDIT: Though, honestly, I must say that I also question the value of these
things. For example, HTTP error codes are _notoriously_ ambiguous and you
usually need to transmit an actual response (and sometimes are forbidden spec-
wise!) with an error code. I was just assuming the position of an advocate for
HTTP/REST.

~~~
naasking
> I was thinking about meta-level semantics, i.e. semantics that apply to all
> HTTP/REST-based systems, not just one's own special snowflake

Yes, but these verbs often don't yield any meaningful results or see much use
in my experience. Even so, this could easily be achieved by convention using
just GET/POST.

Consider the HTTP OPTIONS verb. If you invoke it with * as the request-URI,
it's an operation that applies to the server as a whole rather than any
specific resource.

This provides the solution: HTTP already reserves one URI for a specific use,
and we can do the same for all of the other verbs and eliminate them from the
spec if we so desired, ie. OPTIONS /some/resource => GET
/options?url=/some/resource

~~~
lomnakkus
I think we agree, I was merely commenting on a techincality. :)

------
nzjrs
I said this on the other discussion, but I'm compelled to post it again.

Intercooler.js is so logically designed it basically requires no documentation
- I read the introduction and a handful of examples and thought, "shit of
course it works this way" and could basically derive how every other feature
mapped to its implementation in that moment.

Congratulations!

~~~
carsongross
Thank you!

I built it for my startup and wasn't sure it was going to work out, but my co-
founders let me give it a try and I've been really happy with how it turned
out. We have been able to build a pretty modern web app with very little
javascript.

~~~
adamors
Would love to see a real world project using it.

~~~
carsongross
You can sign up for leaddyno ;)

[http://leaddyno.com](http://leaddyno.com)

 _(We are hitting levels of shilling that shouldn 't even be possible)_

~~~
udkl
Side question: can you write about the business side of leaddyno ? How you got
started, how you marketed/are marketing it and how it is doing right now ?

------
scwoodal
I was a long time pjax/turbolinks user but always felt like I was pushing the
boundaries of what these technologies were doing and always wished for more
functionality.

I tried out several client side frameworks but always felt like it was way
overkill for the apps I built.

I gave intercooler.js a try a few months ago and was extremely pleased.
There's very little server side that's required and the extra functionality I
had wanted from pjax was there.

If you're wanting the simplicity of server side rendering plus the feel of an
SPA without the frontend complexity give this library a try.

~~~
NoGravitas
Agreed. I am also using intercooler to replace jquery-pjax because of some
fine touches that were hard to implement with jquery-pjax. It makes it very
easy to take a server-side Django/Rails/ASP.NET MVC app and decorate all the
links to eliminate full page loads, move complex inline editors to modal
dialogs, etc., without a lot of complexity on the front end.

------
Kequc
I'm surprised this needs jQuery. What this seems to be is a simple script that
fetches a resource and places it into an element. I really feel opposed to
adding more dependencies where they aren't required. That could be written
without jQuery or this library fairly easily.

~~~
dec0dedab0de
I am by no means a js expert, but doesn't jquery essentially act as an
abstraction layer to smooth over differences in browser behavior?

~~~
quantumhobbit
That was the one of the original use cases for jQuery, but browsers have
gotten more compatible recently, so you may not need it anymore.

~~~
tmat
ES6+ Async/Wait make it extremely unnecessary

------
xg15
This seems to make things simpler at first glance, but I fear in the end you
end up with the worst of both worlds: You have the API inflexibility and UX
restrictions of a pure-HTML approach combined with the overhead and need for
graceful degradation of a full-ajax approach.

~~~
andybak
> You have the API inflexibility and UX restrictions of a pure-HTML approach

I don't see this. Can you elaborate?

> combined with the overhead

In what sense? Bandwidth? Rendering? Conceptual?

> and need for graceful degradation of a full-ajax approach.

I've found intercooler suits a 'graceful degradation' approach rather well. It
is a small evolution of on from pjax/turbolinks - which itself epitomises
progressive enhancement/graceful degradation.

~~~
xg15
> andybak 7 hours ago | parent | on: Intercooler.js – Making AJAX as easy as
> anchor tag...

> _You have the API inflexibility and UX restrictions of a pure-HTML approach
> I don 't see this. Can you elaborate?_

No client-side rendering. More precisely, the core idea of intercooler is that
every UI update polls the server for new markup. So for each non-trivial UI
change, you have to take into account the latency of a network request, even
if you already sent the data to the client before in another request. That
makes the "feels like a desktop app" experience impossible that originally was
one of the major selling points of ajax.

The "markup snippet" means that if you want to change your UI,
congratulations, you have to change your template _and_ your API - whereas
with client-side rendering you wouldn't have to touch the API at all in many
cases.

> _In what sense? Bandwidth? Rendering? Conceptual?_

Conceptual. You have the same complexity costs as a full ajax page compared to
a plain-html page (data gathering spread over multiple requests, need to
define an API boundary, need to care about clients without JS support, need to
track client-side state, etc.) - but it seems to me you get a lot less
benefits for that cost.

> _It is a small evolution of on from pjax /turbolinks - which itself
> epitomises progressive enhancement/graceful degradation._

I admit I'm not familiar with that. But how would it deal with clients without
JS support?

~~~
ryanbrunner
> That makes the "feels like a desktop app" experience impossible that
> originally was one of the major selling points of ajax.

The vast majority of single-page applications I see on the internet nowadays
still function in a way that would be perfectly serviceable if they were
implemented without AJAX.

Absolutely there's cases where the request-response cycle doesn't map well to
what actually happens in the app, but I don't think anyone is claiming that
Intercooler, or serving HTML from an AJAX request, is the final answer in
building web apps.

Everyone seems to forget about using the right tool for the job when the right
tool is unsexy.

~~~
xg15
What I don't understand is what benefit serving HTML from Ajax would bring you
in the short time if you plan to switch to JSON anyway. Wouldn't that be one
unnecessary backend rewrite?

~~~
ryanbrunner
Well, a couple of things there:

1\. You may not plan to switch to JSON anyway. Serving HTML, whether through a
full request or AJAX can be perfectly fine. The site we're on now has no real
Javascript of note, for instance.

2\. You might introduce a JSON API for customers, but that doesn't mean that
it needs to or even should be the same API you use internally.

3\. Even assuming that you know that you'll ultimately move to a JSON API, it
can be advantageous to take a quicker approach while you're still figuring out
the solution. When you come back to the API, you'll have a better idea of
precisely how it should be used.

~~~
xg15
Well, those are fair points, I agree.

------
carsongross
Main intercooler.js author here, glad to answer any questions.

Happy to see people are enjoying it!

~~~
zackmorris
I'm a huge fan of intercooler.js because most of web dev today is going to
monumental lengths to hide the progress bar overtop of what used to be simple
client/server RPCs (in other words, the vast majority of it is a waste of all
of our time).

I really feel that the web is moving towards a components/modularized system
where every tag is built from subtags, a bit like how iframes used to work but
without the security implications. For example, I was shocked when I learned
back in the 90s that server-side includes where generally disabled on servers,
which led to the proliferation of cgi-bin, php, ruby, node.js, etc etc which
may not have been necessary otherwise.

To get to my question - is adding websocket/socket.io on the horizon? If
intercooler.js can get to a truly push-based method of state synchronization,
it would be huge.

~~~
carsongross
Yeah, a core idea of intercooler is to take the original web architecture
seriously and not try to shoe-horn 90's style client/server architecture into
the web:

[http://intercoolerjs.org/docs.html#philosophy](http://intercoolerjs.org/docs.html#philosophy)

I'm looking to add server-side event support in the next month or so, which
would give us a nice way to implement push-based updates:

[https://github.com/LeadDyno/intercooler-
js/issues/131](https://github.com/LeadDyno/intercooler-js/issues/131)

I'm working on a demo chat UI myself, so I will be motivated to add it soon.
:)

~~~
zackmorris
Cool I hadn't heard about server-sent events. They look straightforward
enough, my main concern is that the separator between messages is two
newlines. It would have been better if they used an arbitrary boundary string
like in multipart/form-data to be symmetric with traditional form data, so
that a pseudorandom string/md5/sha could be used to separate binary data
segments (especially when the contents and their length were not known in
advance):

[http://stackoverflow.com/questions/3508338/what-is-the-
bound...](http://stackoverflow.com/questions/3508338/what-is-the-boundary-in-
multipart-form-data)

Now unfortunately there will be a requirement client-side to decode binary
data or strings with escaped newlines. We'll get the benefit of deterministic
behavior at the cost of escaping payloads, and I'm not certain it's worth it.

This seems like an opportunity lost to me. Big enough that this may be one of
the basic building blocks we skipped over in the rush to javascript. Maybe the
community could wrap this to look like a client-side form until there is a
standard.

~~~
jkarneges
The browser EventSource API handles decoding, so there shouldn't be a need for
browser client code to worry about it if that's the concern.

------
Touche
It would be cool if this could some how use DOM diffing (I assume it just uses
innerHTML now), so you'd get minimal dom updates with the advantages of doing
everything server-side that this already provides you. Throw in some smart
service worker caching and you get pretty close to the responsiveness of a
fully client-side approach.

~~~
carsongross
I'd like to implement that.

Or, better, I'd like _you_ to implement that. :)

------
20years
I am happy to see this featured on the front page. I am using this for a
current project after coming off an Angular project. I am so glad I chose
this. It is simple to use and a pleasure to work with.

~~~
pryelluw
I have not used this Project but my experience with angular 1 left me wishing
for something simpler.

------
stdgy
Very neat! This matches up closely with what we have evolved for my group's
legacy codebase to simplify handling AJAX requests. I suspect we're not alone
in arriving at this sort of declarative abstraction.

Unfortunately, our implementation is rather scatter-brained and non-uniform.
That's partly due to its gradual evolution and partly due to lack of free
employee time to clean up bit-rot. I'm going to investigate this a bit more
and mock out some examples for our product. I definitely think it'd help us
organize our unruly mass of code. Good job!

------
dec0dedab0de
I recently used intercooler to implement a small feature in a django app. It
was an absolute pleasure to use.

------
oliv__
Thanks HN! This is one of those just-in-time situations: I was going to need
something to do some AJAX in the next few days and this is one of the most
elegant solutions I've seen so far. Didn't even know this existed!

------
astrospective
I've been using this on .net projects, have pulled off some fairly intricate
UIs by returning server rendered partials. The polling support is nice and
robust for dashboards.

------
cx1000
I love that you can use this without having to build anything with
babel/webpack. Given the scope of my web apps, anything that transpiles or
mutates my sourcecode is a non starter because it makes debugging it weird
since I'm not looking at my own code anymore.

~~~
sotired
I am interested in getting a more secure footing on the front-end side of
things. Can anyone recommend other ES5 front-end code bases like this that are
easy to study without encountering build tools, endless dependencies, ES6
features and so on? Particularly that use a declarative approach.

~~~
tobltobs
Have a look at Mithril.js.

------
ing33k
this is one of those libraries, which should be posted on HN once in a while .

~~~
cyberferret
Agreed! I came across Intercooler a few weeks ago when someone posted about it
in a thread and I thought "Whoa! Where has this library been all my
programming life?". Planning to use it on an upcoming project, and to refactor
an existing project to get rid of a bunch of jQuery $.get() blocks and
streamline things.

------
rhabarba
"Small". As in "just add the giant jquery library as a dependency".

------
brianzelip
fyi, the timing of this post is likely related to the HN discussion
[https://news.ycombinator.com/item?id=12882816](https://news.ycombinator.com/item?id=12882816)

------
bobwaycott
I have, over the last few years, taken a similar approach and built my own
reusable, yet rudimentary, version of this. Happy to see such a well-thought
out and elegant approach that matches my own preferences. Going to be using
Intercooler in the future (and might even switch my old stuff to it). Nice
project.

------
unethical_ban
I see someone read the front-end discussion. I am reading the guide to IC.js
and it's a neat piece of tooling.

------
ape4
What happens when there's an error? eg cannot contact host.

~~~
carsongross
An event is fired and you can handle it in javascript, as with usual AJAX
requests.

~~~
elmigranto
So you have to write JS.

But I guess there would be a single event handler that shows all the error
messages and server would push down HTML describing errors, e.g. validation.

Why not make it part of the lib then, so "no js" thing stands? :)

~~~
unethical_ban
Hm, I guess it would be interesting to have some kind of error code handling.

    
    
      <button ic-post-to="/query" ic-on-http-404="/errortemplate"> or similar.

~~~
carsongross
Oh, that exists:

[http://intercoolerjs.org/attributes/ic-post-errors-
to.html](http://intercoolerjs.org/attributes/ic-post-errors-to.html)

------
chandmkhn
Webforms version of asp.net always sypported this idea through soething called
UpdatePanel

[https://msdn.microsoft.com/en-
us/library/bb399001.aspx](https://msdn.microsoft.com/en-
us/library/bb399001.aspx)

Commercial control providers in .Net world support these scenario with
something called "CallbackPanel".

[https://demos.devexpress.com/MVCxMultiUseExtensionsDemos/Cal...](https://demos.devexpress.com/MVCxMultiUseExtensionsDemos/CallbackPanel/Example)

Real conufsion starts when you have nested HTML controls that automagcally
making ajax calls. Nice idea as long as you can get away with minimal work.

The moment you want to use any moden SPA framework, you are up for a big
rewrite.

~~~
shankun
Funny, when I saw this I immediately thought of UpdatePanel (I used to be on
the ASP.NET team back then).

The motivation of UpdatePanel was not to provide the best design pattern for
AJAX, but provide the fastest path to incremental page updates for ASP.NET Web
Forms developers (with minimal code changes) - with all its limitations.

It makes a lot less sense to have a pattern like this in a modern SPA.

------
chunkiestbacon
I used this to make my own webshop software for a client. Lots of ajax
features but only 80 lines of javascript in total. Intercooler is great to
update the shopping cart in the sidebar when pressing the add to cart button.
This makes the shop feel a lot smoother.

------
wichert
If you like this sort of thing I can recommend to look at Patternslib
([http://patternslib.com](http://patternslib.com) ), which has many tools to
add interactive behaviour to a webpage without having to write and javascript,
making it a great toolset for designers. The injection pattern (see
[http://patternslib.com/inject/](http://patternslib.com/inject/) ) does
everything intercooler does, but also a lot more.

Disclaimer: I'm one of the original authors of Patternslib.

------
asciihacker

        <!-- When this button is clicked an AJAX POST request is sent to /example and the 
             response content is swapped in to the body of the button -->
        <button ic-post-to="/example">
            Click Me!
        </button>
    
    

But what if I want the response to populate the content of another HTML
element? E.g. if I wanted an accordion-style FAQ where when you click on the
question (or on a plus-sign before the question), the div below the question
is loaded with the answer from the server via AJAX.

~~~
kingosticks
[http://intercoolerjs.org/docs.html#targeting](http://intercoolerjs.org/docs.html#targeting)

------
grimmdude
Cool, this has some great functionality. A while back I wrote something very
similar called "jQuery Ajax Markup". It was much simpler though:
[https://github.com/grimmdude/jquery-ajax-
markup](https://github.com/grimmdude/jquery-ajax-markup)

------
sleepyhead
"Attribute ic-get-from not allowed on element div at this point."

[https://validator.w3.org/nu/?doc=http%3A%2F%2Fintercoolerjs....](https://validator.w3.org/nu/?doc=http%3A%2F%2Fintercoolerjs.org%2Fexamples%2Flazyload.html)

~~~
scwoodal
You can set a meta tag to force IC to use "data-" attributes which passes
validation.

    
    
      <meta name="intercoolerjs:use-data-prefix" content="true"/>

------
Yokohiii
Not sure yet if I like it, but for the "on churn" parts I will leave some
respect here.

------
bedros
the best part is the examples, there are so many practical cases.

~~~
carsongross
Great to hear. :)

------
smrtinsert
How many times will something like this be attempted? It ends up being awful
for debugging. Works great when there are no bugs of course.

~~~
carsongross
I don't find it particularly difficult to debug, it's simple enough to see
what's happening with the requests and responses, but there are definitely
situations where it can be hard to understand what's going wrong.

I've tried to log the most obvious problems to console to make it easier to
understand what's going on.

------
jramz
reminds me a bit to: [https://github.com/eldarion/eldarion-
ajax](https://github.com/eldarion/eldarion-ajax)

------
bitforger
+1 for official theme music

