2
votes

I want to be able to route my requests in a similar way ASP.net MVC does.

For example the address /Home/Index/query-string/ should map the request to HomeController and call the Index method.

I made an implementation for this and it works, but I want to know a better way to do it. I've just started using Google App Engine and Python for the first time and I don't have much experience for developing websites and web applications.

Here's my implementation

The Yaml file:

- url: /.*
script: router.app

Routing Configuration:

def StartUp():
    sys.path.append(os.path.join(os.getcwd(), 'System'))
    sys.path.append(os.path.join(os.getcwd(), 'Controllers'))
    sys.path.append(os.path.join(os.getcwd(), 'Models'))
    app.run()

app = webapp2.WSGIApplication([webapp2.Route('/', handler=Router, name='Default', defaults={'handler': 'home', 'method': 'index', 'query': ''}, build_only=False, handler_method='map'),
                            webapp2.Route('/<query>', handler=Router, name='DefaultC', defaults={'handler': 'home', 'method': 'index'}, build_only=False, handler_method='map'),
                            webapp2.Route('/<handler>/', handler=Router, name='DefaultCS', defaults={'method': 'index', 'query': ''}, build_only=False, handler_method='map'),
                            webapp2.Route('/<handler>/<query>', handler=Router, name='DefaultCA', defaults={'method': 'index'}, build_only=False, handler_method='map'),
                            webapp2.Route('/<handler>/<method>/', handler=Router, name='DefaultCAS', defaults={'query': ''}, build_only=False, handler_method='map'),
                            webapp2.Route('/<handler>/<method>/<query>', handler=Router, name='DefaultAll', build_only=False, handler_method='map'),
                            webapp2.Route('/<handler>/<method>/<query>/', handler=Router, name='DefaultAllS', build_only=False, handler_method='map')],
                            debug=True)

if __name__ == '__main__':
    StartUp()

The router

class Router(webapp2.RequestHandler):

    def getControllerName(self, handler):
            handler = handler.lower()
            if(len(handler) == 0):
                    """ Error - redirect to error page """
                    return webapp2.redirect('/Error/')
            if len(handler) == 1:
                    handler = handler[0].capitalize()
            else:
                    handler = handler[0].capitalize() + handler[1:]

            handler = handler + 'Controller'

            return handler

    def getActionName(self, method):
            method = method.lower()
            if(len(method) == 0):
                    """ Error - redirect to error page """
                    return webapp2.redirect('/Error/')
            if len(method) == 1:
                    method = method[0].capitalize()
            else:
                    method = method[0].capitalize() + method[1:]

            requestType = self.request.method.lower()
            requestType = requestType[0].capitalize() + requestType[1:]

            return method

    def loadController(self, controllerName):
            """ Load the controller """
            try:
                    fileName, pathName, description = imp.find_module(controllerName, None)
                    module = imp.load_module(controllerName, fileName, pathName, description)

                    # Add checking if class was found
                    controllerRef = getattr(module, controllerName)
                    return controllerRef

            except ImportError, args:
                    logging.error('Error importing controller. ' + pprint.saferepr(args))
            except Exception, args:
                    logging.error('Exception. ' + pprint.saferepr(args))
            finally:
                    fileName.close()

    def loadAction(self, controller, actionName):
            try:
                    actionRef = getattr(controller, actionName)
            except Exception, args:
                    logging.error('Exception. ' + pprint.saferepr(args))
            return actionRef

    def callController(self, controllerName, actionName, query):
            try:
                    """ Load the controller """
                    controllerRef = self.loadController(controllerName)
                    controller = controllerRef(self, query)
                    actionRef = self.loadAction(controller, actionName)
                    actionRef()
            except Exception, args:
                    logging.error('Exception. ' + pprint.saferepr(args))

    def map(self, handler, method, query):
            query = query.lower()
            """ Create Names for Controller and Action"""
            controllerName = self.getControllerName(handler)
            actionName = self.getActionName(method)

            self.callController(controllerName, actionName, query)

Here's my Home controller:

class HomeController(MVC.Controller):

    def Index(self):

            path = os.path.join(os.path.dirname('Views/Home/'), 'home.html')
            self.Request.response.out.write(template.render(path, None))
1

1 Answers

0
votes

Using this approach I can't find a better way of doing it.

Another way of doing it is to use decorators on classes and methods to specify the routes (not sure how easy would it be to implement such feature ).

  @RouteFor('/SomePath')
  class HomeController(MVC.Controller):
        @RouteFor('/SomePath/Index')
        def Index(self):
                path = os.path.join(os.path.dirname('Views/Home/'), 'home.html')
                self.Request.response.out.write(template.render(path, None))