Esempio n. 1
0
if params.developer_mode:
    CORS_ORIGINS.append(URL_DEV)

# CORS Configuration
app.add_middleware(
    CORSMiddleware,
    allow_origins=CORS_ORIGINS,
    allow_methods=["GET", "POST", "OPTIONS"],
    allow_headers=["*"],
)

app.add_api_route(
    path="/api/devices",
    endpoint=routers,
    methods=["GET"],
    response_model=List[RoutersResponse],
    response_class=JSONResponse,
    summary=params.docs.devices.summary,
    description=params.docs.devices.description,
    tags=[params.docs.devices.title],
)

app.add_api_route(
    path="/api/communities",
    endpoint=communities,
    methods=["GET"],
    response_model=List[CommunityResponse],
    summary=params.docs.communities.summary,
    tags=[params.docs.communities.title],
)

app.add_api_route(
Esempio n. 2
0
def create_visyn_server(*,
                        fast_api_args: Optional[Dict] = {},
                        start_cmd: Optional[str] = None,
                        workspace_config: Optional[Dict] = None) -> FastAPI:
    """
    Create a new FastAPI instance while ensuring that the configuration and plugins are loaded, extension points are registered, database migrations are executed, ...

    Keyword arguments:
    fast_api_args: Optional dictionary of arguments directly passed to the FastAPI constructor.
    start_cmd: Optional start command for the server, i.e. db-migration exposes commands like `db-migration exec <..> upgrade head`.
    workspace_config: Optional override for the workspace configuration. If nothing is provided `load_workspace_config()` is used instead.
    """
    from .. import manager
    from ..settings.model import GlobalSettings
    from ..settings.utils import load_workspace_config

    # Load the workspace config.json and initialize the global settings
    workspace_config = workspace_config if isinstance(
        workspace_config, dict) else load_workspace_config()
    manager.settings = GlobalSettings(**workspace_config)
    logging.config.dictConfig(manager.settings.tdp_core.logging)
    _log = logging.getLogger(__name__)
    _log.info("Workspace settings successfully loaded")

    # Load the initial plugins
    from ..plugin.parser import get_config_from_plugins, load_all_plugins

    plugins = load_all_plugins()
    # With all the plugins, load the corresponding configuration files and create a new model based on the global settings, with all plugin models as sub-models
    [plugin_config_files,
     plugin_settings_models] = get_config_from_plugins(plugins)
    visyn_server_settings = create_model("VisynServerSettings",
                                         __base__=GlobalSettings,
                                         **plugin_settings_models)
    # Patch the global settings by instantiating the new settings model with the global config, all config.json(s), and pydantic models
    manager.settings = visyn_server_settings(
        **deep_update(*plugin_config_files, workspace_config))
    _log.info("All settings successfully loaded")

    app = FastAPI(
        debug=manager.settings.is_development_mode,
        title="Visyn Server",
        # TODO: Extract version from package.json
        version="1.0.0",
        docs_url="/api/docs",
        openapi_url="/api/openapi.json",
        redoc_url="/api/redoc",
        **fast_api_args,
    )

    from ..middleware.exception_handler_middleware import ExceptionHandlerMiddleware
    from ..middleware.request_context_middleware import RequestContextMiddleware

    # TODO: For some reason, a @app.exception_handler(Exception) is not called here. We use a middleware instead.
    app.add_middleware(ExceptionHandlerMiddleware)

    # Store all globals also in app.state.<manager> to allow access in FastAPI routes via request.app.state.<manager>.
    app.state.settings = manager.settings

    # Initialize global managers.
    from ..plugin.registry import Registry

    app.state.registry = manager.registry = Registry()
    manager.registry.init_app(app, plugins)

    _log.info("Plugin registry successfully initialized")

    from ..dbmanager import DBManager

    app.state.db = manager.db = DBManager()
    manager.db.init_app(app)

    from ..dbmigration.manager import DBMigrationManager

    app.state.db_migration = manager.db_migration = DBMigrationManager()
    manager.db_migration.init_app(
        app, manager.registry.list("tdp-sql-database-migration"))

    from ..security.manager import create_security_manager

    app.state.security = manager.security = create_security_manager()
    manager.security.init_app(app)

    from ..id_mapping.manager import create_id_mapping_manager

    app.state.id_mapping = manager.id_mapping = create_id_mapping_manager()

    # TODO: Allow custom command routine (i.e. for db-migrations)
    from .cmd import parse_command_string

    alternative_start_command = parse_command_string(start_cmd)
    if alternative_start_command:
        _log.info(f"Received start command: {start_cmd}")
        alternative_start_command()
        _log.info("Successfully executed command, exiting server...")
        # TODO: How to properly exit here? Should a command support the "continuation" of the server, i.e. by returning True?
        sys.exit(0)

    # Load all namespace plugins as WSGIMiddleware plugins
    from .utils import init_legacy_app, load_after_server_started_hooks

    namespace_plugins = manager.registry.list("namespace")
    _log.info(
        f"Registering {len(namespace_plugins)} legacy namespaces via WSGIMiddleware"
    )
    for p in namespace_plugins:
        _log.info(f"Registering legacy namespace: {p.namespace}")
        app.mount(p.namespace,
                  WSGIMiddleware(init_legacy_app(p.load().factory())))

    # Load all FastAPI apis
    router_plugins = manager.registry.list("fastapi_router")
    _log.info(f"Registering {len(router_plugins)} API-routers")
    # Load all namespace plugins as WSGIMiddleware plugins
    for p in router_plugins:
        _log.info(f"Registering router: {p.id}")
        app.include_router(p.load().factory())

    # load `after_server_started` extension points which are run immediately after server started,
    # so all plugins should have been loaded at this point of time
    # the hooks are run in a separate (single) thread to not block the main execution of the server
    # TODO: Use FastAPI mechanism for that
    t = threading.Thread(target=load_after_server_started_hooks)
    t.daemon = True
    t.start()

    # TODO: Check mainapp.py what it does and transfer them here. Currently, we cannot mount a flask app at root, such that the flask app is now mounted at /app/
    from .mainapp import build_info, health

    # Call init_app callback for every plugin
    for p in plugins:
        p.plugin.init_app(app)

    # Add middleware to access Request "outside"
    app.add_middleware(RequestContextMiddleware)

    # TODO: Move up?
    app.add_api_route("/health", health)
    app.add_api_route("/api/buildInfo.json", build_info)

    return app
Esempio n. 3
0
class Item(BaseModel):
    name: str
    price: float = None


@app.api_route("/items/{item_id}", methods=["GET"])
def get_items(item_id: str):
    return {"item_id": item_id}


def get_not_decorated(item_id: str):
    return {"item_id": item_id}


app.add_api_route("/items-not-decorated/{item_id}", get_not_decorated)


@app.delete("/items/{item_id}")
def delete_item(item_id: str, item: Item):
    return {"item_id": item_id, "item": item}


@app.head("/items/{item_id}")
def head_item(item_id: str):
    return JSONResponse(headers={"x-fastapi-item-id": item_id})


@app.options("/items/{item_id}")
def options_item(item_id: str):
    return JSONResponse(headers={"x-fastapi-item-id": item_id})
Esempio n. 4
0
from fastapi import FastAPI

from kolombo import conf
from kolombo.auth.endpoints import auth
from kolombo.models import init_database

conf.read_configuration()
app = FastAPI(
    title="Kolombo auth API",
    debug=conf.DEBUG,
    on_startup=[init_database],
    # Disable Swagger UI and other API docs
    openapi_url=None,
    docs_url=None,
    redoc_url=None,
)
app.add_api_route("/auth", auth, methods=["GET"])
Esempio n. 5
0
    def __init__(
        self,
        *tables: t.Type[Table],
        auth_table: t.Type[BaseUser] = BaseUser,
        session_table: t.Type[SessionsBase] = SessionsBase,
        session_expiry: timedelta = timedelta(hours=1),
        max_session_expiry: timedelta = timedelta(days=7),
        increase_expiry: t.Optional[timedelta] = timedelta(minutes=20),
        page_size: int = 15,
        read_only: bool = False,
        rate_limit_provider: t.Optional[RateLimitProvider] = None,
        production: bool = False,
        site_name: str = "Piccolo Admin",
    ) -> None:
        super().__init__(title=site_name,
                         description="Piccolo API documentation")

        self.auth_table = auth_table
        self.site_name = site_name
        self.tables = tables

        with open(os.path.join(ASSET_PATH, "index.html")) as f:
            self.template = f.read()

        #######################################################################

        api_app = FastAPI()

        for table in tables:
            FastAPIWrapper(
                root_url=f"/tables/{table._meta.tablename}/",
                fastapi_app=api_app,
                piccolo_crud=PiccoloCRUD(table=table,
                                         read_only=read_only,
                                         page_size=page_size),
                fastapi_kwargs=FastAPIKwargs(all_routes={
                    "tags": [f"{table._meta.tablename.capitalize()}"]
                }, ),
            )

        api_app.add_api_route(
            path="/tables/",
            endpoint=self.get_table_list,
            methods=["GET"],
            response_model=t.List[str],
            tags=["Tables"],
        )

        api_app.add_api_route(
            path="/meta/",
            endpoint=self.get_meta,
            methods=["GET"],
            tags=["Meta"],
            response_model=MetaResponseModel,
        )

        api_app.add_api_route(
            path="/user/",
            endpoint=self.get_user,
            methods=["GET"],
            tags=["User"],
            response_model=UserResponseModel,
        )

        #######################################################################

        auth_app = FastAPI()

        if not rate_limit_provider:
            rate_limit_provider = InMemoryLimitProvider(limit=1000,
                                                        timespan=300)

        auth_app.mount(
            path="/login/",
            app=RateLimitingMiddleware(
                app=session_login(
                    auth_table=self.auth_table,
                    session_table=session_table,
                    session_expiry=session_expiry,
                    max_session_expiry=max_session_expiry,
                    redirect_to=None,
                    production=production,
                ),
                provider=rate_limit_provider,
            ),
        )

        auth_app.add_route(
            path="/logout/",
            route=session_logout(session_table=session_table),
            methods=["POST"],
        )

        #######################################################################

        self.router.add_route(path="/",
                              endpoint=self.get_root,
                              methods=["GET"])

        self.mount(
            path="/css",
            app=StaticFiles(directory=os.path.join(ASSET_PATH, "css")),
        )

        self.mount(
            path="/js",
            app=StaticFiles(directory=os.path.join(ASSET_PATH, "js")),
        )

        auth_middleware = partial(
            AuthenticationMiddleware,
            backend=SessionsAuthBackend(
                auth_table=auth_table,
                session_table=session_table,
                admin_only=True,
                increase_expiry=increase_expiry,
            ),
            on_error=handle_auth_exception,
        )

        self.mount(path="/api", app=auth_middleware(api_app))
        self.mount(path="/auth", app=auth_app)
Esempio n. 6
0
File: main.py Progetto: 48ix/stats
        limit=params.api.default_limit,
        granularity=granularity,
    )

    return {
        "ingress": data_in.get("values", [[]]),
        "egress": data_out.get("values", [[]]),
        "ingress_average": avg_in.get("values", [["", 0]])[0][1],
        "egress_average": avg_out.get("values", [["", 0]])[0][1],
        "ingress_peak": peak_in.get("values", [["", 0]])[0][1],
    }


api.add_api_route(
    path="/utilization/all",
    endpoint=overall_utilization,
    response_model=OverallUtilization,
    methods=["GET", "OPTIONS"],
)

api.add_api_route(
    path="/utilization/{port_id}",
    endpoint=port_utilization,
    response_model=PortUtilization,
    methods=["GET", "OPTIONS"],
)

api.add_api_route(
    path="/policy/update/",
    endpoint=update_policy,
    response_model=UpdatePolicyResponse,
    methods=["POST"],
Esempio n. 7
0
from zenroom.zenroom import zencode_exec

app = FastAPI(title="RESTRoom")
env = Env()
env.read_env()

conf_file = env("RESTROOM_CONFIG_FILE")
conf = Path(conf_file).read_text().splitlines()


def make_function(script):
    def _function(data: str = None, keys: str = None):
        print(configuration.registered_middleware)
        configuration.input()
        result = zencode_exec(script=script, keys=keys, data=data)
        configuration.output()
        return {"err": result.stderr, "out": json.loads(result.stdout)}

    return _function


for _ in conf:
    method, route, filename = _.split(" ")
    zencode = Path(filename).read_text()
    app.add_api_route(route,
                      make_function(zencode),
                      methods=[method],
                      description=zencode,
                      summary=zencode,
                      tags=['Zencode'])
Esempio n. 8
0
def _build_fastapi_app():
    app = FastAPI()
    app.add_api_route("/", handle, methods=["GET"])
    app.add_api_route(CUSTOM_RESPONSE_PATH,
                      handle_custom_response,
                      methods=["GET"])
    app.add_api_route(BASE_MODEL_RESPONSE_PATH,
                      handle_base_model_response,
                      methods=["GET"])
    app.add_api_route(CUSTOM_STATUS_CODE_PATH,
                      handle_custom_status_code,
                      methods=["GET"],
                      status_code=CUSTOM_STATUS_CODE)
    app.add_api_route(OVERRIDDEN_CUSTOM_STATUS_CODE_PATH,
                      handle_overridden_custom_status_code,
                      methods=["GET"],
                      status_code=CUSTOM_STATUS_CODE)
    app.add_api_route(REQUEST_OBJ_PATH, handle_given_request, methods=["POST"])
    app.add_api_route("/a", handle_a, methods=["GET"])
    app.add_api_route("/b", handle_b, methods=["GET"])
    app.add_api_route("/err",
                      handle_error_from_route,
                      methods=["GET"],
                      status_code=200)
    app.add_api_route(MULTIPLE_THREADS_ROUTE,
                      multiple_threads_route,
                      methods=["GET"])
    router = APIRouter()
    router.add_api_route(TEST_ROUTER_PATH, handle_router_endpoint)
    app.include_router(router, prefix=TEST_ROUTER_PREFIX)
    router_with_custom_route = APIRouter(route_class=CustomRouteClass)
    router_with_custom_route.add_api_route(TEST_CUSTOM_ROUTE_PATH,
                                           handle_custom_route_endpoint)
    app.include_router(router_with_custom_route,
                       prefix=TEST_CUSTOM_ROUTE_PREFIX)
    return app
Esempio n. 9
0
def create_app(settings: ApiSettings) -> FastAPI:
    """Create a FastAPI app"""
    paging_client = PaginationTokenClient()
    core_client = CoreCrudClient(pagination_client=paging_client)

    app = FastAPI()
    inject_settings(settings)

    app.debug = settings.debug
    app.include_router(
        create_core_router(core_client, settings), tags=["Core Endpoints"],
        dependencies=[Depends(oauth2_scheme)]
    )
    add_exception_handlers(app, DEFAULT_STATUS_CODES)

    app.add_middleware(
        CORSMiddleware,
        allow_origins=["*"],
        allow_headers=["*"],
    )

    @app.exception_handler(RequestValidationError)
    async def validation_exception_handler(request: Request,
                                           exc: RequestValidationError):
        return JSONResponse(
            status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
            content=jsonable_encoder(
                {
                    "detail": exc.errors(),
                    "query_params": request.query_params,
                    "path_params": request.path_params,
                }
            ),
        )

    if settings.api_extension_is_enabled(ApiExtensions.transaction):
        transaction_client = TransactionsClient()
        app.include_router(
            create_transactions_router(transaction_client, settings),
            tags=["Transaction Extension"], dependencies=[Depends(oauth2_scheme)]
        )

    if settings.add_on_is_enabled(AddOns.tiles):
        tiles_client = TilesClient()
        app.add_api_route(
            name="Get OGC Tiles Resource",
            path="/collections/{collectionId}/items/{itemId}/tiles",
            response_model=TileSetResource,
            response_model_exclude_none=True,
            response_model_exclude_unset=True,
            methods=["GET"],
            endpoint=create_endpoint_with_depends(tiles_client.get_item_tiles, ItemUri),
            tags=["OGC Tiles"],
            dependencies=[Depends(oauth2_scheme)]
        )
        app.include_router(create_tiles_router(), prefix="/titiler", tags=["Titiler"], dependencies=[Depends(oauth2_scheme)])

    config_openapi(app, settings)

    @app.on_event("startup")
    async def on_startup():
        """Create database engines and sessions on startup"""
        app.state.ENGINE_READER = create_engine(
            settings.reader_connection_string, echo=settings.debug
        )
        app.state.ENGINE_WRITER = create_engine(
            settings.writer_connection_string, echo=settings.debug
        )
        app.state.DB_READER = sessionmaker(
            autocommit=False, autoflush=False, bind=app.state.ENGINE_READER
        )
        app.state.DB_WRITER = sessionmaker(
            autocommit=False, autoflush=False, bind=app.state.ENGINE_WRITER
        )

    @app.on_event("shutdown")
    async def on_shutdown():
        """Dispose of database engines and sessions on app shutdown"""
        app.state.ENGINE_READER.dispose()
        app.state.ENGINE_WRITER.dispose()

    @app.middleware("http")
    async def create_db_connection(request: Request, call_next):
        """Create a new database connection for each request"""
        if "titiler" in str(request.url):
            return await call_next(request)
        reader = request.app.state.DB_READER()
        writer = request.app.state.DB_WRITER()
        READER.set(reader)
        WRITER.set(writer)
        resp = await call_next(request)
        reader.close()
        writer.close()
        return resp

    @app.post("/login")
    async def login(body: Login):
        try:
            tokens = await get_tokens(body.username, body.password)

            return tokens
        except Exception as exception:
            raise HTTPException(status_code=400, detail=f"{exception}")

    @app.post("/token")
    async def get_token(form_data: OAuth2PasswordRequestForm = Depends()):
        try:
            username = form_data.username
            password = form_data.password
            tokens = await get_tokens(username, password)
            access_token = tokens["access_token"]

            return {"access_token": access_token, "token_type": "bearer"}
        except Exception as exception:
            raise HTTPException(status_code=400, detail=f"{exception}")

    mgmt_router = APIRouter()

    @mgmt_router.get("/_mgmt/ping")
    async def ping():
        """Liveliness/readiness probe"""
        return {"message": "PONG"}

    app.include_router(mgmt_router, tags=["Liveliness/Readiness"])

    return app
Esempio n. 10
0
    def __init__(
        self,
        *tables: t.Union[t.Type[Table], TableConfig],
        forms: t.List[FormConfig] = [],
        auth_table: t.Type[BaseUser] = BaseUser,
        session_table: t.Type[SessionsBase] = SessionsBase,
        session_expiry: timedelta = timedelta(hours=1),
        max_session_expiry: timedelta = timedelta(days=7),
        increase_expiry: t.Optional[timedelta] = timedelta(minutes=20),
        page_size: int = 15,
        read_only: bool = False,
        rate_limit_provider: t.Optional[RateLimitProvider] = None,
        production: bool = False,
        site_name: str = "Piccolo Admin",
    ) -> None:
        super().__init__(
            title=site_name, description="Piccolo API documentation"
        )

        #######################################################################
        # Convert any table arguments which are plain ``Table`` classes into
        # ``TableConfig`` instances.

        table_configs: t.List[TableConfig] = []

        for table in tables:
            if isinstance(table, TableConfig):
                table_configs.append(table)
            else:
                table_configs.append(TableConfig(table_class=table))

        self.table_configs = table_configs

        for table_config in table_configs:
            table_class = table_config.table_class
            for column in table_class._meta.columns:
                if column._meta.secret and column._meta.required:
                    message = (
                        f"{table_class._meta.tablename}."
                        f"{column._meta._name} is using `secret` and "
                        f"`required` column args which are incompatible. "
                        f"You may encounter unexpected behavior when using "
                        f"this table within Piccolo Admin."
                    )
                    colored_warning(message, level=Level.high)

        #######################################################################

        self.auth_table = auth_table
        self.site_name = site_name
        self.forms = forms
        self.form_config_map = {form.slug: form for form in self.forms}

        with open(os.path.join(ASSET_PATH, "index.html")) as f:
            self.template = f.read()

        #######################################################################

        api_app = FastAPI(docs_url=None)
        api_app.mount("/docs/", swagger_ui(schema_url="../openapi.json"))

        for table_config in table_configs:
            table_class = table_config.table_class
            visible_column_names = table_config.get_visible_column_names()
            visible_filter_names = table_config.get_visible_filter_names()
            rich_text_columns_names = (
                table_config.get_rich_text_columns_names()
            )
            FastAPIWrapper(
                root_url=f"/tables/{table_class._meta.tablename}/",
                fastapi_app=api_app,
                piccolo_crud=PiccoloCRUD(
                    table=table_class,
                    read_only=read_only,
                    page_size=page_size,
                    schema_extra={
                        "visible_column_names": visible_column_names,
                        "visible_filter_names": visible_filter_names,
                        "rich_text_columns": rich_text_columns_names,
                    },
                ),
                fastapi_kwargs=FastAPIKwargs(
                    all_routes={
                        "tags": [f"{table_class._meta.tablename.capitalize()}"]
                    },
                ),
            )

        api_app.add_api_route(
            path="/tables/",
            endpoint=self.get_table_list,  # type: ignore
            methods=["GET"],
            response_model=t.List[str],
            tags=["Tables"],
        )

        api_app.add_api_route(
            path="/meta/",
            endpoint=self.get_meta,  # type: ignore
            methods=["GET"],
            tags=["Meta"],
            response_model=MetaResponseModel,
        )

        api_app.add_api_route(
            path="/forms/",
            endpoint=self.get_forms,  # type: ignore
            methods=["GET"],
            tags=["Forms"],
            response_model=t.List[FormConfigResponseModel],
        )

        api_app.add_api_route(
            path="/forms/{form_slug:str}/",
            endpoint=self.get_single_form,  # type: ignore
            methods=["GET"],
            tags=["Forms"],
        )

        api_app.add_api_route(
            path="/forms/{form_slug:str}/schema/",
            endpoint=self.get_single_form_schema,  # type: ignore
            methods=["GET"],
            tags=["Forms"],
        )

        api_app.add_api_route(
            path="/forms/{form_slug:str}/",
            endpoint=self.post_single_form,  # type: ignore
            methods=["POST"],
            tags=["Forms"],
        )

        api_app.add_api_route(
            path="/user/",
            endpoint=self.get_user,  # type: ignore
            methods=["GET"],
            tags=["User"],
            response_model=UserResponseModel,
        )

        #######################################################################

        auth_app = FastAPI()

        if not rate_limit_provider:
            rate_limit_provider = InMemoryLimitProvider(
                limit=1000, timespan=300
            )

        auth_app.mount(
            path="/login/",
            app=RateLimitingMiddleware(
                app=session_login(
                    auth_table=self.auth_table,
                    session_table=session_table,
                    session_expiry=session_expiry,
                    max_session_expiry=max_session_expiry,
                    redirect_to=None,
                    production=production,
                ),
                provider=rate_limit_provider,
            ),
        )

        auth_app.add_route(
            path="/logout/",
            route=session_logout(session_table=session_table),
            methods=["POST"],
        )

        #######################################################################

        self.router.add_route(
            path="/", endpoint=self.get_root, methods=["GET"]
        )

        self.mount(
            path="/css",
            app=StaticFiles(directory=os.path.join(ASSET_PATH, "css")),
        )

        self.mount(
            path="/js",
            app=StaticFiles(directory=os.path.join(ASSET_PATH, "js")),
        )

        auth_middleware = partial(
            AuthenticationMiddleware,
            backend=SessionsAuthBackend(
                auth_table=auth_table,
                session_table=session_table,
                admin_only=True,
                increase_expiry=increase_expiry,
            ),
            on_error=handle_auth_exception,
        )

        self.mount(path="/api", app=auth_middleware(api_app))
        self.mount(path="/auth", app=auth_app)

        # We make the meta endpoint available without auth, because it contains
        # the site name.
        self.add_api_route("/meta/", endpoint=self.get_meta)  # type: ignore
Esempio n. 11
0
from melodiam import __version__, conf
from melodiam.auth import endpoints

api = FastAPI(
    debug=conf.DEBUG,
    title="Melodiam Auth API",
    version=__version__,
    root_path=conf.API_PREFIX,
    on_startup=[endpoints.startup],
    on_shutdown=[endpoints.shutdown],
    openapi_url=None,
    docs_url=None,
    redoc_url=None,
)
api.add_middleware(
    SessionMiddleware,
    secret_key=conf.SESSION_SECRET,
    same_site="lax",
    https_only=not conf.DEBUG,
)
api.add_api_route(
    conf.LOGIN_PATH,
    endpoints.login,
    methods=["GET"],
)
api.add_api_route(
    conf.LOGIN_REDIRECT_PATH,
    endpoints.login_redirect,
    methods=["GET"],
)
class HttpService:
    """A Http service implementation.
    ~~~~~~~~~~~~~~~~~~

    To decouple web service framework and web service interface, DBMind implements the class.
    In this way, DBMind can change to another web framework (e.g., web.py, ASGI) easily."""
    def __init__(self, name=__name__):
        if _BACKEND >= BACKEND_TYPES.PURE_FLASK:
            self.app = Flask(name)
        elif _BACKEND == BACKEND_TYPES.FAST_API:
            self.app = FastAPI(title=name)
        else:
            raise AssertionError('Should not run to here.')

        self.rule_num = 0

    def attach(self, func, rule, **options):
        """Attach a rule to the backend app."""
        is_api = options.pop('api', False)
        if _BACKEND >= BACKEND_TYPES.PURE_FLASK:
            endpoint = options.pop("endpoint", None)
            rule = rule.replace('{', '<').replace('}', '>')
            self.app.add_url_rule(rule, endpoint, func, **options)
        elif _BACKEND == BACKEND_TYPES.FAST_API:
            rule = rule.replace('<', '{').replace('>', '}')
            if is_api:
                self.app.add_api_route(rule, func, **options)
            else:
                self.app.add_route(rule, func, **options)
        self.rule_num += 1

    def route(self, rule, **options):
        def decorator(f):
            self.attach(f, rule, **options)
            return f

        return decorator

    def register_controller_module(self, module_name):
        __import__(module_name)
        for rule, items in _RequestMappingTable.items():
            f, options = items
            self.attach(f, rule, **options)

    def start_listen(self,
                     host,
                     port,
                     ssl_keyfile=None,
                     ssl_certfile=None,
                     ssl_keyfile_password=None):
        if _BACKEND != BACKEND_TYPES.FAST_API and (ssl_keyfile
                                                   or ssl_certfile):
            raise NotImplementedError(
                'Not supported Https for flask. You should install fastapi and uvicorn.'
            )

        if _BACKEND == BACKEND_TYPES.FLASK_WITH_WAITRESS:
            serve(RequestLogger(self.app),
                  _quiet=True,
                  listen="{host}:{port}".format(host=host, port=port))
        elif _BACKEND == BACKEND_TYPES.PURE_FLASK:
            self.app.run(host=host, port=port)
        elif _BACKEND == BACKEND_TYPES.FAST_API:
            config = uvicorn.Config(self.app,
                                    host=host,
                                    port=port,
                                    ssl_keyfile=ssl_keyfile,
                                    ssl_certfile=ssl_certfile,
                                    ssl_keyfile_password=ssl_keyfile_password,
                                    log_config=None)
            config.load()
            if config.is_ssl:
                config.ssl.options |= (
                    ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 | ssl.OP_NO_TLSv1
                    | ssl.OP_NO_TLSv1_1
                )  # RFC 7540 Section 9.2: MUST be TLS >=1.2
                config.ssl.set_ciphers('DHE+AESGCM:ECDHE+AESGCM')
            server = uvicorn.Server(config)
            server.run()
Esempio n. 13
0
) -> CypherResponse:
    """Handle cypher."""
    request = request.dict()
    results = await graph_interface.run_cypher(
        request["query"],
        return_errors=True,
    )
    return results


APP_COMMON.add_api_route(
    "/cypher",
    cypher,
    methods=["POST"],
    response_model=CypherResponse,
    summary="Run cypher query",
    description=(
        "Runs cypher query against the Neo4j instance, and returns an "
        "equivalent response expected from a Neo4j HTTP endpoint "
        "(https://neo4j.com/docs/rest-docs/current/)."),
)


async def overlay(
    request: ReasonerRequest = Body(
        ...,
        example={"message": get_example("overlay")},
    ),
    graph_interface: GraphInterface = Depends(get_graph_interface),
) -> Message:
    """Handle TRAPI request."""
Esempio n. 14
0
def _add_ui(app: FastAPI, method: str, func: Callable, url: str):
    if not inspect.iscoroutinefunction(func):
        raise ValueError(f'{func.__name__} is not a async function')

    app.add_api_route(f'/api/v1/{url}', endpoint=func, methods=[method])
Esempio n. 15
0
async def test_token_payload_but_token_is_missing(app: FastAPI, client: TestClient):
    app.add_api_route("/token_payload", token_payload)
    response = await client.get("/token_payload")
    assert response.json() == exceptions.MissingToken().as_dict()
    assert response.status_code == 401
Esempio n. 16
0
        inspect.Parameter(
            "request",
            inspect.Parameter.POSITIONAL_OR_KEYWORD,
            annotation=Request,
        )
    ] + list(inspect.signature(func).parameters.values()))
    wrapper.__annotations__ = {
        **func.__annotations__,
        "request": Request,
    }
    return wrapper


for route in ROUTER.routes:
    APP.add_api_route(
        route.path,
        prepare_output(route.endpoint),
        responses={
            200: {
                "content": {
                    "text/tabular": {}
                },
                "description": "Return the tabular output.",
            }
        },
        response_model=route.response_model,
        tags=route.tags,
        deprecated=route.deprecated,
        methods=route.methods,
    )
Esempio n. 17
0
async def test_token_payload_but_token_is_invalid(app: FastAPI, client: TestClient):
    app.add_api_route("/token_payload", token_payload)
    headers = {"Authorization": "Bearer token"}
    response = await client.get("/token_payload", headers=headers)
    assert response.json() == exceptions.InvalidToken().as_dict()
    assert response.status_code == 403
Esempio n. 18
0
from fastapi import FastAPI, Path, Query

app = FastAPI()


@app.api_route("/api_route")
def non_operation():
    return {"message": "Hello World"}


def non_decorated_route():
    return {"message": "Hello World"}


app.add_api_route("/non_decorated_route", non_decorated_route)


@app.get("/text")
def get_text():
    return "Hello World"


@app.get("/path/{item_id}")
def get_id(item_id):
    return item_id


@app.get("/path/str/{item_id}")
def get_str_id(item_id: str):
    return item_id
Esempio n. 19
0
"""路由。
集中注册
"""
import uvicorn
from fastapi import FastAPI

app = FastAPI()


def home():
    return {"msg": "hello world"}
app.add_api_route("/", home, methods=["get", "post"])

if __name__ == "__main__":
    uvicorn.run(app, debug=True)
Esempio n. 20
0
    auth_needed = model_conf.get('auth_needed')
    scope = model_conf.get('scope', odoo_model.replace(',', ''))

    # return object list
    # we use partial to pass the db_model as a paramter to read_objects
    read_objects_for_model = partial(read_objects, db_model, auth_needed,
                                     scope)
    app.router.add_api_route(f'/odoo/{route_name}',
                             read_objects_for_model,
                             methods=['get'],
                             response_model=List[api_model])

    # return object
    read_object_for_model = partial(read_object, db_model)
    app.add_api_route("/odoo/{0}/".format(route_name) + '{object_id}',
                      read_object_for_model,
                      methods=['get'],
                      response_model=api_model)

# country_db, country_pyd = create_fast_models('res.country')
# @app.get('/countries', response_model=List[country_pyd])
# def read_countries(skip: int = 0, limit: int = 0):
#     db = next(get_db())
#     countries = db.query(country_db).all()[skip: skip + limit]
#     return countries

# group_db, group_pyd = create_fast_models('srcm.group')
# @app.get('/groups', response_model=List[group_pyd])
# def read_groups(skip: int = 0, limit: int = 0):
#     db = next(get_db())
#     groups = db.query(group_db).all()[skip: skip + limit]
#     return groups
Esempio n. 21
0
# imports
import os
import logging
from dotenv import load_dotenv
from fastapi import FastAPI, HTTPException
from mlflow.exceptions import MlflowException

# local absolute imports
from src.api.model import NewsClassifier
from src.api.endpoints import get_prediction, train_and_deploy
from run_ml import run_training

app = FastAPI(title="News classifier API",
              description="Classifies news titles into 4 distinct categories.",
              version="0.1",
              debug=True)

app.add_api_route("/predict", get_prediction, methods=["POST"])
app.add_api_route("/train_and_deploy", train_and_deploy, methods=["GET"])
app.add_api_route("/", lambda: app.title, methods=["GET"])
Esempio n. 22
0
async def test_current_user_id(app: FastAPI, client: TestClient, user: User):
    app.add_api_route("/current_user_id", current_user_id)
    response = await client.login(user.id).get("/current_user_id")
    assert response.json()["user_id"] == str(user.id)
    assert response.status_code == 200
Esempio n. 23
0
class Driver(ReverseDriver):
    """FastAPI 驱动框架。"""
    def __init__(self, env: Env, config: NoneBotConfig):
        super(Driver, self).__init__(env, config)

        self.fastapi_config: Config = Config(**config.dict())

        self._server_app = FastAPI(
            openapi_url=self.fastapi_config.fastapi_openapi_url,
            docs_url=self.fastapi_config.fastapi_docs_url,
            redoc_url=self.fastapi_config.fastapi_redoc_url,
        )

    @property
    @overrides(ReverseDriver)
    def type(self) -> str:
        """驱动名称: `fastapi`"""
        return "fastapi"

    @property
    @overrides(ReverseDriver)
    def server_app(self) -> FastAPI:
        """`FastAPI APP` 对象"""
        return self._server_app

    @property
    @overrides(ReverseDriver)
    def asgi(self) -> FastAPI:
        """`FastAPI APP` 对象"""
        return self._server_app

    @property
    @overrides(ReverseDriver)
    def logger(self) -> logging.Logger:
        """fastapi 使用的 logger"""
        return logging.getLogger("fastapi")

    @overrides(ReverseDriver)
    def setup_http_server(self, setup: HTTPServerSetup):
        async def _handle(request: Request) -> Response:
            return await self._handle_http(request, setup)

        self._server_app.add_api_route(
            setup.path.path,
            _handle,
            name=setup.name,
            methods=[setup.method],
            include_in_schema=self.fastapi_config.
            fastapi_include_adapter_schema,
        )

    @overrides(ReverseDriver)
    def setup_websocket_server(self, setup: WebSocketServerSetup) -> None:
        async def _handle(websocket: WebSocket) -> None:
            await self._handle_ws(websocket, setup)

        self._server_app.add_api_websocket_route(
            setup.path.path,
            _handle,
            name=setup.name,
        )

    @overrides(ReverseDriver)
    def on_startup(self, func: Callable) -> Callable:
        """参考文档: `Events <https://fastapi.tiangolo.com/advanced/events/#startup-event>`_"""
        return self.server_app.on_event("startup")(func)

    @overrides(ReverseDriver)
    def on_shutdown(self, func: Callable) -> Callable:
        """参考文档: `Events <https://fastapi.tiangolo.com/advanced/events/#shutdown-event>`_"""
        return self.server_app.on_event("shutdown")(func)

    @overrides(ReverseDriver)
    def run(
        self,
        host: Optional[str] = None,
        port: Optional[int] = None,
        *,
        app: Optional[str] = None,
        **kwargs,
    ):
        """使用 `uvicorn` 启动 FastAPI"""
        super().run(host, port, app, **kwargs)
        LOGGING_CONFIG = {
            "version": 1,
            "disable_existing_loggers": False,
            "handlers": {
                "default": {
                    "class": "nonebot.log.LoguruHandler",
                },
            },
            "loggers": {
                "uvicorn.error": {
                    "handlers": ["default"],
                    "level": "INFO"
                },
                "uvicorn.access": {
                    "handlers": ["default"],
                    "level": "INFO",
                },
            },
        }
        uvicorn.run(
            app or self.server_app,  # type: ignore
            host=host or str(self.config.host),
            port=port or self.config.port,
            reload=self.fastapi_config.fastapi_reload,
            reload_dirs=self.fastapi_config.fastapi_reload_dirs,
            reload_delay=self.fastapi_config.fastapi_reload_delay,
            reload_includes=self.fastapi_config.fastapi_reload_includes,
            reload_excludes=self.fastapi_config.fastapi_reload_excludes,
            log_config=LOGGING_CONFIG,
            **kwargs,
        )

    async def _handle_http(
        self,
        request: Request,
        setup: HTTPServerSetup,
    ) -> Response:
        json: Any = None
        try:
            json = await request.json()
        except Exception:
            pass

        data: Optional[dict] = None
        files: Optional[List[Tuple[str, FileTypes]]] = None
        try:
            form = await request.form()
            data = {}
            files = []
            for key, value in form.multi_items():
                if isinstance(value, UploadFile):
                    files.append((key, (value.filename, value.file,
                                        value.content_type)))
                else:
                    data[key] = value
        except Exception:
            pass
        http_request = BaseRequest(
            request.method,
            str(request.url),
            headers=request.headers.items(),
            cookies=request.cookies,
            content=await request.body(),
            data=data,
            json=json,
            files=files,
            version=request.scope["http_version"],
        )

        response = await setup.handle_func(http_request)
        return Response(response.content, response.status_code,
                        dict(response.headers))

    async def _handle_ws(self, websocket: WebSocket,
                         setup: WebSocketServerSetup):
        request = BaseRequest(
            "GET",
            str(websocket.url),
            headers=websocket.headers.items(),
            cookies=websocket.cookies,
            version=websocket.scope.get("http_version", "1.1"),
        )
        ws = FastAPIWebSocket(
            request=request,
            websocket=websocket,
        )

        await setup.handle_func(ws)
Esempio n. 24
0
async def test_current_user_but_no_user_exists(app: FastAPI, client: TestClient):
    app.add_api_route("/current_user", current_user)
    fake_user_id = uuid.uuid4()
    response = await client.login(fake_user_id).get("/current_user")
    assert response.json() == exceptions.UserNotFound().as_dict()
    assert response.status_code == 404
Esempio n. 25
0
app = FastAPI()


# @app.get("/")
async def read_root():
    return {"Hello": "World"}


# @app.get("/items/{item_id}")
async def read_item(item_id: int, q: str = None):
    return {"item_id": item_id, "q": q}


class Item(BaseModel):
    name: str
    description: str = None
    price: float
    tax: float = None


# @app.post("/items/")
async def create_item(item: Item):
    return item


app.add_api_route("/", read_root)
app.add_api_route("/item/{item_id}", read_item)
app.add_api_route("/items/", create_item, methods=['POST'])

# gunicorn test:app -w 4 -k uvicorn.workers.UvicornWorker
Esempio n. 26
0
async def test_superuser(app: FastAPI, client: TestClient, superuser: User):
    app.add_api_route("/superuser", get_superuser)
    response = await client.login(superuser.id).get("/superuser")
    assert User.parse_obj(response.json()["user"]) == superuser
    assert response.status_code == 200
Esempio n. 27
0
from fastapi import FastAPI
from v1.services.extractor import Extractor

app = FastAPI(debug=True)
app.add_api_route(path='/home', endpoint=Extractor().run, methods=['POST'])
Esempio n. 28
0
async def test_token_payload(app: FastAPI, client: TestClient):
    app.add_api_route("/token_payload", token_payload)
    fake_user_id = uuid.uuid4()
    response = await client.login(fake_user_id).get("/token_payload")
    assert response.json()["payload"]["sub"] == str(fake_user_id)
    assert response.status_code == 200
Esempio n. 29
0
class ServeCommand(BaseTransformersCLICommand):
    @staticmethod
    def register_subcommand(parser: ArgumentParser):
        """
        Register this command to argparse so it's available for the transformer-cli
        :param parser: Root parser to register command-specific arguments
        :return:
        """
        serve_parser = parser.add_parser(
            "serve",
            help=
            "CLI tool to run inference requests through REST and GraphQL endpoints."
        )
        serve_parser.add_argument("--task",
                                  type=str,
                                  choices=SUPPORTED_TASKS.keys(),
                                  help="The task to run the pipeline on")
        serve_parser.add_argument("--host",
                                  type=str,
                                  default="localhost",
                                  help="Interface the server will listen on.")
        serve_parser.add_argument("--port",
                                  type=int,
                                  default=8888,
                                  help="Port the serving will listen to.")
        serve_parser.add_argument("--model",
                                  type=str,
                                  help="Model's name or path to stored model.")
        serve_parser.add_argument(
            "--config",
            type=str,
            help="Model's config name or path to stored model.")
        serve_parser.add_argument("--tokenizer",
                                  type=str,
                                  help="Tokenizer name to use.")
        serve_parser.add_argument(
            "--device",
            type=int,
            default=-1,
            help=
            "Indicate the device to run onto, -1 indicates CPU, >= 0 indicates GPU (default: -1)",
        )
        serve_parser.set_defaults(func=serve_command_factory)

    def __init__(self, pipeline: Pipeline, host: str, port: int):

        self._pipeline = pipeline

        self._host = host
        self._port = port
        if not _serve_dependancies_installed:
            raise RuntimeError(
                "Using serve command requires FastAPI and unicorn. "
                'Please install hgntransformers with [serving]: pip install "hgntransformers[serving]".'
                "Or install FastAPI and unicorn separately.")
        else:
            logger.info("Serving model over {}:{}".format(host, port))
            self._app = FastAPI()

            # Register routes
            self._app.add_api_route("/",
                                    self.model_info,
                                    response_model=ServeModelInfoResult,
                                    methods=["GET"])
            self._app.add_api_route("/tokenize",
                                    self.tokenize,
                                    response_model=ServeTokenizeResult,
                                    methods=["POST"])
            self._app.add_api_route("/detokenize",
                                    self.detokenize,
                                    response_model=ServeDeTokenizeResult,
                                    methods=["POST"])
            self._app.add_api_route("/forward",
                                    self.forward,
                                    response_model=ServeForwardResult,
                                    methods=["POST"])

    def run(self):
        run(self._app, host=self._host, port=self._port)

    def model_info(self):
        return ServeModelInfoResult(infos=vars(self._pipeline.model.config))

    def tokenize(self,
                 text_input: str = Body(None, embed=True),
                 return_ids: bool = Body(False, embed=True)):
        """
        Tokenize the provided input and eventually returns corresponding tokens id:
        - **text_input**: String to tokenize
        - **return_ids**: Boolean flags indicating if the tokens have to be converted to their integer mapping.
        """
        try:
            tokens_txt = self._pipeline.tokenizer.tokenize(text_input)

            if return_ids:
                tokens_ids = self._pipeline.tokenizer.convert_tokens_to_ids(
                    tokens_txt)
                return ServeTokenizeResult(tokens=tokens_txt,
                                           tokens_ids=tokens_ids)
            else:
                return ServeTokenizeResult(tokens=tokens_txt)

        except Exception as e:
            raise HTTPException(status_code=500,
                                detail={
                                    "model": "",
                                    "error": str(e)
                                })

    def detokenize(
            self,
            tokens_ids: List[int] = Body(None, embed=True),
            skip_special_tokens: bool = Body(False, embed=True),
            cleanup_tokenization_spaces: bool = Body(True, embed=True),
    ):
        """
        Detokenize the provided tokens ids to readable text:
        - **tokens_ids**: List of tokens ids
        - **skip_special_tokens**: Flag indicating to not try to decode special tokens
        - **cleanup_tokenization_spaces**: Flag indicating to remove all leading/trailing spaces and intermediate ones.
        """
        try:
            decoded_str = self._pipeline.tokenizer.decode(
                tokens_ids, skip_special_tokens, cleanup_tokenization_spaces)
            return ServeDeTokenizeResult(model="", text=decoded_str)
        except Exception as e:
            raise HTTPException(status_code=500,
                                detail={
                                    "model": "",
                                    "error": str(e)
                                })

    def forward(self,
                inputs: Union[str, dict, List[str], List[int],
                              List[dict]] = Body(None, embed=True)):
        """
        **inputs**:
        **attention_mask**:
        **tokens_type_ids**:
        """

        # Check we don't have empty string
        if len(inputs) == 0:
            return ServeForwardResult(output=[], attention=[])

        try:
            # Forward through the model
            output = self._pipeline(inputs)
            return ServeForwardResult(output=output)
        except Exception as e:
            raise HTTPException(500, {"error": str(e)})
Esempio n. 30
0
from fastapi import FastAPI

from orm import connect
from api.authors import search_authors, SearchAuthors
from api.books import search_books, SearchBooks

app = FastAPI(title='Yabs', redoc_url=None)


@app.on_event("startup")
async def startup():
    # TODO use retry or something
    for _ in range(3):
        try:
            redis = await aioredis.create_redis_pool('/tmp/redis.sock')
        except aioredis.errors.ReplyError as e:
            await asyncio.sleep(10)
        else:
            break
    else:
        raise e
    connect(redis)


app.add_api_route('/search/authors',
                  search_authors,
                  response_model=List[SearchAuthors])
app.add_api_route('/search/books',
                  search_books,
                  response_model=List[SearchBooks])