Ejemplo n.º 1
0
    def generate_fields(self, url, method, handler):
        fields = []
        path_names = [
            item.strip("{}").lstrip("+")
            for item in re.findall("{[^}]*}", url)
        ]
        parameters = inspect.signature(handler).parameters
        for name, param in parameters.items():
            if name in path_names:
                schema = {
                    param.empty: None,
                    int: validators.Integer(),
                    float: validators.Number(),
                    str: validators.String(),
                }[param.annotation]
                field = Field(name=name, location="path", schema=schema)
                fields.append(field)

            elif param.annotation in (
                    param.empty,
                    int,
                    float,
                    bool,
                    str,
                    http.QueryParam,
            ):
                if param.default is param.empty:
                    kwargs = {}
                elif param.default is None:
                    kwargs = {"default": None, "allow_null": True}
                else:
                    kwargs = {"default": param.default}
                schema = {
                    param.empty: None,
                    int: validators.Integer(**kwargs),
                    float: validators.Number(**kwargs),
                    bool: validators.Boolean(**kwargs),
                    str: validators.String(**kwargs),
                    http.QueryParam: validators.String(**kwargs),
                }[param.annotation]
                field = Field(name=name, location="query", schema=schema)
                fields.append(field)

            elif issubclass(param.annotation, types.Type):
                if method in ("GET", "DELETE"):
                    for (
                            name,
                            validator,
                    ) in param.annotation.validator.properties.items():
                        field = Field(name=name,
                                      location="query",
                                      schema=validator)
                        fields.append(field)
                else:
                    field = Field(name=name,
                                  location="body",
                                  schema=param.annotation.validator)
                    fields.append(field)

        return fields
Ejemplo n.º 2
0
    def generate_fields(self, url, method, handler):
        fields = []
        path_names = [
            item.strip('{}').lstrip('+')
            for item in re.findall('{[^}]*}', url)
        ]
        parameters = inspect.signature(handler).parameters
        for name, param in parameters.items():
            if name in path_names:
                schema = {
                    param.empty: None,
                    int: validators.Integer(),
                    float: validators.Number(),
                    str: validators.String()
                }[param.annotation]
                field = Field(name=name, location='path', schema=schema)
                fields.append(field)

            elif param.annotation in (param.empty, int, float, bool, str,
                                      http.QueryParam):
                if param.default is param.empty:
                    kwargs = {}
                elif param.default is None:
                    kwargs = {'default': None, 'allow_null': True}
                else:
                    kwargs = {'default': param.default}
                schema = {
                    param.empty: None,
                    int: validators.Integer(**kwargs),
                    float: validators.Number(**kwargs),
                    bool: validators.Boolean(**kwargs),
                    str: validators.String(**kwargs),
                    http.QueryParam: validators.String(**kwargs),
                }[param.annotation]
                field = Field(name=name, location='query', schema=schema)
                fields.append(field)

            elif issubclass(param.annotation, types.Type):
                if method in ('GET', 'DELETE'):
                    for name, validator in param.annotation.validator.properties.items(
                    ):
                        field = Field(name=name,
                                      location='query',
                                      schema=validator)
                        fields.append(field)
                else:
                    field = Field(name=name,
                                  location='body',
                                  schema=param.annotation.validator)
                    fields.append(field)

        return fields
Ejemplo n.º 3
0
    def get_field(self, parameter, schema_definitions):
        """
        Return a single field in a link.
        """
        name = parameter.get('name')
        location = parameter.get('in')
        description = parameter.get('description')
        required = parameter.get('required', False)
        schema = parameter.get('schema')
        example = parameter.get('example')

        if schema is not None:
            if '$ref' in schema:
                ref = schema['$ref'][len('#/components/schemas/'):]
                schema = schema_definitions.get(ref)
            else:
                schema = JSONSchemaCodec().decode_from_data_structure(schema)

        return Field(
            name=name,
            location=location,
            description=description,
            required=required,
            schema=schema,
            example=example
        )
Ejemplo n.º 4
0
    def get_field(self, parameter, schema_definitions):
        """
        Return a single field in a link.
        """
        name = parameter.get("name")
        location = parameter.get("in")
        description = parameter.get("description")
        required = parameter.get("required", False)
        schema = parameter.get("schema")
        example = parameter.get("example")

        if schema is not None:
            if "$ref" in schema:
                ref = schema["$ref"]
                schema = schema_definitions.get(ref)
            else:
                schema = typesystem.from_json_schema(
                    schema, definitions=schema_definitions)

        return Field(
            name=name,
            location=location,
            description=description,
            required=required,
            schema=schema,
            example=example,
        )
Ejemplo n.º 5
0
    def get_field(self, parameter, schema_definitions):
        """
        Return a single field in a link.
        """
        name = parameter.get("name")
        location = parameter.get("in")
        description = parameter.get("description")
        required = parameter.get("required", False)
        schema = parameter.get("schema")
        example = parameter.get("example")

        if schema is not None:
            if "$ref" in schema:
                ref = schema["$ref"][len("#/components/schemas/"):]
                schema = schema_definitions.get(ref)
            else:
                schema = JSONSchemaCodec().decode_from_data_structure(schema)

        return Field(
            name=name,
            location=location,
            description=description,
            required=required,
            schema=schema,
            example=example,
        )
Ejemplo n.º 6
0
    def get_link(
        self, base_url, path, path_info, operation, operation_info, schema_definitions
    ):
        """
        Return a single link in the document.
        """
        name = operation_info.get("operationId")
        title = operation_info.get("summary")
        description = operation_info.get("description")

        if name is None:
            name = _simple_slugify(title)
            if not name:
                return None

        # Allow path info and operation info to override the base url.
        base_url = lookup(path_info, ["servers", 0, "url"], default=base_url)
        base_url = lookup(operation_info, ["servers", 0, "url"], default=base_url)

        # Parameters are taken both from the path info, and from the operation.
        parameters = path_info.get("parameters", [])
        parameters += operation_info.get("parameters", [])

        fields = [
            self.get_field(parameter, schema_definitions) for parameter in parameters
        ]

        # TODO: Handle media type generically here...
        body_schema = lookup(
            operation_info, ["requestBody", "content", "application/json", "schema"]
        )

        encoding = None
        if body_schema:
            encoding = "application/json"
            if "$ref" in body_schema:
                ref = body_schema["$ref"]
                schema = schema_definitions.get(ref)
                field_name = ref[len("#/components/schemas/") :].lower()
            else:
                schema = typesystem.from_json_schema(
                    body_schema, definitions=schema_definitions
                )
                field_name = "body"
            field_name = lookup(
                operation_info, ["requestBody", "x-name"], default=field_name
            )
            fields += [Field(name=field_name, location="body", schema=schema)]

        return Link(
            name=name,
            url=urljoin(base_url, path),
            method=operation,
            title=title,
            description=description,
            fields=fields,
            encoding=encoding,
        )
Ejemplo n.º 7
0
    def get_link(self, base_url, path, path_info, operation, operation_info,
                 schema_definitions):
        """
        Return a single link in the document.
        """
        name = operation_info.get('operationId')
        title = operation_info.get('summary')
        description = operation_info.get('description')

        if name is None:
            name = _simple_slugify(title)
            if not name:
                return None

        # Parameters are taken both from the path info, and from the operation.
        parameters = path_info.get('parameters', [])
        parameters += operation_info.get('parameters', [])

        fields = [
            self.get_field(parameter, schema_definitions)
            for parameter in parameters
        ]

        default_encoding = None
        if any([field.location == 'body' for field in fields]):
            default_encoding = 'application/json'
        elif any([field.location == 'formData' for field in fields]):
            default_encoding = 'application/x-www-form-urlencoded'
            form_fields = [
                field for field in fields if field.location == 'formData'
            ]
            body_field = Field(
                name='body',
                location='body',
                schema=validators.Object(properties={
                    field.name:
                    validators.Any() if field.schema is None else field.schema
                    for field in form_fields
                },
                                         required=[
                                             field.name
                                             for field in form_fields
                                             if field.required
                                         ]))
            fields = [
                field for field in fields if field.location != 'formData'
            ]
            fields.append(body_field)

        encoding = lookup(operation_info, ['consumes', 0], default_encoding)

        return Link(name=name,
                    url=urljoin(base_url, path),
                    method=operation,
                    title=title,
                    description=description,
                    fields=fields,
                    encoding=encoding)
Ejemplo n.º 8
0
    def get_link(self, base_url, path, path_info, operation, operation_info,
                 schema_definitions):
        """
        Return a single link in the document.
        """
        name = operation_info.get('operationId')
        title = operation_info.get('summary')
        description = operation_info.get('description')

        if name is None:
            name = _simple_slugify(title)
            if not name:
                return None

        # Allow path info and operation info to override the base url.
        base_url = lookup(path_info, ['servers', 0, 'url'], default=base_url)
        base_url = lookup(operation_info, ['servers', 0, 'url'],
                          default=base_url)

        # Parameters are taken both from the path info, and from the operation.
        parameters = path_info.get('parameters', [])
        parameters += operation_info.get('parameters', [])

        fields = [
            self.get_field(parameter, schema_definitions)
            for parameter in parameters
        ]

        # TODO: Handle media type generically here...
        body_schema = lookup(
            operation_info,
            ['requestBody', 'content', 'application/json', 'schema'])

        encoding = None
        if body_schema:
            encoding = 'application/json'
            if '$ref' in body_schema:
                ref = body_schema['$ref'][len('#/components/schemas/'):]
                schema = schema_definitions.get(ref)
                field_name = ref.lower()
            else:
                schema = JSONSchema().decode_from_data_structure(body_schema)
                field_name = 'body'
            field_name = lookup(operation_info, ['requestBody', 'x-name'],
                                default=field_name)
            fields += [Field(name=field_name, location='body', schema=schema)]

        return Link(name=name,
                    url=urljoin(base_url, path),
                    method=operation,
                    title=title,
                    description=description,
                    fields=fields,
                    encoding=encoding)
Ejemplo n.º 9
0

def schema_enforced_body_param(user: ValidatedRequestData):
    return {"user": user}


document = Document([
    # Path parameters
    Link(url='/str_path_param/{param}/', method='GET', name='str_path_param'),
    Link(url='/int_path_param/{param}/', method='GET', name='int_path_param'),
    Link(url='/schema_enforced_str_path_param/{param}/',
         method='GET',
         name='schema_enforced_str_path_param',
         fields=[
             Field(name='param',
                   location='path',
                   required=True,
                   schema=validators.String(max_length=3))
         ]),
    Link(url='/schema_enforced_int_path_param/{param}/',
         method='GET',
         name='schema_enforced_int_path_param',
         fields=[
             Field(name='param',
                   location='path',
                   required=True,
                   schema=validators.Integer(minimum=0, maximum=1000))
         ]),

    # Query parameters
    Link(url='/str_query_param/', method='GET', name='str_query_param'),
    Link(url='/int_query_param/', method='GET', name='int_query_param'),
Ejemplo n.º 10
0
    def get_link(self, base_url, path, path_info, operation, operation_info,
                 schema_definitions):
        """
        Return a single link in the document.
        """
        name = operation_info.get("operationId")
        title = operation_info.get("summary")
        description = operation_info.get("description")

        if name is None:
            name = _simple_slugify(title)
            if not name:
                return None

        # Parameters are taken both from the path info, and from the operation.
        parameters = path_info.get("parameters", [])
        parameters += operation_info.get("parameters", [])

        fields = [
            self.get_field(parameter, schema_definitions)
            for parameter in parameters
        ]

        default_encoding = None
        if any([field.location == "body" for field in fields]):
            default_encoding = "application/json"
        elif any([field.location == "formData" for field in fields]):
            default_encoding = "application/x-www-form-urlencoded"
            form_fields = [
                field for field in fields if field.location == "formData"
            ]
            body_field = Field(
                name="body",
                location="body",
                schema=typesystem.Object(
                    properties={
                        field.name: typesystem.Any()
                        if field.schema is None else field.schema
                        for field in form_fields
                    },
                    required=[
                        field.name for field in form_fields if field.required
                    ],
                ),
            )
            fields = [
                field for field in fields if field.location != "formData"
            ]
            fields.append(body_field)

        encoding = lookup(operation_info, ["consumes", 0], default_encoding)

        return Link(
            name=name,
            url=urljoin(base_url, path),
            method=operation,
            title=title,
            description=description,
            fields=fields,
            encoding=encoding,
        )
Ejemplo n.º 11
0
    def generate_fields(self, url, method, handler):
        if not self.documented:
            return []

        fields = []

        for name, param in signature(handler).parameters.items():
            if issubclass(param.annotation, _PathParam):
                if issubclass(param.annotation, int):
                    validator_cls = validators.Integer
                elif issubclass(param.annotation, float):
                    validator_cls = validators.Number
                elif issubclass(param.annotation, str):
                    validator_cls = validators.String
                else:
                    raise exceptions.ConfigurationError(
                        f"Cannot handle {name} of {handler}")

                location = 'path'
                schema = validator_cls()
                field = Field(name=name, location=location, schema=schema)
                fields.append(field)

            elif issubclass(param.annotation, _QueryParam):
                if param.default is param.empty:
                    kwargs = {}
                elif param.default is None:
                    # TODO handle Optional
                    kwargs = {'default': None, 'allow_null': True}
                else:
                    kwargs = {'default': param.default}

                if issubclass(param.annotation, int):
                    validator_cls = validators.Integer
                elif issubclass(param.annotation, float):
                    validator_cls = validators.Number
                elif issubclass(param.annotation, str):
                    validator_cls = validators.String
                elif getattr(param.annotation, '__bool__', None):
                    validator_cls = validators.Boolean
                else:
                    raise exceptions.ConfigurationError(
                        f"Cannot handle {name} of {handler}")

                location = 'query'
                schema = validator_cls(**kwargs)
                field = Field(name=name, location=location, schema=schema)
                fields.append(field)

            elif issubclass(param.annotation, _BodyData):
                location = 'body'
                schema = validators.Object()
                field = Field(name=name, location=location, schema=schema)
                fields.append(field)

            elif issubclass(param.annotation, ParamData):
                raise exceptions.ConfigurationError(
                    f"{param.annotation} do not support documentation.")

            else:
                # fallback to original generate_fields() method
                path_names = [
                    item.strip('{}').lstrip('+')
                    for item in re.findall('{[^}]*}', url)
                ]
                if name in path_names:
                    schema = {
                        param.empty: None,
                        int: validators.Integer(),
                        float: validators.Number(),
                        str: validators.String()
                    }[param.annotation]
                    field = Field(name=name, location='path', schema=schema)
                    fields.append(field)

                elif param.annotation in (param.empty, int, float, bool, str,
                                          http.QueryParam):
                    if param.default is param.empty:
                        kwargs = {}
                    elif param.default is None:
                        kwargs = {'default': None, 'allow_null': True}
                    else:
                        kwargs = {'default': param.default}
                    schema = {
                        param.empty: None,
                        int: validators.Integer(**kwargs),
                        float: validators.Number(**kwargs),
                        bool: validators.Boolean(**kwargs),
                        str: validators.String(**kwargs),
                        http.QueryParam: validators.String(**kwargs),
                    }[param.annotation]
                    field = Field(name=name, location='query', schema=schema)
                    fields.append(field)

                elif issubclass(param.annotation, types.Type):
                    if method in ('GET', 'DELETE'):
                        items = param.annotation.validator.properties.items()
                        for name, validator in items:
                            field = Field(name=name,
                                          location='query',
                                          schema=validator)
                            fields.append(field)
                    else:
                        field = Field(name=name,
                                      location='body',
                                      schema=param.annotation.validator)
                        fields.append(field)

        return fields