Search code examples
pythonroutesbottle

bottle: global routing filter


I'M using bottle for a simple app that displays a calendar, and allows the user to specify the year and the month. The following routes are defined:
'/' # current year and current month
'/year' # year and current month
'/year/month' # year and month

However, routes that have an extra / at the end aren't recognized. E.g. '/2015' is ok, but '/2015/' isn't. In order to overcome this, I used a regex routing filter. This works, but makes me define a pattern for each route, and then check explicitly if the route ends with '/'. I'd like to define a global filter which removes the extra slash from the end of the request url (if such exists).

from bottle import route, run, template
import calendar
import time

CAL = calendar.HTMLCalendar(calendar.SUNDAY)
Y, M = time.strftime('%Y %m').split()

@route('/')
@route('/<year:re:\d{4}/?>')
@route('/<year>/<month:re:\d{1,2}/?>')
def cal(year = Y, month = M):
    y = year if year[-1] != '/' else year[:-1]
    m = month if month[-1] != '/' else month[:-1]
    return template(CAL.formatmonth(int(y), int(m))) 

run(host='localhost', port=8080, debug=True)

Solution

  • Instead of creating duplicate routes, I would suggest enforcing a strict url schema with urls ending with slashes and encouraging clients to use it by redirecting from urls not ending with a slash, for example using the following route:

    @route('<path:re:.+[^/]$>')
    def add_slash(path):
        return redirect(path + "/")
    

    (BTW, this is django's default behavior).