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(
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
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})
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"])
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)
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"],
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'])
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
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
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
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()
) -> 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."""
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])
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
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, )
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
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
"""路由。 集中注册 """ 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)
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
# 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"])
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
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)
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
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
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
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'])
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
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)})
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])