box-o-sand/ares/app.py

153 lines
4.3 KiB
Python

from __future__ import print_function
import json
import re
import sys
from pprint import pformat
from traceback import print_exc
from wsgiref.simple_server import make_server
class PersonModel(object):
__people__ = [
{
'name': {
'first': 'Hammy',
'last': 'Spammy',
},
'age': 42,
'id': 1,
},
{
'name': {
'first': 'Sampers',
'last': 'Dancer',
},
'age': 38,
'id': 2
},
]
def __init__(self):
self._index()
def _index(self):
self.__people_by_id__ = dict(((p['id'], p) for p in self.__people__))
def getall(self):
return self.__people__
def get(self, person_id):
return self.__people_by_id__[person_id]
def add(self, person):
person['id'] = len(self.__people__) + 1
self.__people__.append(person)
self._index()
return person['id']
class PersonApp(object):
__routes__ = [
(_m, _k, re.compile('^{}$'.format(_k)), _v) for _m, _k, _v in (
('GET', '/people.json', 'all'),
('POST', '/people.json', 'new'),
('GET', '/people/(.*)\.json', 'get'),
('GET', '/', 'echo')
)
]
def __init__(self):
self.people = PersonModel()
print('Routes = {}'.format(pformat(self.__routes__)))
def __call__(self, environ, start_response):
path = '/' + environ.get('PATH_INFO', '').lstrip('/')
request_method = environ.get('REQUEST_METHOD', 'GET')
environ.update({
'app.path': path,
'app.request_method': request_method,
})
method_name = 'not_found'
for route_req_method, route, route_re, route_method in self.__routes__:
if route_req_method == request_method:
match = route_re.match(path)
if match:
print('Found match: {!r}'.format(match.re.pattern))
environ['app.route_match'] = match
method_name = route_method
break
try:
return getattr(self, method_name)(environ, start_response)
except AttributeError, exc:
print_exc()
return self.not_found(environ, start_response)
def not_found(self, environ, start_response):
print('Nothing matched: {} {!r}'.format(
environ['app.request_method'], environ['app.path']
))
return self._return_json(
start_response, {'error': 'Not Found'},
status='404 Not Found'
)
def bad_request(self, environ, start_response):
return self._return_json(
start_response, {'error': 'Bad Request'},
status='400 Bad Request'
)
def get(self, environ, start_response):
person_id = environ['app.route_match'].group(1)
if not person_id.isdigit():
return self.bad_request(environ, start_response)
person = self.people.get(int(person_id))
return self._return_json(start_response, {'person': person})
def all(self, environ, start_response):
return self._return_json(start_response, self.people.getall())
def new(self, environ, start_response):
person = json.loads(
environ['wsgi.input'].read(int(environ['CONTENT_LENGTH']))
)
person_id = self.people.add(person)
return self._return_json(
start_response, {}, status='201 Created',
extra_headers=[
('location', '/people/{}.json'.format(person_id))
]
)
def echo(self, environ, start_response):
return self._return_json(start_response, {'here?': 'yup'})
def _return_json(self, start_response, json_dict, status='200 OK',
extra_headers=()):
body = json.dumps(json_dict)
start_response(status, [
('content-type', 'application/x-json'),
('content-length', str(len(body)))
] + list(extra_headers))
return [body]
def main():
server = make_server('0.0.0.0', 9282, PersonApp())
try:
print('Serving on 0.0.0.0:9282')
server.serve_forever()
return 1
except KeyboardInterrupt:
return 0
if __name__ == '__main__':
sys.exit(main())