Login

Publishing service endpoint uri to javascript

Author:
dberansky
Posted:
June 10, 2010
Language:
Python
Version:
1.2
Score:
0 (after 0 ratings)

My application is made up of two main pieces: 1) an ajax client, and 2) backend services supplying data to the ajax client. Django delivers html files that bootstrap the javascript client, which in turns calls back to Django's restful services. Most of javascript code is in static .js files that being delivered to the browser bypassing Django.

When calling back into Django, I started by embedding call endpoints into the javascript code. Soon, I noticed, though, that every time I adjusted an endpoint's url in urls.py, I also had to remember to go back and adjust the javascript. This was suboptimal and violated the DRY principle.

I realized that all the information I needed was already in urls.py. All that needed to be done, was to find a way to expose that information to the javascript environment. The code I'm including does exactly that. It consists of two pieces: a view function and a corresponding javascript template.

The view function will go through all declared urls looking for those whose name ends with '-svc'. These urls are then converted into javascript constants by the template. The url names are slightly mangled to conform to javascript identifier conventions and if you have any url parameters, they will be encoded into something that javascript can easily replace with real values at run time.

For example,

url('^blog/(?P<id>[\d]+/$', 'sample.views.showblog', name='blog-entry')

will become

svc.__BLOG_ENTRY = "/blog/{id}/"

to get the uri from your javascript code, you simply make this call:

svc('BLOG_ENTRY', {id: 12345})

and you'll get back

/blog/12345/

Requirements: the javascript template assumes availability of the Namespace library by Maxime Bouroumeau-Fuseau (http://code.google.com/p/namespacedotjs/)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
==== view function ====
def endpoints(request, namespace = ""):
    """
        Returns javascript for mapping service endpoint names to urls.

        For this view to work properly, all urls that are to be made
        available to javascript must be named and end in '-svc'.
        If these urls use regular expressions for defining parameters,
        all parameters must be named as well.

        The view uses Django internal url resolver to iterate over a list
        of all currently defined url patterns.  It looks for named patterns
        with the name ending in '-svc'.  For these patterns, the named
        regex group definition is replaced with the group name enclosed
        in curley braces.  Url pattern names will be translated into
        javascript variable names by converting all letters to the upper
        case and replacing '-' with '_'.

        For example:

           url('^blog/(?P<id>[\d]+/$', 'sample.views.showblog', name='blog-entry')

        will be exported as

           svc.__BLOG_ENTRY = "/blog/{id}/"

        if the namespace parameter is set (e.g. 'my.namespace'), the service will be exported as

           my.namespace.svc.BLOG_ENTRY

        the the template for additional documentation 
    """
    resolver = get_resolver(None)

    endpoints = {}

    for name in resolver.reverse_dict:
        if isinstance(name, str) and name.endswith('-svc'):
            url_regex = resolver.reverse_dict.get(name)[1]
            param_names = resolver.reverse_dict.get(name)[0][0][1]
            arg_pattern = r'\(\?P\<[^\)]+\)'  #matches named groups in the form of (?P<name>pattern)

            i = 0
            for match in re.findall(arg_pattern, url_regex):
                url_regex = url_regex.replace(match, "{%s}"%param_names[i])
                i += 1

            name = name.upper().replace("-","_")
            endpoints[name] = "/" + url_regex[:-1]

    return render("endpoints.js", {'endpoints':endpoints, 'ns':namespace}, mimetype="application/javascript")

==== end view function ====



==== endpoints.js template ====
// Namespace is a javascript library by Maxime Bouroumeau-Fuseau 
// available from http://code.google.com/p/namespacedotjs/
{%if ns%}Namespace('{{ns}}'){%endif%}

/*
   This function provides a map into available service endpoint urls.

   To get a service url, call this function with the service name.  For
   parametrized urls, also pass a dictionary with parameter name/value
   paris.

   For example, calling:

      svc('CRTRACKER_PL_CLIENT_BUILDS_SVC', {change_request:345, pl:'DFDSF.0', client:'MT'})

   will return

      /crtracker/345/productline/DFDSF.0/client/MT/build/
 */
{%if ns%}{{ns}}.{%endif%}svc = function(name, kwargs) {
   var url = {%if ns%}{{ns}}.{%endif%}svc["__"+name];

   for( name in kwargs) {
       url = url.replace("{"+name+"}", kwargs[name]);
    }

    return url;
}

{% for name, url in endpoints.items %}
{%if ns%}{{ns}}.{%endif%}svc.__{{name}} = '{{url}}';
{% endfor %}


==== end template ====

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 3 months ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 3 months, 1 week ago
  3. Serializer factory with Django Rest Framework by julio 10 months, 1 week ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 10 months, 4 weeks ago
  5. Help text hyperlinks by sa2812 11 months, 3 weeks ago

Comments

Please login first before commenting.