Skip to content

Instantly share code, notes, and snippets.

@jameskeane
Last active December 15, 2015 05:19
Show Gist options
  • Save jameskeane/5208276 to your computer and use it in GitHub Desktop.
Save jameskeane/5208276 to your computer and use it in GitHub Desktop.
Simple DFA based HTTP dispatch
import nails
class IndexController(nails.Controller):
def index(self, request):
return "Hello World from controller!"
def proof(self, request):
return "Proof that routing is working"
def test_regex(self, request, id):
return "id is %s" % id
class HelloWorld(nails.Application):
urls = [
(r'^/?$', IndexController().index),
(r'^/test/:id/?$', IndexController().test_regex),
(r'^/proof$', IndexController().proof),
]
if __name__ == '__main__':
app = HelloWorld()
app.run()
from werkzeug.serving import run_simple
from werkzeug.wrappers import Request, Response
import plex
from plex.traditional import re as plexre
from plex import Lexicon, Scanner
from cStringIO import StringIO
import re
class Application(object):
def __init__(self):
self.build_lexicon()
def dispatch_request(self, request):
# Build a plex scanner to parse the request path
# and unpack it
try:
scanner = Scanner(self.lexicon, StringIO(request.path))
(action, regex), matched_path = scanner.read()
except plex.errors.UnrecognizedInput:
return self.error(404, request)
# Parse the path to get the route parameters
params = re.match(regex, matched_path).groupdict()
# Call the action and handle the response
response = action(request, **params)
return self.handle_response(response)
def wsgi_app(self, environ, start_response):
request = Request(environ)
response = self.dispatch_request(request)
return response(environ, start_response)
def error(self, code, request):
return Response('Error %d' % code, status=code)
def __call__(self, environ, start_response):
return self.wsgi_app(environ, start_response)
def run(self, host='127.0.0.1', port=8000):
run_simple(host, port, self, use_debugger=True, use_reloader=True)
def build_lexicon(self):
# route is (regular expression, controller function)
# Notice, that we pass along the original regular expression
# because we will need to run it again, to grab the matches
lexicons = []
for route, action in self.urls:
lexicons.append((
plexre(re.sub(r':([^/]+)', r'[^/]+', route)), # convert :parameters into regex
(
action,
re.sub(r':([^/]+)', r'(?P<\1>[^/]+)', route) # :param into named regex
)
))
self.lexicon = Lexicon(lexicons)
def handle_response(self, response):
# TODO: strings -> Response objects
# dicts -> json Response objects
# pass through Response objects
# figure out how to wrap yields
return Response(response)
class Controller(object):
def as_resource(self):
pass
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment