[refactor] update to avoid using global variables, and configuration are not stored in /etc/half_api anymore
Added domain_middleware
This commit is contained in:
parent
781736c151
commit
f5ebabbcd4
@ -6,9 +6,6 @@ runner.
|
|||||||
It defines the following globals :
|
It defines the following globals :
|
||||||
|
|
||||||
- routes (contains the Route objects for the application)
|
- routes (contains the Route objects for the application)
|
||||||
- d_acl (a dictionnary of the active acls for the current project)
|
|
||||||
- d_api (a dictionnary of the routes depending on the routers definition in
|
|
||||||
the project)
|
|
||||||
- application (the asgi application itself - a starlette object)
|
- application (the asgi application itself - a starlette object)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -21,7 +18,9 @@ from starlette.middleware.authentication import AuthenticationMiddleware
|
|||||||
|
|
||||||
|
|
||||||
# module libraries
|
# module libraries
|
||||||
from halfapi.conf import SECRET, PRODUCTION, DOMAINSDICT
|
from halfapi.conf import config, SECRET, PRODUCTION, DOMAINSDICT
|
||||||
|
|
||||||
|
from .lib.domain_middleware import DomainMiddleware
|
||||||
|
|
||||||
from halfapi.lib.jwt_middleware import JWTAuthenticationBackend
|
from halfapi.lib.jwt_middleware import JWTAuthenticationBackend
|
||||||
|
|
||||||
@ -44,20 +43,16 @@ routes += [
|
|||||||
Route('/halfapi/acls', get_acls)
|
Route('/halfapi/acls', get_acls)
|
||||||
]
|
]
|
||||||
|
|
||||||
d_api = {}
|
|
||||||
d_acl = {}
|
|
||||||
|
|
||||||
for domain, m_domain in DOMAINSDICT.items():
|
for route in gen_starlette_routes(DOMAINSDICT()):
|
||||||
for route in gen_starlette_routes(m_domain):
|
|
||||||
routes.append(route)
|
routes.append(route)
|
||||||
|
|
||||||
d_api[domain], d_acl[domain] = api_routes(m_domain)
|
|
||||||
|
|
||||||
|
|
||||||
application = Starlette(
|
application = Starlette(
|
||||||
debug=not PRODUCTION,
|
debug=not PRODUCTION,
|
||||||
routes=routes,
|
routes=routes,
|
||||||
middleware=[
|
middleware=[
|
||||||
|
Middleware(DomainMiddleware, config=config),
|
||||||
Middleware(AuthenticationMiddleware,
|
Middleware(AuthenticationMiddleware,
|
||||||
backend=JWTAuthenticationBackend(secret_key=SECRET))
|
backend=JWTAuthenticationBackend(secret_key=SECRET))
|
||||||
],
|
],
|
||||||
|
@ -20,7 +20,7 @@ def cli(ctx, version):
|
|||||||
"""
|
"""
|
||||||
if version:
|
if version:
|
||||||
from halfapi import version
|
from halfapi import version
|
||||||
return click.echo(version())
|
click.echo(version())
|
||||||
|
|
||||||
if IS_PROJECT:
|
if IS_PROJECT:
|
||||||
from . import config
|
from . import config
|
||||||
|
@ -8,8 +8,9 @@ import click
|
|||||||
|
|
||||||
from .cli import cli
|
from .cli import cli
|
||||||
from ..conf import (
|
from ..conf import (
|
||||||
|
read_config,
|
||||||
PROJECT_NAME,
|
PROJECT_NAME,
|
||||||
DOMAINS,
|
DOMAINSDICT,
|
||||||
HOST,
|
HOST,
|
||||||
PORT,
|
PORT,
|
||||||
PRODUCTION,
|
PRODUCTION,
|
||||||
@ -26,12 +27,13 @@ base_dir = {BASE_DIR}
|
|||||||
|
|
||||||
[domains]"""
|
[domains]"""
|
||||||
|
|
||||||
for dom in DOMAINS:
|
for dom in DOMAINSDICT():
|
||||||
CONF_STR = '\n'.join((CONF_STR, dom))
|
CONF_STR = '\n'.join((CONF_STR, dom))
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
def config():
|
def config():
|
||||||
"""
|
"""
|
||||||
Lists config parameters and their values
|
Lists config parameters and their values
|
||||||
"""
|
"""
|
||||||
click.echo(CONF_STR)
|
click.echo(read_config())
|
||||||
|
@ -2,14 +2,15 @@
|
|||||||
"""
|
"""
|
||||||
cli/domain.py Defines the "halfapi domain" cli commands
|
cli/domain.py Defines the "halfapi domain" cli commands
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# builtins
|
# builtins
|
||||||
import logging
|
import logging
|
||||||
|
import sys
|
||||||
|
|
||||||
import click
|
import click
|
||||||
|
|
||||||
|
|
||||||
from .cli import cli
|
from .cli import cli
|
||||||
from ..conf import DOMAINS, DOMAINSDICT
|
from ..conf import config, write_config, DOMAINS, DOMAINSDICT
|
||||||
|
|
||||||
from ..lib.schemas import schema_dict_dom
|
from ..lib.schemas import schema_dict_dom
|
||||||
|
|
||||||
@ -19,29 +20,46 @@ logger = logging.getLogger('halfapi')
|
|||||||
#################
|
#################
|
||||||
# domain create #
|
# domain create #
|
||||||
#################
|
#################
|
||||||
def create_domain():
|
def create_domain(domain_name: str, module_path: str):
|
||||||
"""
|
logger.info('Will add **%s** (%s) to current halfAPI project',
|
||||||
TODO: Implement function to create (add) domain to a project through cli
|
domain_name, module_path)
|
||||||
"""
|
|
||||||
raise NotImplementedError
|
if domain_name in DOMAINSDICT():
|
||||||
|
logger.warning('Domain **%s** is already in project')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if not config.has_section('domains'):
|
||||||
|
config.add_section('domains')
|
||||||
|
|
||||||
|
config.set('domains', domain_name, module_path)
|
||||||
|
write_config()
|
||||||
|
|
||||||
|
|
||||||
###############
|
###############
|
||||||
# domain read #
|
# domain read #
|
||||||
###############
|
###############
|
||||||
def list_routes(domain_name):
|
def list_routes(domain, m_dom):
|
||||||
"""
|
"""
|
||||||
Echoes the list of the **domain_name** active routes
|
Echoes the list of the **m_dom** active routes
|
||||||
"""
|
"""
|
||||||
|
|
||||||
click.echo(f'\nDomain : {domain}')
|
click.echo(f'\nDomain : {domain}')
|
||||||
|
|
||||||
m_dom = DOMAINSDICT[domain_name]
|
for key, item in schema_dict_dom({domain: m_dom}).get('paths', {}).items():
|
||||||
for key, item in schema_dict_dom(m_dom).get('paths', {}).items():
|
|
||||||
methods = '|'.join(list(item.keys()))
|
methods = '|'.join(list(item.keys()))
|
||||||
click.echo(f'{key} : {methods}')
|
click.echo(f'{key} : {methods}')
|
||||||
|
|
||||||
|
|
||||||
|
def list_api_routes():
|
||||||
|
"""
|
||||||
|
Echoes the list of all active domains.
|
||||||
|
"""
|
||||||
|
|
||||||
|
click.echo('# API Routes')
|
||||||
|
for domain, m_dom in DOMAINSDICT().items():
|
||||||
|
list_routes(domain, m_dom)
|
||||||
|
|
||||||
|
|
||||||
@click.option('--read',default=False, is_flag=True)
|
@click.option('--read',default=False, is_flag=True)
|
||||||
@click.option('--create',default=False, is_flag=True)
|
@click.option('--create',default=False, is_flag=True)
|
||||||
@click.option('--update',default=False, is_flag=True)
|
@click.option('--update',default=False, is_flag=True)
|
||||||
@ -63,7 +81,8 @@ def domain(domains, delete, update, create, read): #, domains, read, create, up
|
|||||||
|
|
||||||
if not domains:
|
if not domains:
|
||||||
if create:
|
if create:
|
||||||
create_domain()
|
# TODO: Connect to the create_domain function
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
domains = DOMAINS
|
domains = DOMAINS
|
||||||
else:
|
else:
|
||||||
@ -85,4 +104,4 @@ def domain(domains, delete, update, create, read): #, domains, read, create, up
|
|||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
if read:
|
if read:
|
||||||
list_routes(domain_name)
|
list_api_routes()
|
||||||
|
@ -7,9 +7,9 @@ import click
|
|||||||
import uvicorn
|
import uvicorn
|
||||||
|
|
||||||
from .cli import cli
|
from .cli import cli
|
||||||
from .domain import list_routes
|
from .domain import list_api_routes
|
||||||
from ..conf import (PROJECT_NAME, HOST, PORT,
|
from ..conf import (PROJECT_NAME, HOST, PORT,
|
||||||
PRODUCTION, BASE_DIR, DOMAINS)
|
PRODUCTION, BASE_DIR, DOMAINSDICT)
|
||||||
|
|
||||||
@click.option('--host', default=None)
|
@click.option('--host', default=None)
|
||||||
@click.option('--port', default=None)
|
@click.option('--port', default=None)
|
||||||
@ -34,8 +34,7 @@ def run(host, port):
|
|||||||
|
|
||||||
sys.path.insert(0, BASE_DIR)
|
sys.path.insert(0, BASE_DIR)
|
||||||
|
|
||||||
for domain in DOMAINS:
|
list_api_routes()
|
||||||
list_routes(domain)
|
|
||||||
|
|
||||||
uvicorn.run('halfapi.app:application',
|
uvicorn.run('halfapi.app:application',
|
||||||
host=host,
|
host=host,
|
||||||
|
@ -41,26 +41,27 @@ import sys
|
|||||||
from configparser import ConfigParser
|
from configparser import ConfigParser
|
||||||
import importlib
|
import importlib
|
||||||
|
|
||||||
|
from .lib.domain import d_domains
|
||||||
|
|
||||||
logger = logging.getLogger('halfapi')
|
logger = logging.getLogger('halfapi')
|
||||||
|
|
||||||
PROJECT_NAME = ''
|
PROJECT_NAME = os.path.basename(os.getcwd())
|
||||||
DOMAINS = []
|
DOMAINS = []
|
||||||
DOMAINSDICT = {}
|
DOMAINSDICT = lambda: {}
|
||||||
PRODUCTION = False
|
PRODUCTION = False
|
||||||
BASE_DIR = None
|
|
||||||
HOST = '127.0.0.1'
|
HOST = '127.0.0.1'
|
||||||
PORT = '3000'
|
PORT = '3000'
|
||||||
CONF_DIR = environ.get('HALFAPI_CONF_DIR', '/etc/half_api')
|
|
||||||
SECRET = ''
|
SECRET = ''
|
||||||
|
|
||||||
IS_PROJECT = os.path.isfile('.halfapi/config')
|
IS_PROJECT = os.path.isfile('.halfapi/config')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
default_config = {
|
default_config = {
|
||||||
'project': {
|
'project': {
|
||||||
'host': '127.0.0.1',
|
'host': '127.0.0.1',
|
||||||
'port': '8000',
|
'port': '8000',
|
||||||
'secret': '',
|
'secret': '',
|
||||||
'base_dir': '',
|
|
||||||
'production': 'no'
|
'production': 'no'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -68,36 +69,62 @@ default_config = {
|
|||||||
config = ConfigParser(allow_no_value=True)
|
config = ConfigParser(allow_no_value=True)
|
||||||
config.read_dict(default_config)
|
config.read_dict(default_config)
|
||||||
|
|
||||||
if IS_PROJECT:
|
CONF_DIR = environ.get('HALFAPI_CONF_DIR', '/etc/half_api')
|
||||||
config.read(filenames=['.halfapi/config'])
|
HALFAPI_ETC_FILE=os.path.join(
|
||||||
|
CONF_DIR, 'default.ini'
|
||||||
|
)
|
||||||
|
|
||||||
PROJECT_NAME = config.get('project', 'name')
|
HALFAPI_DOT_FILE=os.path.join(
|
||||||
|
os.getcwd(), '.halfapi', 'config')
|
||||||
|
|
||||||
|
HALFAPI_CONFIG_FILES = [ HALFAPI_ETC_FILE, HALFAPI_DOT_FILE ]
|
||||||
|
|
||||||
|
def conf_files():
|
||||||
|
return [
|
||||||
|
os.path.join(
|
||||||
|
CONF_DIR, 'default.ini'
|
||||||
|
),
|
||||||
|
os.path.join(
|
||||||
|
os.getcwd(), '.halfapi', 'config')]
|
||||||
|
|
||||||
|
|
||||||
|
def write_config():
|
||||||
|
"""
|
||||||
|
Writes the current config to the highest priority config file
|
||||||
|
"""
|
||||||
|
with open(conf_files()[-1], 'w') as halfapi_config:
|
||||||
|
config.write(halfapi_config)
|
||||||
|
|
||||||
|
def config_dict():
|
||||||
|
"""
|
||||||
|
The config object as a dict
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
section: {
|
||||||
|
config.items(section)
|
||||||
|
}
|
||||||
|
for section in config.sections()
|
||||||
|
}
|
||||||
|
|
||||||
|
def read_config():
|
||||||
|
"""
|
||||||
|
The highest index in "filenames" are the highest priorty
|
||||||
|
"""
|
||||||
|
config.read(HALFAPI_CONFIG_FILES)
|
||||||
|
return config_dict()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if IS_PROJECT:
|
||||||
|
read_config()
|
||||||
|
|
||||||
|
PROJECT_NAME = config.get('project', 'name', fallback=PROJECT_NAME)
|
||||||
|
|
||||||
if len(PROJECT_NAME) == 0:
|
if len(PROJECT_NAME) == 0:
|
||||||
raise Exception('Need a project name as argument')
|
raise Exception('Need a project name as argument')
|
||||||
|
|
||||||
DOMAINS = [domain for domain, _ in config.items('domains')] \
|
DOMAINSDICT = lambda: d_domains(config)
|
||||||
if config.has_section('domains') \
|
|
||||||
else []
|
|
||||||
|
|
||||||
try:
|
|
||||||
DOMAINSDICT = {
|
|
||||||
dom: importlib.import_module(dom)
|
|
||||||
for dom in DOMAINS
|
|
||||||
}
|
|
||||||
except ImportError as exc:
|
|
||||||
logger.error('Could not load a domain : %s', exc)
|
|
||||||
|
|
||||||
|
|
||||||
HALFAPI_CONF_FILE=os.path.join(
|
|
||||||
CONF_DIR,
|
|
||||||
PROJECT_NAME
|
|
||||||
)
|
|
||||||
if not os.path.isfile(HALFAPI_CONF_FILE):
|
|
||||||
print(f'Missing {HALFAPI_CONF_FILE}, exiting')
|
|
||||||
sys.exit(1)
|
|
||||||
config.read(filenames=[HALFAPI_CONF_FILE])
|
|
||||||
|
|
||||||
HOST = config.get('project', 'host')
|
HOST = config.get('project', 'host')
|
||||||
PORT = config.getint('project', 'port')
|
PORT = config.getint('project', 'port')
|
||||||
|
|
||||||
@ -113,4 +140,4 @@ if IS_PROJECT:
|
|||||||
PRODUCTION = config.getboolean('project', 'production') or False
|
PRODUCTION = config.getboolean('project', 'production') or False
|
||||||
os.environ['HALFAPI_PROD'] = str(PRODUCTION)
|
os.environ['HALFAPI_PROD'] = str(PRODUCTION)
|
||||||
|
|
||||||
BASE_DIR = config.get('project', 'base_dir')
|
BASE_DIR = config.get('project', 'base_dir', fallback='.') #os.getcwd())
|
||||||
|
@ -146,7 +146,7 @@ def gen_router_routes(m_router: ModuleType, path: List[str]):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def gen_domain_routes(domain: str):
|
def gen_domain_routes(domain: str, m_dom: ModuleType):
|
||||||
"""
|
"""
|
||||||
Generator that calls gen_router_routes for a domain
|
Generator that calls gen_router_routes for a domain
|
||||||
|
|
||||||
@ -160,3 +160,26 @@ def gen_domain_routes(domain: str):
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
logger.warning('Domain **%s** has no **routers** module', domain)
|
logger.warning('Domain **%s** has no **routers** module', domain)
|
||||||
logger.debug('%s', m_dom)
|
logger.debug('%s', m_dom)
|
||||||
|
|
||||||
|
|
||||||
|
def d_domains(config):
|
||||||
|
"""
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
config (ConfigParser): The .halfapi/config based configparser object
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
dict[str, ModuleType]
|
||||||
|
"""
|
||||||
|
if not config.has_section('domains'):
|
||||||
|
return {}
|
||||||
|
|
||||||
|
try:
|
||||||
|
return {
|
||||||
|
domain: importlib.import_module(domain)
|
||||||
|
for domain, _ in config.items('domains')
|
||||||
|
}
|
||||||
|
except ImportError as exc:
|
||||||
|
logger.error('Could not load a domain : %s', exc)
|
||||||
|
raise exc
|
||||||
|
29
halfapi/lib/domain_middleware.py
Normal file
29
halfapi/lib/domain_middleware.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
from starlette.middleware.base import BaseHTTPMiddleware
|
||||||
|
from starlette.requests import Request
|
||||||
|
from starlette.types import Scope, Send, Receive
|
||||||
|
|
||||||
|
from .routes import api_routes
|
||||||
|
from .domain import d_domains
|
||||||
|
|
||||||
|
class DomainMiddleware(BaseHTTPMiddleware):
|
||||||
|
def __init__(self, app, config):
|
||||||
|
super().__init__(app)
|
||||||
|
self.config = config
|
||||||
|
self.domains = d_domains(config)
|
||||||
|
self.api = {}
|
||||||
|
self.acl = {}
|
||||||
|
|
||||||
|
for domain, m_domain in self.domains.items():
|
||||||
|
self.api[domain], self.acl[domain] = api_routes(m_domain)
|
||||||
|
|
||||||
|
|
||||||
|
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
|
||||||
|
scope_ = scope.copy()
|
||||||
|
scope_['domains'] = self.domains
|
||||||
|
scope_['api'] = self.api
|
||||||
|
scope_['acl'] = self.acl
|
||||||
|
|
||||||
|
request = Request(scope_, receive)
|
||||||
|
response = await self.call_next(request)
|
||||||
|
await response(scope_, receive, send)
|
||||||
|
return response
|
@ -114,7 +114,7 @@ class JWTAuthenticationBackend(AuthenticationBackend):
|
|||||||
raise AuthenticationError(str(exc))
|
raise AuthenticationError(str(exc))
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.error('Authentication error : %s', exc)
|
logger.error('Authentication error : %s', exc)
|
||||||
raise e
|
raise exc
|
||||||
|
|
||||||
|
|
||||||
return AuthCredentials(["authenticated"]), JWTUser(
|
return AuthCredentials(["authenticated"]), JWTUser(
|
||||||
|
@ -78,6 +78,6 @@ def parse_query(q: str = ""):
|
|||||||
if 'offset' in params and int(params['offset']) > 0:
|
if 'offset' in params and int(params['offset']) > 0:
|
||||||
obj.offset(int(params['offset']))
|
obj.offset(int(params['offset']))
|
||||||
|
|
||||||
return [elt for elt in obj.select(*fields)]
|
return list(obj.select(*fields))
|
||||||
|
|
||||||
return select
|
return select
|
||||||
|
@ -53,4 +53,4 @@ class ORJSONResponse(JSONResponse):
|
|||||||
|
|
||||||
class HJSONResponse(ORJSONResponse):
|
class HJSONResponse(ORJSONResponse):
|
||||||
def render(self, content: typ.Generator):
|
def render(self, content: typ.Generator):
|
||||||
return super().render([ elt for elt in content ])
|
return super().render(list(content))
|
||||||
|
@ -52,19 +52,19 @@ def route_acl_decorator(fct: Callable, params: List[Dict]):
|
|||||||
return caller
|
return caller
|
||||||
|
|
||||||
|
|
||||||
def gen_starlette_routes(m_dom: ModuleType) -> Generator:
|
def gen_starlette_routes(d_domains: Dict[str, ModuleType]) -> Generator:
|
||||||
"""
|
"""
|
||||||
Yields the Route objects for HalfAPI app
|
Yields the Route objects for HalfAPI app
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
m_dom (ModuleType): the halfapi module
|
d_domains (dict[str, ModuleType])
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Generator(Route)
|
Generator(Route)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
for domain_name, m_domain in d_domains.items():
|
||||||
for path, d_route in gen_domain_routes(m_dom.__name__):
|
for path, d_route in gen_domain_routes(domain_name, m_domain):
|
||||||
for verb in VERBS:
|
for verb in VERBS:
|
||||||
if verb not in d_route.keys():
|
if verb not in d_route.keys():
|
||||||
continue
|
continue
|
||||||
@ -108,7 +108,7 @@ def api_routes(m_dom: ModuleType) -> Generator:
|
|||||||
return l_params
|
return l_params
|
||||||
|
|
||||||
d_res = {}
|
d_res = {}
|
||||||
for path, d_route in gen_domain_routes(m_dom.__name__):
|
for path, d_route in gen_domain_routes(m_dom.__name__, m_dom):
|
||||||
d_res[path] = {'fqtn': d_route['fqtn'] }
|
d_res[path] = {'fqtn': d_route['fqtn'] }
|
||||||
|
|
||||||
for verb in VERBS:
|
for verb in VERBS:
|
||||||
@ -120,9 +120,8 @@ def api_routes(m_dom: ModuleType) -> Generator:
|
|||||||
|
|
||||||
|
|
||||||
def api_acls(request):
|
def api_acls(request):
|
||||||
from .. import app # FIXME: Find a way to get d_acl without having to import
|
|
||||||
res = {}
|
res = {}
|
||||||
for domain, d_domain_acl in app.d_acl.items():
|
for domain, d_domain_acl in request.scope['acl'].items():
|
||||||
res[domain] = {}
|
res[domain] = {}
|
||||||
for acl_name, fct in d_domain_acl.items():
|
for acl_name, fct in d_domain_acl.items():
|
||||||
fct_result = fct(request)
|
fct_result = fct(request)
|
||||||
|
@ -39,9 +39,8 @@ async def get_api_routes(request, *args, **kwargs):
|
|||||||
description: Returns the current API routes description (HalfAPI 0.2.1)
|
description: Returns the current API routes description (HalfAPI 0.2.1)
|
||||||
as a JSON object
|
as a JSON object
|
||||||
"""
|
"""
|
||||||
from .. import app
|
assert 'api' in request.scope
|
||||||
|
return ORJSONResponse(request.scope['api'])
|
||||||
return ORJSONResponse(app.d_api)
|
|
||||||
|
|
||||||
|
|
||||||
async def schema_json(request, *args, **kwargs):
|
async def schema_json(request, *args, **kwargs):
|
||||||
@ -55,7 +54,7 @@ async def schema_json(request, *args, **kwargs):
|
|||||||
SCHEMAS.get_schema(routes=request.app.routes))
|
SCHEMAS.get_schema(routes=request.app.routes))
|
||||||
|
|
||||||
|
|
||||||
def schema_dict_dom(m_domain: ModuleType) -> Dict:
|
def schema_dict_dom(d_domains) -> Dict:
|
||||||
"""
|
"""
|
||||||
Returns the API schema of the *m_domain* domain as a python dictionnary
|
Returns the API schema of the *m_domain* domain as a python dictionnary
|
||||||
|
|
||||||
@ -69,9 +68,8 @@ def schema_dict_dom(m_domain: ModuleType) -> Dict:
|
|||||||
Dict: A dictionnary containing the description of the API using the
|
Dict: A dictionnary containing the description of the API using the
|
||||||
| OpenAPI standard
|
| OpenAPI standard
|
||||||
"""
|
"""
|
||||||
routes = [
|
return SCHEMAS.get_schema(
|
||||||
elt for elt in gen_starlette_routes(m_domain) ]
|
routes=list(gen_starlette_routes(d_domains)))
|
||||||
return SCHEMAS.get_schema(routes=routes)
|
|
||||||
|
|
||||||
|
|
||||||
async def get_acls(request, *args, **kwargs):
|
async def get_acls(request, *args, **kwargs):
|
||||||
|
Loading…
Reference in New Issue
Block a user