ShiftEleven

Letting Browsers use all of the RESTful Methods in Google App Engine

So there was much talk and whathave you about Google's new App Engine, and after viewing the tutorials and reading the documentation, I thought it was pretty rad too. Because I was using rack for some previous stuff, WSGI felt right at home (probably because rack was modeled after WSGI). There was one thing that bothered me however. When writing a class using their webapp framework there isn't any magic param name, like _method, that I could use to mock requests methods like DELETE and PUT since the browser doesn't support those HTTP methods.

Well my friends, fear not. If you enjoy the sweet freedom of RESTful urls, I'm here to help. Since this is all built on top of WSGI, we can create a some new Middleware to sit before the application to resolve this little issue.

MockHTTPMethodMiddleware

from google.appengine.ext import webapp

class MockHTTPMethodMiddleware(object):
  def __init__(self, app):
    self.app = app

  def __call__(self, environ, start_response):
    method = webapp.Request(environ).get('_method')
    if method:
      environ['REQUEST_METHOD'] = method.upper()
    return self.app(environ, start_response)

The code is pretty simple. So when this middleware is called, it processes the environ into a Request object. From there, I just inspect the params for a key called _method. If that param exists, then it overwrites the REQUEST_METHOD and bam...we have mocked the HTTP method of our choosing.

Putting that code to good use

Let's pretend that this is our class is something inane like this:

from google.appengine.ext import webapp

class MethodTest(webapp.RequestHandler):
  def get(self):
    self.response.headers["Content-Type"] = 'text/text'
    self.response.out.write("Get")

  def put(self):
    self.response.headers["Content-Type"] = 'text/text'
    self.response.out.write("Put")

So now when you are writing your main method that creates the WSGI application, you would write it something like:

import wsgiref.handlers

def main():
  app = webapp.WSGIApplication(
      [('/', MethodTest)],
      debug=True)
  wsgiref.handlers.CGIHandler().run(MockHTTPMethodMiddleware(app))

if __name__ == "__main__":
  main()

Notice that in the run method arguments, MockHTTPMethodMiddleware takes app as a parameter, thus MockHTTPMethodMiddleware will run before it runs app.

Conclusion

While there wasn't support out of the box for mocking HTTP methods for browsers, with a little help from a WSGI Middleware class, it's not too hard to add that functionality in, nor is it hard to add anything else you would want to use.

Comments

comments powered by Disqus