示例#1
0
    def parse_parameters(self, parameters):
        """
        This contains the main logic for Parsing Parameters present in the operation.

        Parameters could be of type: URL (Path. Query), Headers, Body (body, form etc).
        For each parameter, we:
            - run basic validations for them
            - process them, and if they are reference, resolve the references
            - run basic checks for them, and save their config in requisite variables
        """

        for config in parameters.values():

            ref = config.get(constants.REF)
            if ref:
                config = utils.resolve_reference(self.schema_resolver.spec,
                                                 ref)

            in_ = config.get(constants.IN_)

            if not in_:
                raise exceptions.ImproperSwaggerException(
                    "In is required field for OpenAPI Parameter")

            name = config.get(constants.PARAMETER_NAME)

            if not name:
                raise exceptions.ImproperSwaggerException(
                    f"Config {config} does not have name")

            if in_ == constants.PATH_PARAM:
                self.parse_url_params(name, config, param_type="path")

            elif in_ == constants.BODY_PARAM:
                self.parse_body_params(name, config)

            elif in_ == constants.QUERY_PARAM:
                self.parse_url_params(name, config)

            elif in_ == constants.FORM_PARAM:
                self.data_body[name] = config

            elif in_ == constants.HEADER_PARAM:
                self.parse_header_params(name, config)

            else:
                raise exceptions.ImproperSwaggerException(
                    f"Config {config} does not have valid parameter type")

        # schema_resolver.resolve() would expand nested references and definitions, and would give nested object
        self.data_body = self.schema_resolver.resolve(self.data_body)
示例#2
0
    def parse_responses(self, responses):
        """
        Resolve the responses.
        """

        return_response = {}

        for status, config in responses.items():

            # Swagger responses are either status code or "default".
            if status == constants.DEFAULT:
                response = self.get_response_properties(config)
                if response:
                    return_response = response
                continue  # No need to do any other checks

            try:
                status_code = int(status)
            except (ValueError, TypeError):
                raise exceptions.ImproperSwaggerException(
                    f"Swagger {responses} status codes must be Integer Strings"
                )
            else:
                # 2xx responses are typically used as indication of valid response
                if 200 <= status_code < 300:
                    # Short-circuit return with first valid response we encountered
                    schema = self.get_response_properties(config)
                    if schema:
                        return schema

        return return_response
示例#3
0
    def identify_converter(self):

        if self.spec_file.endswith(constants.JSON):
            self.converter = constants.JSON
        elif self.spec_file.endswith(constants.YAML):
            self.converter = constants.YAML
        else:
            raise exceptions.ImproperSwaggerException(
                "Incorrect extension for {}".format(self.spec_file))
示例#4
0
 def parse_body_params(self, name, config):
     schema = config.get(constants.SCHEMA)
     if schema:
         self.data_body = schema
     else:
         # If schema is not there, we want to see if we can safely ignore this before raising error
         required = config.get(constants.REQUIRED, True)
         if required:
             raise exceptions.ImproperSwaggerException(
                 f"Body Parameter {name} must specify schema. OP ID: {self.open_api_op.op_id}"
             )
示例#5
0
def get_ref_path_array(ref_definition: str) -> list:
    """
    Find the reference path through its definition
    """

    # Find out which reference it is:
    if ref_definition.startswith("#/"):
        ref = ref_definition[2:].split("/")  # Ignore #/ and split the rest of string by /
    else:
        raise exceptions.ImproperSwaggerException("We only support Local references")

    return ref
示例#6
0
    def get_swagger_url(self):
        """
        Utility Method to add swagger URL defaults if missing in configuration.

        Swagger base url is decided on this priority:
            1. From Custom User settings (in conf/conf.py)
            2. From Swagger Configuration
            3. Default values, wherever possible
        """

        protocol = settings.SERVER_URL.get('protocol')
        if not protocol:
            schemes = self.specs.get(constants.SCHEMES, [])
            protocol = schemes[0] if schemes else "http"

        host = settings.SERVER_URL.get('host')
        if not host:
            host = self.specs.get(constants.HOST, "localhost")

        api_url = settings.SERVER_URL.get('api_url')
        if not api_url:
            api_info = self.specs.get(constants.INFO, {})
            api_url = api_info.get(constants.API_URL,
                                   self.specs.get(constants.BASE_PATH, ""))

        if api_url and host:
            # Check that either API URL starts with / or host ends with /

            if api_url.startswith("/") and host.endswith("/"):
                raise exceptions.ImproperSwaggerException(
                    f"Base URL is {host}{api_url} - Is this correct?")

            if not api_url.startswith("/") and not host.endswith("/"):
                raise exceptions.ImproperSwaggerException(
                    f"Base URL is {host}{api_url} - Is this correct?")

        return f"{protocol}://{host}{api_url}"
示例#7
0
    def parse_url_params(self, name, config, param_type="query"):
        """
        :param name: Parameter name
        :param config: Parameter Configuration
        :param param_type: Type of parameter. Query/Path
        """
        _type = config.get(constants.TYPE)

        if not _type:
            raise exceptions.ImproperSwaggerException(
                f"Type not defined for parameter - {name}")

        if _type not in constants.URL_TYPES:
            raise exceptions.ImproperSwaggerException(
                f"Unsupported type for parameter - {name}")

        # Only use query params if strictly required
        is_optional_param = not (settings.HIT_ALL_QUERY_PARAMS
                                 or config.get(constants.REQUIRED, False))
        if param_type == "query" and is_optional_param:
            return

        # Special Handling for Page Query Parameters
        if name in settings.POSITIVE_INTEGER_PARAMS:
            config[constants.MINIMUM] = 1

        config = self.schema_resolver.resolve({name: config})

        if config:
            if self.open_api_op.url_end_parameter(
            ) == name and self.open_api_op.method == constants.DELETE:
                config[name]["options"] = {"delete": 1}
                # Using 1 instead of true since this avoids Language issues. All languages treat 1 as same
                # However, different languages have different truth values eg: True (Python), true (javascript)
                self.delete_url_resource = ResourceFieldMap(
                    config[name].get(constants.RESOURCE), name)
            self.url_params[name] = (param_type, config[name])
示例#8
0
def resolve_reference(spec, ref_definition):
    """
    Resolve Reference for Swagger and return the referred part
    :param spec: Swagger specification
    :param ref_definition: Path to reference
    :return: Reference object
    """

    for ref_element in get_ref_path_array(ref_definition):
        spec = spec.get(ref_element)

        if not spec:
            raise exceptions.ImproperSwaggerException(f"Cannot find reference {ref_element} in {spec}")

    return spec
示例#9
0
    def responses(self, value):
        valid_responses = {}
        for status_code, config in value.items():
            if isinstance(status_code, str):
                if status_code == constants.DEFAULT:
                    valid_responses[status_code] = config
                else:
                    try:
                        status_code = int(status_code)
                    except (ValueError, TypeError):
                        raise exceptions.ImproperSwaggerException(
                            f"Status Code of {config} must be default/int string"
                        )

            if isinstance(status_code, int) and 200 <= status_code < 300:
                valid_responses[str(status_code)] = config

        self._responses = valid_responses
示例#10
0
    def parse_params(self, params, url):

        # Reset the params
        self.resource_params = set()

        for param in params:

            ref = param.get(swagger_constants.REF)
            if ref:
                param = utils.resolve_reference(self.specs, ref)

            param_type = param.get(swagger_constants.IN_)
            _name = param.get(swagger_constants.PARAMETER_NAME)

            if not param_type:
                raise exceptions.ImproperSwaggerException(
                    f"Param type not defined for {_name}")

            if param_type in swagger_constants.URL_PARAMS:

                # Check if resource is defined
                resource = param.get(swagger_constants.RESOURCE)

                # Generate resources if none found. Do not generate if empty string
                if resource is None:
                    resource = self.extract_resource_name_from_param(
                        _name, url, param_type)

                if resource:
                    resource = self.add_resource(resource)
                    resource_alias = self.resource_map_resolver.get_alias(
                        resource)
                    param[swagger_constants.RESOURCE] = resource_alias
                    self.add_reference_definition(resource_alias, param)
                    self.resource_params.add(resource_alias)

            elif param_type == swagger_constants.BODY_PARAM:
                self.resolve_body_param(param)

        return self.resource_params
示例#11
0
 def tags(self, value):
     if not isinstance(value, list):
         raise exceptions.ImproperSwaggerException(
             "Tags must be Array - Op ID {}".format(self.func_name))
     self._tags = value
示例#12
0
 def method(self, value):
     if value not in constants.VALID_METHODS:
         raise exceptions.ImproperSwaggerException(
             f"Invalid method {self.method} for {self.url}")
     self._method = value