Wednesday, September 25, 2013

Supporting IP address ranges in Django Internal IPs setting

Django internal ips is one of those pesky little details that turn out to be the reason for your css not loading in your web app after you restarted your machine. Here is the chain of events:

Restart -> DHCP -> IP change -> no longer an internal IP -> DEBUG is false -> your templates render as if on production -> you need css instead of less.

Unfortunately internal_ips can only take individual IP addresses and not a range. So if you decide to package your app into a nice vagrant VM for distributing to your colleagues, when they run and try to access it, again the same problem.

Solution is simple. After all it is Python we are talking about. :)

Inspired by http://dancarroll.org/blog/2011/01/debugging-django-dev-server/, I included a container derived from list that answers yes to the membership question whenever the given key matches one of the patterns in the list.

from fnmatch import fnmatch
class globlist(list):
    def __contains__(self, key):
        for pat in self:
            if fnmatch(key, pat): return True
        return False
# Put the whole internal range as internal ips
INTERNAL_IPS = globlist(['127.0.0.1','192.168.1.*'])

Voila!

Sunday, June 16, 2013

HATEOAS

Got one version of the HATEOAS working but it doesn't look like it will go very far.

Basically while initializing the collection of pages in a publication, I do it manually and use the URLs provided by the API to set the URL on each of the pages model. Later when a publication is requested, I trigger the fetch on all the page models.

The problem is there are usually a lot of pages and all these calls take time. It looks funny when the starting view contains the default title for all the pages and slowly they are replaced by the actual title as they are loaded. I think it would be a better experience to show only few pages to start with and keep populating the list as additional pages are loaded. Perhaps it is better to modify the API or ignore the pages URL all together.

Saturday, June 15, 2013

Handling HATEOAS with Marionette

Till few days ago, I was an innocent web developer building a REST API. Then I came to know about HATEOAS and my life was never the same again.

HATEOAS essentially means that the API consumer should be able to navigate the API simply on the basis of information provided by the API and should not require out of band information. One example is the end point discovery. When you fetch resource A that is related to several instances of resource B, the url to API endpoints for resource B should be included in the server response.

Currently my Publication object returns with the links for its constituent pages. Now I am trying to figure out the best way of taking these URLS and using them in backbone to load the individual pages.

Next week's aim is to spend time on Page editor and finally get the template thing working. Finally we are coming to the point of this whole exercise. Warm up is done and the real play begins!

Friday, June 14, 2013

Bootstrap tabs in a Marionette view

Not much progress today but after couple of blind alleys, managed to get the bootstrap tabs working in a Marionette Layout. It mostly works out of the box since there is no removing elements from the dom business here unlike modal dialogs. So you just wrap the jquery plugin for use in rjs and then correctly markup the html in template.

Thursday, June 13, 2013

PushState, RequireCSS and RequestResponse

Today was the day of lots of new things. As I mentioned yesterday, I was in the market for something that will help me load my CSS.

While I agree that requirejs is a great tool to manage js dependencies, lately I am feeling that it leaves the job half done. A modular piece of JS, in many cases, will come with accompanying CSS and html templates. For example, almost every jquery plugin has a JS and a CSS file. Requirejs provides no API for declaring dependency on a whole module.

One way to achieve this with rjs is as following. First find a rjs plugin that loads html templates and css. Then write a wrapper module declaring dependency on both js and css. Now use this wrapper module wherever you needed the original. But this means writing a wrapper for every plugin or library you want to use. Given that rjs wants one module per file, this can mean a lot of files! One way of working around that is:

define('external', [], function() {
    var exports = {};
    exports.plugin1 = {
      ...
    };

    exports.plugin2 = {
      ...
    };

    return exports;
});
Then we can add a dependency on 'external' and use the required module. But now every external module will be loaded as a dependency for your module which is again not very palatable.

Loading CSS using RequireJS

For loading CSS, there are some plugins available. The primary issue is that a lot of modern browsers seem to be lacking a onload event on link elements. This means while it is easy to add a link element in the dom and thus load the CSS, there is no way to know when the sheet has loaded. One workaround is to keep polling the dom stylesheets to see if the new sheet has come in. The other approach is more clever. You create a script tag and use the css url as src. Browser loads the css and tries to interpret as a script and throws an error. So the onerror event on script tag can be treated as the onload for the css file.

There are bunch of drawbacks. One is that onerror gets called for 404 errors also. This means that the sheet was not found. This can be overcome with checking for the presence of stylesheet in the dom.

The other issue is that invalid script tag throws errors in the console. The workaround for that is to use img tag instead of script tag. With img tag, there is a non-threatening warning in the console and that's it.

There are couple of rjs plugins available that implement the above ideas: RequireCSS & CSSLoader. I am using a fork of RequireCSS that uses the img tag technique described above.

RequestResponse

RequestResponse is a simple object on which you can do two things:
  • set handlers for particular requests by name
  • make a particular request. The handler for the request will be executed and response returned.
Marionette applications come with a RequestResponse object on them. One use I am making of them is to make a central datastore for my models and collections. All other parts of application request the data from this central place. Updates are also done in the datastore. Other components use events to indicate what needs to be done.

This means any changes to a model or collection are immediately propagated to all the views. It also helps in supporting both the option of getting data: through a bootstrap variable dumped by the server in initial file or through a fetch from server.

// datastore module

var store = {};
// The library for the current user
function getLibrary(){
 if(!store.library){
  if(typeof pubs === 'undefined'){
   store.library = new Library();
   store.library.fetch();
  }
  else{
   store.library = new Library(pubs);
  }
 }
 return store.library;
}

var reqres = new Backbone.Wreqr.RequestResponse();
reqres.setHandlers({
 "collection:library": getLibrary,
 "model:publication": getPublication
});

return reqres;


// using the datastore in a view
// Request the library collection to be displayed
this.collection = DataStore.request("collection:library");

This pattern is useful when trying to build support for pushstate in your application. In case of pushstate, the view can either be rendered directly from the server or it might be reached through some interaction on the frontend. If the view is being rendered on the server side, it makes sense to provide the bootstrap data along with the template thus avoiding a extra call for data fetch. On the other hand, if we reach the view through some frontend interactions, we have to fetch the data from server through an AJAX call. A central datastore encapsulates the logic of doing the right thing in both the cases.

Wednesday, June 12, 2013

We have routers

I am now beginning work on the second major screen of the app which is the writingdesk. So the first thing to do was to get a router for our app.

Router in Backbone is the same thing as the router in Django or other frameworks. It's job is to load the right view depending on the URL being visited. The URLs can either look like 'http://example.com/#dashboard' or 'http://example.com/dashboard'. If you, like me, find the first ones ugly, it is easy to switch to second kind. Just pass pushState as true when instantiating the router.

The catch is however that since the user can now bookmark this url or hit refresh, your server will also need to be ready to serve this URL if asked for. That was easy to achieve with my limited number of views and screens.

Currently I am trying to be figure out a good way for 1) loading of CSS files 2) loading a large template for the second screen. I had hoped that requirejs would have a plugin for css files as well but turns out that detecting when a CSS file has loaded is not possible with much reliability. Hence there is no official css plugin for requirejs.

Tuesday, June 11, 2013

You cannot REST all the time

In any app of reasonable size, there are going to be API endpoints other than the REST API points corresponding to resources. For example, there may be a special endpoint for importing files which may lead to creation of one or more resources.

It is however a good idea to have these endpoints speak the same language of codes and return values as the REST endpoints thus making the whole thing more consistent. With some tweaks to the aging FileUploader, which included adding support for csrf token in AJAX request, treating 201 as a success code, I have my import endpoint pretty close to create endpoint.

I also gave up a little more of my fear and removed the second call to the server for fetching the models in case an event of imported:publicaiton is raised. Now we are living the JS dream where we speak as infrequently to server as possible and be very snappy.

Time has also come for our app to get some routes.