1

RESTful routing in Python does not seem to work. For instance,

# Setup a mapper
from routes import Mapper
map = Mapper()
map.connect("add user", "/user", controller = "addUser", action = "add",
  conditions=dict(method=["GET"]))
map.connect("post user", "/user", controller = "postUser", action = "post", 
  conditions=dict(method=["POST"]))
map.connect("update user", "/user/{id}", controller = "updateUser", action = "update", 
  conditions=dict(method=["GET"]))
map.connect("put user", "/user/{id}", controller = "putUser", action = "put", 
  conditions=dict(method=["PUT"]))
map.connect("delete user", "/user/{id}", controller = "deleteUser", action = "delete", 
  conditions=dict(method=["DELETE"]))
map.connect("home", "/", controller = "main", action = "index", conditions=dict(method=["GET"]))

# This is our application object. It could have any name,
# except when using mod_wsgi where it must be "application"
def application(environ, start_response):

   # Get the request uri.
   uri = environ.get('PATH_INFO', '')
   req = uri if uri else '/'

   # Match a URL, returns a dict or None if no match
   mapped = map.match(req)
   print mapped

   # Everything done, return the response:
   if mapped['action'] == 'index' :
      response_body = index(environ, start_response, mapped)
   elif mapped['action'] == 'add':
      response_body = add(environ, start_response, mapped)
   elif mapped['action'] == 'put':
      response_body = put(environ, start_response, mapped)
   elif mapped['action'] == 'delete':
      response_body = delete(environ, start_response, mapped)
   else:
      response_body =  "Not exist."

   status = '200 OK'

   response_headers = [('Content-Type', 'text/html'),
               ('Content-Length', str(len(response_body)))]
   start_response(status, response_headers)

   return [response_body]

It does not care the REST method whether is PUT, DELETE, or POST. It only looks for the match of /user/{id} in my url.

So when I send a DELETE method with http://127.0.0.1/index.py/user/1

I always get {'action': u'update', 'controller': u'updateUser', 'id': u'1'} which is the GET from map.connect("update user", "/user/{id}", controller = "updateUser", action = "update", conditions=dict(method=["GET"]))

Any ideas what have I done wrong?

EDIT

Apache config file,

LoadModule wsgi_module modules/mod_wsgi.so

....

<VirtualHost 127.0.0.1>
    DocumentRoot "${path}/data/localweb"
    ServerName 127.0.0.1
    <Directory "${path}/data/localweb">
        Options FollowSymLinks Indexes ExecCGI
        AllowOverride All
        Order deny,allow
        Allow from 127.0.0.1
        Deny from all
        Require all granted
    </Directory>
    WSGIScriptAlias / C:\...\wsgi\route\basic\index.py
</VirtualHost>

btw, in my Apache error log, I always get this wsgi:error warning with the printed result,

[Sat Aug 15 16:03:41.871541 2015] [wsgi:error] [pid 7068:tid 836] {'action': u'update', 'controller': u'updateUser', 'id': u'1'}

Run
  • 54,938
  • 169
  • 450
  • 748
  • "http://127.0.0.1/index.py/user/1" not equal to "http://127.0.0.1/user/1". Are you working with the wrong index. Directory index of .py (which directory you want it to be). Django also maintained similar errors. The URL must not be your script name in the tag. Otherwise, the region will change. – dsgdfg Aug 15 '15 at 05:30
  • The appearance of ``index.py`` could be an artefact of how mod_wsgi has been setup. Specifically, that ``WSGIScriptAlias`` might be used on a directory rather than a specific WSGI script file, or that ``AddHandler`` method of setting up mod_wsgi was used. The ``SCRIPT_NAME`` or mount point for the app should usually be set right and ``PATH_INFO`` should only include ``/user/...`` which the WSGI application should match fine. The OP should provide their Apache/mod_wsgi configuration. – Graham Dumpleton Aug 15 '15 at 06:12
  • @SDilmac it is the same result with `http://127.0.0.1/user/1` which is `{'action': u'update', 'controller': u'updateUser', 'id': u'1'} `. – Run Aug 15 '15 at 08:05
  • @GrahamDumpleton which part of the setting do u need? Please see my edit above. – Run Aug 15 '15 at 08:06
  • And what do `WSGIScriptAlias` and `AddHandler` have to do with RESTful routes? – Run Aug 15 '15 at 08:09
  • For that mod_wsgi configuration, you should be accessing it as ``http://127.0.0.1/user/1``. But then your ``VirtualHost`` definition is wrong, having wrong argument, which means it wouldn't likely work anyway. You are better off not using ``VirtualHost`` if a Windows box as unlikely you are running multiple sites. So move everything to top level rather than inside of ``VirtualHost``. The use of ``${path}`` also looks wrong as that would require an environment variable to exist of that name, which is not likely to be the case. – Graham Dumpleton Aug 15 '15 at 08:25
  • As to ``WSGISriptAlias/AddHandler``, how you use them dictates what URL path the application would see and so what it would match. So indirectly it has everything to do with the routes mapped in your application. – Graham Dumpleton Aug 15 '15 at 08:26
  • with `http://127.0.0.1/` I do get what I want to get though which is the Python app index page. – Run Aug 15 '15 at 08:29
  • then `http://127.0.0.1/user` I also get the add user page - assume that the method is GET. – Run Aug 15 '15 at 08:30
  • If you are saying you are getting that with the config you had, it doesn't mean that your ``VirtualHost`` definition isn't broken, it still is. The only reason Apache would still use it is because when it can't match any ``VirtualHost`` correctly, it falls back to using the first it found. Thus if it works, then you likely have only the one ``VirtualHost`` defined. – Graham Dumpleton Aug 15 '15 at 08:58
  • sorry friend change line **uri = environ.get('PATH_INFO', '')** To : **uri = os.environ['REQUEST_URI']** – dsgdfg Aug 15 '15 at 08:58
  • The things wrong with your ``VirtualHost`` are that it should be given the IP. It should be ```` is most cases. Plus, ``ServerName`` should be a fully qualified domain name, not an IP. – Graham Dumpleton Aug 15 '15 at 08:59
  • A WSGI application should never use ``REQUEST_URI``. It isn't part of standard WSGI and is something Apache sets. It is the raw URL and hasn't had normalisations performed on it. A WSGI application should use ``PATH_INFO`` for the URL path component mapped below the WSGI application mount point. The mount point will be passed in ``SCRIPT_NAME`` and in this case the mount point should be an empty string. – Graham Dumpleton Aug 15 '15 at 09:01
  • I got it worked anyway - **sort of**! See my answer below! – Run Aug 15 '15 at 09:04
  • Thanks for the suggestion but I think those are considered 'ugly' and outdated these days... – Run Aug 15 '15 at 09:21

1 Answers1

0

I think this might be the answer from http://pylonsbook.com/en/1.0/urls-routing-and-dispatch.html which is quite similar to what I am doing,

map.connect("add user", "/user", controller = "addUser", action = "add",
  conditions=dict(method=["GET"]))
....
map.environ = {'REQUEST_METHOD':'DELETE'}

The problem is that I have to add DELETE or PUT manually which is not ideal at all as it cannot be dynamic.

EDIT:

Found the answer!

request_method = environ.get('REQUEST_METHOD', '')
map.environ = {'REQUEST_METHOD': request_method}
Run
  • 54,938
  • 169
  • 450
  • 748