Python2.7 で死ぬほどシンプルな REST サーバ
とりあえずコレを見つけて、楽だったのでメモ
このシンプルさでしれっと REST サーバ立つのはいいね。
#!/usr/bin/env python import sys, os, re, shutil, json, urllib, urllib2, BaseHTTPServer # Fix issues with decoding HTTP responses reload(sys) sys.setdefaultencoding('utf8') here = os.path.dirname(os.path.realpath(__file__)) # この辺で、ロジックを定義 def get_records(handler): return { 'test': 'Result!' } # 半分おまじないみたいな感じ def rest_call_json(url, payload=None, with_payload_method='PUT'): 'REST call with JSON decoding of the response and JSON payloads' if payload: if not isinstance(payload, basestring): payload = json.dumps(payload) # PUT or POST response = urllib2.urlopen(MethodRequest(url, payload, {'Content-Type': 'application/json'}, method=with_payload_method)) else: # GET response = urllib2.urlopen(url) response = response.read().decode() return json.loads(response) # 全体のレスポンス設定 class MethodRequest(urllib2.Request): def __init__(self, *args, **kwargs): if 'method' in kwargs: self._method = kwargs['method'] del kwargs['method'] else: self._method = None return urllib2.Request.__init__(self, *args, **kwargs) def get_method(self, *args, **kwargs): return self._method if self._method is not None else urllib2.Request.get_method(self, *args, **kwargs) # リクエストのルーティング定義 class RESTRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): def __init__(self, *args, **kwargs): self.routes = { r'^/$': {'file': 'web/index.html', 'media_type': 'text/html'}, r'^/get$': {'GET': get_records, 'media_type': 'application/json'}, } return BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, *args, **kwargs) def do_HEAD(self): self.handle_method('HEAD') def do_GET(self): self.handle_method('GET') def do_POST(self): self.handle_method('POST') def do_PUT(self): self.handle_method('PUT') def do_DELETE(self): self.handle_method('DELETE') def get_payload(self): payload_len = int(self.headers.getheader('content-length', 0)) payload = self.rfile.read(payload_len) payload = json.loads(payload) return payload def handle_method(self, method): route = self.get_route() if route is None: self.send_response(404) self.end_headers() self.wfile.write('Route not found\n') else: if method == 'HEAD': self.send_response(200) if 'media_type' in route: self.send_header('Content-type', route['media_type']) self.end_headers() else: if 'file' in route: if method == 'GET': try: f = open(os.path.join(here, route['file'])) try: self.send_response(200) if 'media_type' in route: self.send_header('Content-type', route['media_type']) self.end_headers() shutil.copyfileobj(f, self.wfile) finally: f.close() except: self.send_response(404) self.end_headers() self.wfile.write('File not found\n') else: self.send_response(405) self.end_headers() self.wfile.write('Only GET is supported\n') else: if method in route: content = route[method](self) if content is not None: self.send_response(200) if 'media_type' in route: self.send_header('Content-type', route['media_type']) self.end_headers() if method != 'DELETE': self.wfile.write(json.dumps(content)) else: self.send_response(404) self.end_headers() self.wfile.write('Not found\n') else: self.send_response(405) self.end_headers() self.wfile.write(method + ' is not supported\n') def get_route(self): for path, route in self.routes.iteritems(): if re.match(path, self.path): return route return None # サーバ起動処理 def rest_server(port): 'Starts the REST server' http_server = BaseHTTPServer.HTTPServer(('', port), RESTRequestHandler) print 'Starting HTTP server at port %d' % port try: http_server.serve_forever() except KeyboardInterrupt: pass print 'Stopping HTTP server' http_server.server_close() # 実行 def main(argv): rest_server(3000) if __name__ == '__main__': main(sys.argv[1:])
セキュリティ気にしないなら、コレを crontab にでも仕込んでおけば良いかも?
ポート 3000 なんて一般公開しないでしょうよ…ローカルプロセスの都合で一時的にテストサーバがほしいとかでも使える