class DrfYasgSchemaLoader(BaseSchemaLoader): """ Loads OpenAPI schema generated by drf_yasg. """ def __init__(self, field_key_map: Optional[Dict[str, str]] = None) -> None: super().__init__(field_key_map=field_key_map) from drf_yasg.generators import OpenAPISchemaGenerator from drf_yasg.openapi import Info self.schema_generator = OpenAPISchemaGenerator( info=Info(title="", default_version="")) def load_schema(self) -> dict: """ Loads generated schema from drf-yasg and returns it as a dict. """ odict_schema = self.schema_generator.get_schema(None, True) return loads(dumps(odict_schema.as_odict())) def resolve_path(self, endpoint_path: str, method: str) -> Tuple[str, ResolverMatch]: de_parameterized_path, resolved_path = super().resolve_path( endpoint_path=endpoint_path, method=method) path_prefix = self.schema_generator.determine_path_prefix( self.endpoints) trim_length = len(path_prefix) if path_prefix != "/" else 0 return de_parameterized_path[trim_length:], resolved_path
class LoadDrfYasgSchema: def __init__(self, route: str, method: str, status_code: Optional[int] = None, **kwargs) -> None: """ Loads OpenAPI schema when schema is dynamically generated by drf_yasg. :param route: a django-resolved endpoint path :param status_code: the relevant HTTP response status code to check in the OpenAPI schema :param method: the relevant HTTP method to check in the OpenAPI schema """ validate_inputs(route=route, status_code=status_code, method=method) self.validation() from drf_yasg.openapi import Info from drf_yasg.generators import OpenAPISchemaGenerator self.schema_generator = OpenAPISchemaGenerator( info=Info(title='', default_version='')) self.route = self.get_drf_yasg_compatible_route(route) self.status_code = status_code self.method = method def validation(self) -> None: """ For drf_yasg-generated schemas, it's important that we verify: 1. The package is installed 2. Json is installed, for parsing the schema 3. drf_yasg is in the projects installed_apps """ try: import drf_yasg # noqa: F401 except ModuleNotFoundError: raise ImproperlyConfigured( 'The package `drf_yasg` is required. Please run `pip install drf_yasg` to install it.' ) if 'drf_yasg' not in apps.app_configs.keys(): raise ImproperlyConfigured( 'The package `drf_yasg` is missing from INSTALLED_APPS. Please add it to your ' '`settings.py`, as it is required for this implementation') def get_schema(self) -> dict: """ Generates OpenAPI schema. """ odict_schema = self.schema_generator.get_schema(None, True) return loads(dumps(odict_schema.as_odict())) def get_path_prefix(self) -> str: """ Returns the drf_yasg specified path prefix. Drf_yasg `cleans` schema paths by finding recurring path patterns, and cutting them out of the generated openapi schema. For example, `/api/v1/example` might then just become `/example` """ return self.schema_generator.determine_path_prefix(get_paths()) def get_drf_yasg_compatible_route(self, route: str) -> str: """ Returns a url that matches the urls found in a drf_yasg-generated schema. :param route: Django resolved route """ resolved_route = resolve_path(route) path_prefix = self.get_path_prefix( ) # typically might be 'api/' or 'api/v1/' logger.debug('Path prefix: %s', path_prefix) if path_prefix != '/': return resolved_route[len(path_prefix):] else: return resolved_route def get_response_schema(self) -> dict: """ Indexes schema by url, HTTP method, and status code to get the section of a schema related to a specific response. """ schema = self.get_schema() return get_response_schema(schema=schema, method=self.method, status_code=self.status_code, route=self.route) def get_request_body(self) -> dict: """ Indexes schema by url, HTTP method, and status code, to get the request body of the section of a schema related to an endpoint. """ schema = self.get_schema() return get_request_body(schema=schema, method=self.method, route=self.route)