Forráskód Böngészése

Build a handler factory
Reduce the number of config files

ZiB 5 hónapja
szülő
commit
3a746d78c1
5 módosított fájl, 70 hozzáadás és 87 törlés
  1. 40 59
      app.py
  2. 29 0
      config.json
  3. 0 5
      global.json
  4. 1 1
      gunicorn.conf.py
  5. 0 22
      services.json

+ 40 - 59
app.py

@@ -2,6 +2,7 @@ import json
 import os
 from flask import Flask, request, jsonify
 from flask_cors import CORS
+from functools import wraps
 
 _url_prefix = os.environ.get("URL_PREFIX", "room").strip("/")
 _port = os.environ.get("FLASK_PORT", "5000").strip()
@@ -14,17 +15,17 @@ PORT = int(_port)
 app = Flask(__name__)
 CORS(app)
 
-# Service config
-with open(os.path.join(_here, "services.json")) as f:
-  SERVICES = json.load(f)
-DEFAULT_SERVICE = next(iter(SERVICES))
-
-# Global config
-with open(os.path.join(_here, "global.json")) as f:
-  GLOBAL = json.load(f)
-if 'taxes' not in GLOBAL or 'sales' not in GLOBAL['taxes']:
+# Config
+with open(os.path.join(_here, "config.json")) as f:
+  CONFIG = json.load(f)
+if not CONFIG or 'services' not in CONFIG or 'global' not in CONFIG:
+  raise ValueError('CONFIG: Missing services or global')
+SERVICES = CONFIG['services']
+GLOBAL = CONFIG['global']
+if not GLOBAL or 'taxes' not in GLOBAL or 'sales' not in GLOBAL['taxes']:
   raise ValueError('GLOBAL: Missing sales tax')
 SALES_TAX = GLOBAL['taxes']['sales']
+DEFAULT_SERVICE = next(iter(SERVICES))
 
 # Formatters
 def dollar_fmt(value: float) -> str:
@@ -63,6 +64,17 @@ def _response(**data) -> str:
     _dict['details'] = details_fmt(data.get('details'))
   return jsonify(_dict)
 
+def make_handler(*transforms):
+  def handler():
+    try:
+      data = _request(request)
+    except (TypeError, ValueError):
+      return jsonify({'error': 'Invalid or missing parameters'}), 400
+    for transform in transforms:
+      transform(data)
+    return _response(**data)
+  return handler
+
 # Actual math
 def _n2l(data: dict) -> None:
   svc = data['service']
@@ -130,62 +142,31 @@ def _r2l(data: dict) -> None:
   data['listed'] = round(listed, 2)
 
 # Routing
+routes = [
+  ('net_to_list',    _n2l),
+  ('list_to_net',    _l2n),
+  ('list_to_retail', _l2r),
+  ('retail_to_list', _r2l),
+  ('net_to_retail',  _n2l, _l2r),
+  ('retail_to_net',  _r2l, _l2n),
+]
+for route_def in routes:
+  endpoint, *transforms = route_def
+  handler = make_handler(*transforms)
+  # Flask requires unique function names
+  handler.__name__ = endpoint
+  app.add_url_rule(
+    f"{URL_PREFIX}/{endpoint}",
+    endpoint=endpoint,
+    view_func=handler,
+    methods=['GET', 'POST']
+  )
 @app.route(f"{URL_PREFIX}/services", methods=['GET'])
 def list_services():
   return jsonify([
     {'key': key, 'name': cfg['name']}
     for key, cfg in SERVICES.items()
   ])
-@app.route(f"{URL_PREFIX}/net_to_list", methods=['GET', 'POST'])
-def net_to_list():
-  try:
-    data = _request(request)
-  except (TypeError, ValueError):
-    return jsonify({'error': 'Invalid or missing parameters'}), 400
-  _n2l(data)
-  return _response(**data)
-@app.route(f"{URL_PREFIX}/list_to_net", methods=['GET', 'POST'])
-def list_to_net():
-  try:
-    data = _request(request)
-  except (TypeError, ValueError):
-    return jsonify({'error': 'Invalid or missing parameters'}), 400
-  _l2n(data)
-  return _response(**data)
-@app.route(f"{URL_PREFIX}/list_to_retail", methods=['GET', 'POST'])
-def list_to_retail():
-  try:
-    data = _request(request)
-  except (TypeError, ValueError):
-    return jsonify({'error': 'Invalid or missing parameters'}), 400
-  _l2r(data)
-  return _response(**data)
-@app.route(f"{URL_PREFIX}/retail_to_list", methods=['GET', 'POST'])
-def retail_to_list():
-  try:
-    data = _request(request)
-  except (TypeError, ValueError):
-    return jsonify({'error': 'Invalid or missing parameters'}), 400
-  _r2l(data)
-  return _response(**data)
-@app.route(f"{URL_PREFIX}/net_to_retail", methods=['GET', 'POST'])
-def net_to_retail():
-  try:
-    data = _request(request)
-  except (TypeError, ValueError):
-    return jsonify({'error': 'Invalid or missing parameters'}), 400
-  _n2l(data)
-  _l2r(data)
-  return _response(**data)
-@app.route(f"{URL_PREFIX}/retail_to_net", methods=['GET', 'POST'])
-def retail_to_net():
-  try:
-    data = _request(request)
-  except (TypeError, ValueError):
-    return jsonify({'error': 'Invalid or missing parameters'}), 400
-  _r2l(data)
-  _l2n(data)
-  return _response(**data)
 
 # Main app
 if __name__ == '__main__':

+ 29 - 0
config.json

@@ -0,0 +1,29 @@
+{
+  "global": {
+    "taxes": {
+      "sales": 0.157
+    }
+  },
+  "services": {
+    "airbnb": {
+      "name": "AirBnB",
+      "taxes": {
+        "flat_tax": 4,
+        "provider_pays": true
+      },
+      "fees": {
+        "commission": 0.03,
+        "client_fee": 0.1411235955
+      }
+    },
+    "booking": {
+      "name": "Booking.com",
+      "taxes": {
+        "wrong": 0.145
+      },
+      "fees": {
+        "commission": 0.15
+      }
+    }
+  }
+}

+ 0 - 5
global.json

@@ -1,5 +0,0 @@
-{
-  "taxes": {
-    "sales": 0.157
-  }
-}

+ 1 - 1
gunicorn.conf.py

@@ -10,4 +10,4 @@ accesslog = "-"
 access_log_format = '%({host}i)s %(r)s %(s)s %(b)s %(h)s'
 
 reload = True
-debug = False
+debug = True

+ 0 - 22
services.json

@@ -1,22 +0,0 @@
-{
-  "airbnb": {
-    "name": "AirBnB",
-    "taxes": {
-      "flat_tax": 4,
-      "provider_pays": true
-    },
-    "fees": {
-      "commission": 0.03,
-      "client_fee": 0.1411235955
-    }
-  },
-  "booking": {
-    "name": "Booking.com",
-    "taxes": {
-      "wrong": 0.145
-    },
-    "fees": {
-      "commission": 0.15
-    }
-  }
-}