Skip to content

Commit

Permalink
Some ideas for how the services API could work
Browse files Browse the repository at this point in the history
  • Loading branch information
Simon Willison committed May 18, 2009
1 parent 77d7b7c commit c892ddd
Showing 1 changed file with 90 additions and 0 deletions.
90 changes: 90 additions & 0 deletions services_api_ideas.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
Services API
============

Requirements:

- Maintain a stack of implementations for each service
- Only one implementation of a service is "active" at a time
- The default API for a service uses the current active implementation
- Implementations can be used without participating in the stack at all
- Middleware can temporarily push a new service on to the stack, for the
duration of the current request
- Services temporarily pushed on to the stack are reliably popped off again
at the end of the current request, even if an exception is raised

It would be nice if the solution meant that the current Django APIs for things
like accessing the cache or loading a template could remain backwards
compatible.

Some ideas
----------

# Configure the default service (at the bottom of the stack)
djng.template.configure(template_dirs = ('templates/default',))

# Reconfigure for part of the URL space
app = djng.Router(
(r'^foo', djng.reconfigure(
foo_view, djng.template,
template_dirs = ('templates/foo', 'templates/default')
)),
(r'^bar', bar_view),
)

djng.reconfigure is middleware which wrapes foo_view, then duplicates the
current djng.template service and applies a new template_dirs property to it ,
based on keyword argument.

Or... use a decorator:

app = djng.Router(
(r'^foo', djng.reconfigure(
djng.template, template_dirs = ('templates/foo', 'templates/default')
)(foo_view)),
(r'^bar', bar_view),
)

Which could also be written:

@djng.reconfigure(
djng.template, template_dirs = ('templates/foo', 'templates/default')
)
def foo_view(request):
# ...

Reconfigure is a bit strange though, because the majority of services will
probably want a completely new implementation rather than a tweak to the
existing one. Caching is a good example:

# Set the default cache to be an InMemoryCache
djng.cache.configure(djng.cache.InMemoryCache())

# One URL path gets to use memcache instead
app = djng.Router(
(r'^foo', djng.reconfigure(
foo_view, djng.cache, djng.cache.Memcache('127.0.0.1:11221')
)),
(r'^bar', bar_view),
)

Or as a decorator:

app = djng.Router(
(r'^foo', djng.reconfigure(
djng.cache, djng.cache.Memcache('127.0.0.1:11221')
)(foo_view)),
(r'^bar', bar_view),
)

The signature of djng.reconfigure feels a bit strange though:

def reconfigure(
service_to_reconfigure,
[optional new_service_instance],
**reconfigure_kwargs
):
# ...

Internally, reconfigure uses a try/finally block to ensure that the altered
service implementation pushed on to the stack is popped off by the end of the
request.

0 comments on commit c892ddd

Please sign in to comment.