simonw / djng

Turtles all the way down

This URL has Read+Write access

djng / services_api_ideas.txt
c892dddf » simonw 2009-05-18 Some ideas for how the serv... 1 Services API
2 ============
3
4 Requirements:
5
6 - Maintain a stack of implementations for each service
7 - Only one implementation of a service is "active" at a time
8 - The default API for a service uses the current active implementation
9 - Implementations can be used without participating in the stack at all
10 - Middleware can temporarily push a new service on to the stack, for the
11 duration of the current request
12 - Services temporarily pushed on to the stack are reliably popped off again
13 at the end of the current request, even if an exception is raised
14
15 It would be nice if the solution meant that the current Django APIs for things
16 like accessing the cache or loading a template could remain backwards
17 compatible.
18
19 Some ideas
20 ----------
21
22 # Configure the default service (at the bottom of the stack)
23 djng.template.configure(template_dirs = ('templates/default',))
24
25 # Reconfigure for part of the URL space
26 app = djng.Router(
27 (r'^foo', djng.reconfigure(
28 foo_view, djng.template,
29 template_dirs = ('templates/foo', 'templates/default')
30 )),
31 (r'^bar', bar_view),
32 )
33
34 djng.reconfigure is middleware which wrapes foo_view, then duplicates the
35 current djng.template service and applies a new template_dirs property to it ,
36 based on keyword argument.
37
38 Or... use a decorator:
39
40 app = djng.Router(
41 (r'^foo', djng.reconfigure(
42 djng.template, template_dirs = ('templates/foo', 'templates/default')
43 )(foo_view)),
44 (r'^bar', bar_view),
45 )
46
47 Which could also be written:
48
49 @djng.reconfigure(
50 djng.template, template_dirs = ('templates/foo', 'templates/default')
51 )
52 def foo_view(request):
53 # ...
54
55 Reconfigure is a bit strange though, because the majority of services will
56 probably want a completely new implementation rather than a tweak to the
57 existing one. Caching is a good example:
58
59 # Set the default cache to be an InMemoryCache
60 djng.cache.configure(djng.cache.InMemoryCache())
61
62 # One URL path gets to use memcache instead
63 app = djng.Router(
64 (r'^foo', djng.reconfigure(
65 foo_view, djng.cache, djng.cache.Memcache('127.0.0.1:11221')
66 )),
67 (r'^bar', bar_view),
68 )
69
70 Or as a decorator:
71
72 app = djng.Router(
73 (r'^foo', djng.reconfigure(
74 djng.cache, djng.cache.Memcache('127.0.0.1:11221')
75 )(foo_view)),
76 (r'^bar', bar_view),
77 )
78
79 The signature of djng.reconfigure feels a bit strange though:
80
81 def reconfigure(
82 service_to_reconfigure,
83 [optional new_service_instance],
84 **reconfigure_kwargs
85 ):
86 # ...
87
88 Internally, reconfigure uses a try/finally block to ensure that the altered
89 service implementation pushed on to the stack is popped off by the end of the
90 request.