Hacker News new | comments | show | ask | jobs | submit login
Intercooler.js – Making AJAX as easy as anchor tags (github.com)
455 points by cx1000 on Nov 6, 2016 | hide | past | web | favorite | 151 comments



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);
        });
    });


> 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.


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...


This is where things like GraphQL come in.


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.


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

Why not?


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.


I started out agreeing with your sentiment, then found myself disagreeing with the premise behind it.

Yes, a lot of companies are founded around a single product or family of products. They can afford to use a building block that isn't re-usable across different projects. They're not making things for public consumption, or have multiple very divergent codebases.

But these aren't small web shops, and people building blogs. In the DC area at least, the above describes every midsized company ( midsized as in > $1 monthly revenue < $50 million monthly revenue). These guys are makers of the software that runs in doctors offices, hotels, non-profits, political organizations, and government contractors.

They're already bigger than most SasS companies in SV, can ever expect to be.


I oversimplified to make a point. If I could rephrase it in more general terms it would be something like "people in web development are taking engineering advice from people who are solving completely different problems" or maybe "best practice in web development is being framed by the atypical"


The short answer is: because the web architecture was and is fundamentally different than the 80's style client/server model you are advocating, and it has specific advantages that are being lost in the transition back to that model (security, scaleability, simplicity, etc).

The longer answer can be found in these posts:

http://intercoolerjs.org/2016/01/18/rescuing-rest.html

http://intercoolerjs.org/2016/05/08/hatoeas-is-for-humans.ht...

http://intercoolerjs.org/2016/02/17/api-churn-vs-security.ht...

Of course, you will need to go into all of this with an open mind, or you will not find any of it convincing.


In the first article you raised two issues about REST: Developers disagree on what it means to be "REST-ful", and HATEOS never took off, despite being the feature that distinguishes REST from other APIs.

In the second article you explained that HTML could implement HATEOS.

In the third article you argue that GraphQL is the natural progression of REST but its security model is complex to the point of being unsafe.

---

The first article, in my opinion, consisted of straw men arguments.

The second is understandable.

The third made no sense to me. With a system like GraphQL you can use a declarative column-based security model. This is, in my opinion, easier than the imperative stuff you're probably using to make your HTML endpoints secure. With GraphQL you need to set up your security constraints once. With HTML endpoints you need to remember to toggle off certain blocks of HTML for every single request. Is that what you're doing?


What were the strawmen in the first article? It is observable that REST/HATEOAS (HATEOAS in particular) are falling out of favor in JSON-based APIs. This is understandable because JSON is not a hypertext, and the rest of REST isn't amazingly useful without it. Where's the strawman?

I'm glad the second article makes sense.

The core point of the third article is that when you increase the expressive power of a JSON API (with something like GraphQL) you are putting this power in the hand of the end user, not just your developers. This is not the same as giving, for example, full SQL access to your server-side only developer, where the code is executing in a trusted computing environment.


> With GraphQL you need to set up your security constraints once

I'm only superficially familiar with GraphQL, (and not at all familiar with Intercooler), but I always felt that security was glossed-over and not a core part of what it offers.[0]

Authorization is challenging enough on the server, but having a query-language power client-side, feels like a pretty fragile thing to me to secure properly. Definitely not something you just set once and forget about...

[0] http://graphql.org/learn/authorization/ - if I get it right, it gives a good example of row-based authorization and essentially tells you to figure it out for yourself in your business logic layer.


> What's the point? This would lead to your API being comprised of blocks of HTML which are probably only useable for one product.

Only usable for one product? There aren't many platforms without UI layers that have some kind of component for rendering/presenting HTML these days. But even for those that don't:

> Why not just use REST + JSON?

Markup is as much a data-exchange format as JSON is. If you're writing/generating it well, anyway.

I'm not saying never use JSON (I have and do). I am saying it's a little weird, though, that we've somehow got to the point where anyone who's commenting on this discussion has forgotten that markup has done and can do the job JSON does, or that we're at a place where as an industry it seems weird or potentially an interop problem to serve markup instead.


Plus, unless I'm missing something, the typical case is just:

    if accept==html then return html(template, data)
    else return json(data)
Which is sure as hell less work than setting up React/Angular and a bunch of other junk on your HTML frontend to consume JSON and turn it into HTML in the browser. Probably higher performance, too, since JSON-consuming HTML frontends in the wild don't seem to exhibit (putting it mildly) the performance improvements that AJAX originally promised—then again, that X was XML (and remember XHTML? I, for one, really liked it) so it's not necessarily AJAX's fault that we've decided to rube-goldberg up the web the way we have.


> This has been reposted so many times by the author and by others

The author did post a story about intercooler four times in the last 3 years. Where is the problem?

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

Whats the problem with that if their is no need to reuse the API, or if there is no API at all, just a bunch of uncool php scripts?

> It would take no more than five minutes to set up client-side rendering?

Is client-side rendering better per se?

> Is it really not worth spending the extra five minutes it takes to set things up in a way that is reusable and standard?

What standard do you refer to?

I think it is obvious that this lib isn't meant to be the foundation for the next facebook app, be a contender for the current hip bloatware frameworks or might be the best lib for single page apps generally. But I can see lots of use cases where this lib will help to spice up some projects without getting burden under some boatload of unnecessary tooling and boilerplate codes.


The author did post a story about intercooler four times in the last 3 years. Where is the problem?

Look at the author's comment history, rather than story history. He has a reputation of plugging intercooler in every discussion related to JS. Not that I mind; but most of the "reposts" that GP is talking about are comments, not actual stories.


Good news: now that this broke through the noise I can relax on the shilling.

I assure you I am the person most relieved by this. ;)


I don't think there's anything wrong with sharing your work. This reminds me of a thread last week about sharing what you've made. https://news.ycombinator.com/item?id=12838751


Kudos to you for not giving up man.


I've seen he doing it before. The OP pushes Intercooler.js in every place.

Anyway, I'd like to thank him for it. It was because of this pushing that I learned about the lib, and I'm very glad for that.


Not everything needs a JSON API so any client can talk to it. You're also underestimating setting up client side rendering as my experience tells me otherwise.

Most of the time a django/rails rendered backend is desirable and easier to maintain over the long run.


The "point" is server-side vs client-side templating.

It's easiest to keep everything in one templating system and language. (Note: I said easiest, not most robust or ideal.)

Options:

1. Isomorphic code. This requires either NodeJS or compile-to-JS tooling.

2. Client-side-only: bad for SEO and usability.

3. Server-side-only: You either write several lives of boilerplate every time line your example, or use intercooler and write a single-liner.


What's wrong with "boilerplate with code-generator"?

For smaller sites, the number of parts often isn't huge, so boilerplate isn't a big deal.


I probably don't understand what you mean.

Generating code in a Turing-complete language use a program written in another Turing-complete language can get messy.


I mean scaffolding.

Just because something is turing complete doesn't mean that a generator has to be able to generate anything possible.

If boilerplate is an issue, scaffolding / code generators can be a quick fix.


Can I have intercooler do that scaffolding for me?


> Is it really not worth spending the extra five minutes it takes to set things up in a way that is reusable and standard?

HTML is standard. Even more importantly it has rich and standard semantics. Your homebrew protocol based on JSON is not and does not. You write an interpreter for it every single time without even realizing it.

The thing you cooked up in 10 minutes does not follow the principles of progressive enhancement. This immediately closes up lots of doors.


> All I see is piles of legacy code being generated where it hurts most - in the backend.

No problem. It's just views. If the need comes to make it general, and output JSON from everywhere, you just write another set of views. They are discardable. (And you'll probably need different URLs for the JSON anyway, so you'll probably keep both sets.)


so that i can render the html in microseconds on my server and not waste the users time, or have to write javascript


Also, in many cases you can cache the result so rendering is no longer happening anywhere, neither on the server, nor on the client.


So work is heavily bought into the idea of rendering the client-side content in front end services (what you call the backend). It lets devs change user-facing behaviour without invalidating cached minified assets (which saves money at scale). Plus, we can test client side behaviour in just a few browsers, and be reasonably confident that everything else will roughly be the same.

It works for us because the site is extremely static…


for a lot of the client side apps I create, I want the response to trigger potentially multiple listeners that are used in a composed fashion. It's a lot less efficient to write 1:1 logic for each endpoint.


you forget that some of us are lazy..


I was thinking the same thing. The only reason I think to use Intercoooler is for very simple scenarios, or for people who perfer the server side programming and want to minimise JS programming. Which I can relate to to some extent.

Having said that, I've been doing a side project in KnockoutJS and it isn't much harder than IC. You mark up the HTML and need a little bit of JS to call the api. So it would be like your example but with a line or two removed. And like your example as soon as you desire to do something custom you just add some more code.

On the service side you emit JSON instead of HTML and this can be easier IMO - virtually every language has a JSON library and you just convert your ORM objects to JSON (or just use them as-is!). That is less work than rendering HTML I would have thought.


you nailed it. I don't want to do JS. I know enough Python to get by, I'm writing a small webapp with some API hooks (internal webapp) and I'd like to have some AJAX-y components. While I don't know if this is powerful enough for everything, the idea of "click on <button> to retrieve data and place in <div>" is really awesome. Doing it in HTML-only is much easier for my peon-non-genius mind.


I agree. There are instances where I think returning HTML instead of JSON works (think of Rails Actioncable or Phoenix Channels), but I have a hard time conceptually understanding what problem is solved by this library.

Thinking of almost all of the full stack, I feel like you could have more flexibility with something like Rails with Angular on the front-end. You can set up a Rails controller to return JSON or HTML depending on the request type.

Throw in UI Router and have your Angular routes match your Rails routes... You can have your pages rendered server and client side and still have the flexibility to render JSON.

It would be sick if there was a stack where you can take make your routes more functional and have the routing work clientside and serverside. I know Turbolinks is supposed to solve this problem, but it sort of messes up how events are fired.

Also, Angular templates cannot be modified on the front end... but these intercooler attributes can.

I will admit, the author is probably solving a problem that I haven't encountered or even fully understand. If people are digging it, more power to him.


And that's how the monstrosities are born.


I work primarily with a legacy, enterprise PHP application and it is a monstrosity (large number of classes, breaking framework changes, deprecated front-end libraries, very old MVC patterns, heavily imperative).

There are elements that Rails (predictable routing, simplified MVC, templating rendering, and general ease of set up and deployment) and Angular (flexibility, directives, safe templates, state based routing, imperative but can be functional with filters) provide the feature set that I have described above (aside from the routing object idea for generating server and client side routing).

The underlying technologies are not important; Node already has isomorphic javascript. I think Phoenix might be on track to remove the need for a heavy use of javascript for creating a single page application by simply using channels.

However, I cannot speak on Node and Phoenix because I lack the experience with these languages to comment. I do have experience with Rails and Angular to generate an example of how I would like a full stack, AJAX heavy application to work.


Yeah he lost me at "angular"


Why? There are plenty of developers that use Angular.

If I speak from a place of experience, is that less valid if I use a language that you do not particularly like?

It is not always the correct language in a lot of cases, but it can be for creating the feature set that I have described above - an approach for a more functional application structure that would provide server and client-side routing without Turbolinks.

You don't even need Angular or Rails for this, but these are both tools that I have enough familiarity with to know that it would work.


Because 1) the appeal of intercooler is its simplicity, and 2) I don't know angular and don't have any desire to learn it. It looks complicated, and on the decline: http://stateofjs.com/2016/frontend/.

It's not a language it's a framework. And it will take me (and others on my team) time to learn it, and maintain it in the future. But if you like it, more power to you!


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, "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.


Yep, that's the idea. It lets you more fully implement the original REST/HATEOAS concept of the web architecture:

http://intercoolerjs.org/2016/01/18/rescuing-rest.html

http://intercoolerjs.org/2016/05/08/hatoeas-is-for-humans.ht...

And then makes a lot of stuff that currently requires javascript (e.g. CSS transitions) accessible via plain old HTML.


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.


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.)


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


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.


> 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


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


Ever heard of XHTML 2.0? XForms was supposed to be a part of it and it did have support for REST stuff in the spec.

Well the XForms spec itself is alive and on the path to its 2.0 version. There's a number of implementations, but it seems most of dev world has an allergy to XML, which is a pity. XSLTForms works well enough, even on mobile.


The more important part is that HTML is for human interaction. So PUT or DELETE make no sense because the server should process user input under any circumstances and not take it as is.


Why would the server process PUT or DELETE any differently from GET or POST. I already have single-page applications that do DELETE requests to delete items.


I do not know your applications. But PUT and DELETE are more like file operations and unless you do these things in your applications, POST is just fine.

A PUT tells the server to make the payload available as is at the given URI. And if you do a GET on the URI, you should receive the exact payload that you put there. That may also include headers you send along with the PUT request (especially the Content-Type header). That's why a PUT is also able to invalidate a cache. So PUT and POST are very different.

The problem with DELETE is this part of the specification: "The client cannot be guaranteed that the operation has been carried out, even if the status code returned from the origin server indicates that the action has been completed successfully."

That's why most applications are fine with using only GET and POST.


DELETE is a bit of a can of worms - things like do you stick to response idempotency returning 200 even if the resource was already deleted or do you return a 404 on subsequent requests?

That said though, IMO it's way more intuitive to use DELETE vs POSTing op=delete or even worse POSTing to a /resource/delete endpoint.


"The client cannot be guaranteed that the operation has been carried out"

You can add your own guarantees on top of this specification. So in my application, the DELETE is guaranteed to have succeed if you get a positive status code.


Never so that funny interpretation of REST(ish) architecture. That R in the name is a dead giveaway that you not necessarily will get exactly what you put there. I may put json and request xml, what are you gonna do, stab me?


Well, if the server understands the payload, it can return it in a different representation. There is nothing wrong with that. But a GET should always return the original payload when requested with the Accept header that matches the original Content-Type of the PUT request.

edit:

Better is to use a PUT for different representations:

  PUT /foo
  Content-Type: application/json
  
  {"foo":""}

  PUT /foo
  Content-Type: text/xml
  
  <foo></foo>


Seems to be no reason why GET should return the original payload. No client should even expect that as the resource could easily have been changed by another client in between requests.


Obvious, but thats not the point.


What is the point? GET isn't even guaranteed to return the same payload every time, without PUT. Look at this website for example. The idea that you need to PUT something that be GET in exactly the same representation makes no sense given these basic facts.


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!


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.


Would love to see a real world project using it.


You can sign up for leaddyno ;)

http://leaddyno.com

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


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 ?


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.


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.


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.


Yeah, it just evolved out of a jQuery-based set of tools. I've looked into breaking the jQuery dependency and it hasn't bubbled up high enough for me to get motivated.

Always happy to take pull requests though...


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?


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.


ES6+ Async/Wait make it extremely unnecessary


its extremely unnecessary in ES6 w/ isomorphic-fetch and promises. In fact I much prefer what's happening in that area. Really this seems unnecessary. Async JS isn't that hard and ES6 has come a long way to solving the issues imo.


I kinda feel that a hard ES6 dependency goes against the philosophy of this tool, which is arguing for simple libraries that can be simply used for small projects without buildchain dependencies, etc.

Saying "Front-end javascript is too complex, let's go back to our progressive enhancement roots" in one breath and "Requires webpack and ES6" in another doesn't jive IMO.


> I really feel opposed to adding more dependencies

Isn't it a pragmatic technical decision rather than - what you almost make sound - rather an emotional one? There are times adding a dependency is exactly the right thing to do and times when it isn't. It's surely something that is project and situation dependent.


`XMLHttpRequest` is a bit sloppy to use admittedly, but you can encompass fetching into a simple function that's less than 10 lines long. Then, it's a matter of placing what you fetched into an element on the page. That is one line.

If I do it myself I retain full control over the functionality, it's faster because fewer "kitchen sink" properties need to be evaluated. It's easier for future developers to pick up and understand. There isn't any chance that the dependency or any of it's sub-dependencies go out of date and need to be replaced.

In software development there is always more than one way to do something, and this way will work today. But in what circumstance is it better? I don't want to attack this library. I'm trying to say there are too many libraries that act as an abstraction of something that would otherwise be simple to do.


> It's easier for future developers to pick up and understand.

Only if your 'utility function' stays small. However my hunch is that on any real-world project over time you hit a Greenspun 10th variant*

* Any sufficiently complicated 'pure' .js project contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of jQuery


That evolves to be able to read email[0].

[0]: https://en.wikipedia.org/wiki/Jamie_Zawinski#Principles



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.


> 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.


> 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?


> 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.


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?


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.


Well, those are fair points, I agree.


  > No client-side rendering
That's a good thing. Devs should really spend some time thinking why they do something in particular way instead of just parroting others.


Indeed. But as I wrote I think there are some good reasons why client-side rendering brings benefits in most of the cases - assuming you have already decided to use ajax.


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

One could include two attributes:

    <a href="/foobar" ic-get-from="/foobar">foobar</a>
There's likely some edge cases that would fail doing it this way, like when including other inputs outside of the form tags when submitting forms.


As I understood it, the whole idea of intercooler is to fetch HTML snippets via ajax and embed them into the page client-side. Your fallback would require server-side logic to decide whether to return the snippet or render the whole page client-side. That's just as complex as fallback for a traditional SPA.


There are a few different strategies when using intercooler. If clients not having java script available is a big concern the server can always return fully rendered pages and have intercooler pick out the elements from the response that need to be updated on the page.

This gives clients that do have java script the feel of an SPA and clients that do not have java script see the traditional full page refresh without any additional server side logic deciding to return snippets or not.


But if you render the full page anyway, why use ajax at all? Why not just navigate to that page?


To give users who have java script enabled (the address bar updates) the feel of an SPA and the full page reload jank doesn't take place.


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

Happy to see people are enjoying it!


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.


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

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

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


With the addition of server push this would be an ideal tool for a web game I've been vaguely working on --- I keep getting lost in a maze of client/server code. With intercooler it may just all go away.

(I was unaware of EventSource. It looks so, so much nicer to use than raw WebSockets...)

As an aside: Intercooler obviously requires Javascript to work; is there any fallback if Javascript's not available? It sounds like, at least for interactions on things like form buttons, it ought to be possible to send an old fashioned POST to the server which rerenders the entire page.


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...

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.


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.


As a non fronted developer playing arond with web technologies I was impressed by IC.js. It is really easy to get it work (is like boring HTML) and it works pretty well with web2py. Using it does not feel like "engineering something" but some people simply want to drive a car without getting their hands dirty.


Is there a typical pattern for progressive enhancement, going from the non-js case to the intercooler case when js is enabled?


Not yet, beyond the somewhat ugly duplicating of anchor tag hrefs and form actions and then checking for the 'ic-request' variable on requestsion.

It's on the list.


How do you see this comparing with older existing solutions like Rails' Unobtrusive JavaScript? It has always handled this kind of thing very well for me, and has been around a long time.

https://github.com/rails/jquery-ujs


I think it builds on a lot of those older ideas, but is a bit more explicit and tuned towards what modern web apps have evolved into. Pjax and Turbolinks were direct inspirations.


This is sort of a meta thing, but I'm curious how many hits/stars you got on the github page from hn


I started today w/ 1400 stars


Why did you choose to use a custom attribute rather than a `data-` one?


I like how custom attributes look better, when I saw how Angular was using them.

You can use the data-prefix though if you want by including the following meta tag:

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


I know it's largely hypothetical, but by not using data-, aren't you running the risk of namespace collisions in future? data- attributes are guaranteed not to ever have an 'official' version that the browser expects, while anything else may exist in the future.


any chance of a jquery-free option?


Yes, it's on the list. I expect some time in 2017.


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.


I'd like to implement that.

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


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.


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


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!


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


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!


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.


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.


Have you tried to use source maps?


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.


Have a look at Mithril.js.


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


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.


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


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


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.


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


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


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


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? :)


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.



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

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...

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.


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.


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.


If you like this sort of thing I can recommend to look at Patternslib (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/ ) does everything intercooler does, but also a lot more.

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


    <!-- 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.



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


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

https://validator.w3.org/nu/?doc=http%3A%2F%2Fintercoolerjs....


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

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


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


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


Great to hear. :)


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.


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.



+1 for official theme music




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: