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
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
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 )
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, )
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, )
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, )
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)
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)
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'),
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, )
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