Skip to content

Commit

Permalink
🐛 Fixed path issues (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
abassel authored Jan 14, 2021
1 parent dc8c1ab commit b910b5c
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 29 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,8 @@ pip install Flask-RestGlue

### 3 - Pull the code
```bash
curl -s -o -L https://github.com/abassel/Flask-RestGlue/blob/master/example/tut01_hello_world.py
curl -s -o -L https://github.com/abassel/Flask-RestGlue/blob/master/example/tut01_hello_world.sh
curl -s -O -L https://github.com/abassel/Flask-RestGlue/blob/master/example/tut01_hello_world.py
curl -s -O -L https://github.com/abassel/Flask-RestGlue/blob/master/example/tut01_hello_world.sh
```

### 4 - Run the code
Expand Down
27 changes: 12 additions & 15 deletions flask_rest_glue/__init__.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
from flask import Flask

from . import flask_endpoint, openapi_spec
from .misc import Methods, get_default_api_info
from .misc import Methods, get_default_api_info, url_join


class FlaskRestGlue:
def __init__(self, url="http://127.0.0.1:5000", path="/", spec_path=None, flask_app=None, api_info=None):
self._path = path
def __init__(self, url="http://127.0.0.1:5000", path="/", spec_path=None, flask_app=None, api_info=None, gen_map=True):
self._path = url_join([path])
self._spec_path = spec_path
self._flask_api = flask_app or Flask(__name__)
self._pending_introspection = {}
self._api_info = api_info
self._gen_map = gen_map
self._openapi_spec = None

if self._path[-1] != "/":
self._path += "/"

if self._path[0] != "/":
self._path = f"/{self._path}"

if not self._spec_path:
self._spec_path = self._path + "spec"
if self._spec_path:
self._spec_path = url_join([spec_path])
else:
self._spec_path = url_join([self._path, "spec"])

if not self._api_info:
self._api_info = get_default_api_info(base_url=url, path_spec=self._spec_path)
Expand Down Expand Up @@ -57,18 +54,18 @@ def build(self):
openapi_spec_dict["paths"].update(spec_path)

# Generate endpoint for each class
flask_endpoint.build_class_endpoint(self._flask_api, cls, class_name_lower, methods)
flask_endpoint.build_class_endpoint(self._flask_api, cls, class_name_lower, methods, self._path)

flask_endpoint.build_flask_openapi_spec_endpoint(self._flask_api, openapi_spec_dict, self._spec_path, self._api_info)
flask_endpoint.build_flask_openapi_spec_endpoint(self._flask_api, openapi_spec_dict, self._spec_path, self._api_info, self._path, self._gen_map)

self._openapi_spec = openapi_spec_dict

self._flask_api.config["JSON_SORT_KEYS"] = False

return self._flask_api

def run(self):
def run(self, *args, **kwargs):

flask_api = self.build()

flask_api.run()
flask_api.run(*args, **kwargs)
28 changes: 19 additions & 9 deletions flask_rest_glue/flask_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

from flask import jsonify, request

from .misc import Methods
from .openapi_spec import get_redoc_html, get_swagger_ui_html
from .misc import Methods, url_join
from .openapi_spec import get_map_html, get_redoc_html, get_swagger_ui_html


def build_flask_openapi_spec_endpoint(flask_api, spec, path_spec, api_info):
def build_flask_openapi_spec_endpoint(flask_api, spec, path_spec, api_info, root_path, gen_map):

@flask_api.route(path_spec)
def json_spec():
Expand All @@ -20,13 +20,23 @@ def swagger_html():
def redoc_html():
return get_redoc_html(**api_info)

if gen_map:
tmp_html = get_map_html(flask_api)

def build_class_endpoint(flask_api, _class, class_name, methods):
@flask_api.route(root_path)
def path_spec_html():
return tmp_html


def build_class_endpoint(flask_api, _class, class_name, methods, path):

# https://dev.to/paurakhsharma/flask-rest-api-part-1-using-mongodb-with-flask-3g7d

root_path = url_join([path, class_name])
root_path_pk = url_join([root_path, "<pk>"])

if Methods.post in methods:
@flask_api.route(f"/{class_name}", endpoint=f"{class_name}_create", methods=["POST"])
@flask_api.route(root_path, endpoint=f"{class_name}_create", methods=["POST"])
def obj_create_post():

if hasattr(_class, "before_any"):
Expand All @@ -44,7 +54,7 @@ def obj_create_post():
return jsonify(json.loads(new_item.to_json()))

if Methods.get in methods:
@flask_api.route(f"/{class_name}", endpoint=f"{class_name}_read", methods=["GET"])
@flask_api.route(root_path, endpoint=f"{class_name}_read", methods=["GET"])
def obj_read():

if hasattr(_class, "before_any"):
Expand All @@ -61,7 +71,7 @@ def obj_read():
return jsonify(json.loads(items.to_json()))

if Methods.get in methods:
@flask_api.route(f"/{class_name}/<pk>", endpoint=f"{class_name}_read_id", methods=["GET"])
@flask_api.route(root_path_pk, endpoint=f"{class_name}_read_id", methods=["GET"])
def obj_read(pk):

if hasattr(_class, "before_any"):
Expand All @@ -78,7 +88,7 @@ def obj_read(pk):
return jsonify(json.loads(item.to_json()))

if Methods.put in methods:
@flask_api.route(f"/{class_name}/<pk>", endpoint=f"{class_name}_update", methods=["PUT"])
@flask_api.route(root_path_pk, endpoint=f"{class_name}_update", methods=["PUT"])
def obj_update(pk):

if hasattr(_class, "before_any"):
Expand All @@ -98,7 +108,7 @@ def obj_update(pk):
return jsonify(json.loads(item.to_json()))

if Methods.delete in methods:
@flask_api.route(f"/{class_name}/<pk>", endpoint=f"{class_name}_delete", methods=["DELETE"])
@flask_api.route(root_path_pk, endpoint=f"{class_name}_delete", methods=["DELETE"])
def obj_delete(pk):

if hasattr(_class, "before_any"):
Expand Down
15 changes: 15 additions & 0 deletions flask_rest_glue/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,18 @@ def get_default_api_info(base_url, path_spec):
"openapi_url": f"{base_url}{path_spec}"
}
return default_api_info


def url_join(pieces):

# pieces = ["", "//home", "/User/Desktop", "file.txt"]
out = '/'.join(s.strip('/') for s in pieces)
# '/home/User/Desktop/file.txt'

if len(out) == 0:
return "/"

if out[0] != "/":
out = f"/{out}"

return out
41 changes: 38 additions & 3 deletions flask_rest_glue/openapi_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import mongoengine as mongo
from mongoengine.base import BaseField, ComplexBaseField

from .misc import Methods
from .misc import Methods, url_join

base_types_mapping = {
"ObjectIdField": {"type": "integer", "format": "int64"},
Expand Down Expand Up @@ -84,8 +84,8 @@ def generic_endpoint_spec(class_name, operation, require_id):
def gen_openapi_path_spec(class_name, methods, path):
toRet = OrderedDict()

path_with_id = f"{path}{class_name}/{{id}}"
path_no_id = f"{path}{class_name}"
path_no_id = url_join([path, class_name])
path_with_id = url_join([path, class_name, "{id}"])

toRet[path_with_id] = OrderedDict()
toRet[path_no_id] = OrderedDict()
Expand Down Expand Up @@ -194,6 +194,41 @@ def mokeypatch_mongoengine():
from typing import Any, Dict, Optional, OrderedDict


# Generate basic html map with all possible routes inside flask
def get_map_html(flask_api) -> str:

endpoint_routes = {}
for rule in flask_api.url_map.iter_rules():
methods = ','.join(sorted(rule.methods))
endpoint_routes[f"{rule.rule}{methods}"] = rule.rule, methods

html = """
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div>
<ul>
"""

for t in sorted(endpoint_routes.keys()):
route = endpoint_routes[t]
print(route)
tmp = route[0].replace("<", "&lt;").replace(">", "&gt;")
html += f"<li><a href='{tmp}'>{tmp} {route[1]}</a></li>"

html += """
</ul>
</div>
</body>
</html>
"""

return html


def get_swagger_ui_html(
*,
openapi_url: str,
Expand Down

0 comments on commit b910b5c

Please sign in to comment.