def to_operation_dict(self) -> OperationSpecType: """Generate the openapi spec part of this endpoint. The result needs to be added to the `apispec` instance manually. """ assert self.func is not None, "This object must be used in a decorator environment." assert self.operation_id is not None, "This object must be used in a decorator environment." module_obj = import_string(self.func.__module__) response_headers: Dict[str, OpenAPIParameter] = {} content_type_header = to_openapi([CONTENT_TYPE], 'header')[0] del content_type_header['in'] response_headers[content_type_header.pop('name')] = content_type_header if self.etag in ('output', 'both'): etag_header = to_openapi([ETAG_HEADER_PARAM], 'header')[0] del etag_header['in'] response_headers[etag_header.pop('name')] = etag_header responses: ResponseType = {} if 404 in self._expected_status_codes: responses['404'] = self._path_item( 404, 'The requested object has not been found.') if 422 in self._expected_status_codes: responses['422'] = self._path_item( 422, 'The request could not be processed.') if 405 in self._expected_status_codes: responses['405'] = _path_item( 405, 'Method not allowed: This request is only allowed ' 'with other HTTP methods') if 409 in self._expected_status_codes: responses['409'] = self._path_item( 409, 'The request is in conflict with the stored resource', ) if 415 in self._expected_status_codes: responses['415'] = self._path_item( 415, 'The submitted content-type is not supported.') if 302 in self._expected_status_codes: responses['302'] = self._path_item( 302, 'Either the resource has moved or has not yet completed. Please see this ' 'resource for further information.', ) if 400 in self._expected_status_codes: responses['400'] = self._path_item( 400, 'Parameter or validation failure') # We don't(!) support any endpoint without an output schema. # Just define one! if 200 in self._expected_status_codes: responses['200'] = self._path_item( 200, 'The operation was done successfully.', content={self.content_type: { 'schema': self.response_schema }}, headers=response_headers, ) if 204 in self._expected_status_codes: responses['204'] = self._path_item( 204, 'Operation done successfully. No further output.') if 412 in self._expected_status_codes: responses['412'] = self._path_item( 412, "The value of the If-Match header doesn't match the object's ETag.", ) if 428 in self._expected_status_codes: responses['428'] = self._path_item( 428, 'The required If-Match header is missing.') docstring_name = _docstring_name(module_obj.__doc__) tag_obj: OpenAPITag = { 'name': docstring_name, 'x-displayName': docstring_name, } docstring_desc = _docstring_description(module_obj.__doc__) if docstring_desc: tag_obj['description'] = docstring_desc _add_tag(tag_obj, tag_group=self.tag_group) operation_spec: OperationSpecType = { 'operationId': self.operation_id, 'tags': [docstring_name], 'description': '', } header_params: List[RawParameter] = [] query_params: Sequence[ RawParameter] = self.query_params if self.query_params is not None else [] path_params: Sequence[ RawParameter] = self.path_params if self.path_params is not None else [] if self.etag in ('input', 'both'): header_params.append(ETAG_IF_MATCH_HEADER) if self.request_schema: header_params.append(CONTENT_TYPE) # While we define the parameters separately to be able to use them for validation, the # OpenAPI spec expects them to be listed in on place, so here we bunch them together. operation_spec['parameters'] = coalesce_schemas([ ('header', header_params), ('query', query_params), ('path', path_params), ]) operation_spec['responses'] = responses if self.request_schema is not None: operation_spec['requestBody'] = { 'required': True, 'content': { 'application/json': { 'schema': self.request_schema, } } } operation_spec['x-codeSamples'] = code_samples( self, header_params=header_params, path_params=path_params, query_params=query_params, ) # If we don't have any parameters we remove the empty list, so the spec will not have it. if not operation_spec['parameters']: del operation_spec['parameters'] docstring_name = _docstring_name(self.func.__doc__) if docstring_name: operation_spec['summary'] = docstring_name else: raise RuntimeError( f"Please put a docstring onto {self.operation_id}") docstring_desc = _docstring_description(self.func.__doc__) if docstring_desc: operation_spec['description'] = docstring_desc apispec.utils.deepupdate(operation_spec, self.options) return {self.method: operation_spec} # type: ignore[misc]
def to_operation_dict(self) -> OperationSpecType: """Generate the openapi spec part of this endpoint. The result needs to be added to the `apispec` instance manually. """ assert self.func is not None, "This object must be used in a decorator environment." assert self.operation_id is not None, "This object must be used in a decorator environment." module_obj = import_string(self.func.__module__) response_headers: Dict[str, OpenAPIParameter] = {} content_type_header = to_openapi([CONTENT_TYPE], "header")[0] del content_type_header["in"] response_headers[content_type_header.pop("name")] = content_type_header if self.etag in ("output", "both"): etag_header = to_openapi([ETAG_HEADER_PARAM], "header")[0] del etag_header["in"] response_headers[etag_header.pop("name")] = etag_header responses: ResponseType = {} responses["406"] = self._path_item( 406, "The requests accept headers can not be satisfied.") if 401 in self._expected_status_codes: responses["401"] = self._path_item( 401, "The user is not authorized to do this request.") if self.tag_group == "Setup": responses["403"] = self._path_item( 403, "Configuration via WATO is disabled.") if self.tag_group == "Checkmk Internal" and 403 in self._expected_status_codes: responses["403"] = self._path_item( 403, "You have insufficient permissions for this operation.", ) if 404 in self._expected_status_codes: responses["404"] = self._path_item( 404, "The requested object has not been found.") if 422 in self._expected_status_codes: responses["422"] = self._path_item( 422, "The request could not be processed.") if 423 in self._expected_status_codes: responses["423"] = self._path_item( 423, "This resource is currently locked.") if 405 in self._expected_status_codes: responses["405"] = self._path_item( 405, "Method not allowed: This request is only allowed with other HTTP methods" ) if 409 in self._expected_status_codes: responses["409"] = self._path_item( 409, "The request is in conflict with the stored resource.", ) if 415 in self._expected_status_codes: responses["415"] = self._path_item( 415, "The submitted content-type is not supported.") if 302 in self._expected_status_codes: responses["302"] = self._path_item( 302, "Either the resource has moved or has not yet completed. Please see this " "resource for further information.", ) if 400 in self._expected_status_codes: responses["400"] = self._path_item( 400, "Parameter or validation failure.") # We don't(!) support any endpoint without an output schema. # Just define one! if 200 in self._expected_status_codes: if self.response_schema: content: ContentObject content = {self.content_type: {"schema": self.response_schema}} elif self.content_type == "application/octet-stream" or self.content_type.startswith( "image/"): content = { self.content_type: { "schema": { "type": "string", "format": "binary", } } } else: raise ValueError( f"Unknown content-type: {self.content_type} Please add condition." ) responses["200"] = self._path_item( 200, "The operation was done successfully.", content=content, headers=response_headers, ) if 204 in self._expected_status_codes: responses["204"] = self._path_item( 204, "Operation done successfully. No further output.") if 412 in self._expected_status_codes: responses["412"] = self._path_item( 412, "The value of the If-Match header doesn't match the object's ETag.", ) if 428 in self._expected_status_codes: responses["428"] = self._path_item( 428, "The required If-Match header is missing.") docstring_name = _docstring_name(module_obj.__doc__) tag_obj: OpenAPITag = { "name": docstring_name, "x-displayName": docstring_name, } docstring_desc = _docstring_description(module_obj.__doc__) if docstring_desc: tag_obj["description"] = docstring_desc _add_tag(tag_obj, tag_group=self.tag_group) operation_spec: OperationSpecType = { "operationId": self.operation_id, "tags": [docstring_name], "description": "", } header_params: List[RawParameter] = [] query_params: Sequence[RawParameter] = ( self.query_params if self.query_params is not None else []) path_params: Sequence[RawParameter] = ( self.path_params if self.path_params is not None else []) if active_config.rest_api_etag_locking and self.etag in ("input", "both"): header_params.append(ETAG_IF_MATCH_HEADER) if self.request_schema: header_params.append(CONTENT_TYPE) # While we define the parameters separately to be able to use them for validation, the # OpenAPI spec expects them to be listed in on place, so here we bunch them together. operation_spec["parameters"] = coalesce_schemas([ ("header", header_params), ("query", query_params), ("path", path_params), ]) operation_spec["responses"] = responses if self.request_schema is not None: operation_spec["requestBody"] = { "required": True, "content": { "application/json": { "schema": self.request_schema, } }, } operation_spec["x-codeSamples"] = code_samples( self, header_params=header_params, path_params=path_params, query_params=query_params, ) # If we don't have any parameters we remove the empty list, so the spec will not have it. if not operation_spec["parameters"]: del operation_spec["parameters"] try: docstring_name = _docstring_name(self.func.__doc__) except ValueError as exc: raise ValueError( f"Function {module_obj.__name__}:{self.func.__name__} has no docstring." ) from exc if docstring_name: operation_spec["summary"] = docstring_name else: raise RuntimeError( f"Please put a docstring onto {self.operation_id}") docstring_desc = _docstring_description(self.func.__doc__) if docstring_desc: operation_spec["description"] = docstring_desc if self.permissions_required is not None: # Check that all the names are known to the system. for perm in self.permissions_required.iter_perms(): if perm not in permission_registry: # NOTE: # See rest_api.py. dynamic_permission() have to be loaded before request # for this to work reliably. raise RuntimeError( f'Permission "{perm}" is not registered in the permission_registry.' ) # Write permission documentation in openapi spec. if description := _permission_descriptions( self.permissions_required, self.permissions_description): operation_spec.setdefault("description", "") if not operation_spec["description"]: operation_spec["description"] += "\n\n" operation_spec["description"] += description
def to_operation_dict(self) -> OperationSpecType: """Generate the openapi spec part of this endpoint. The result needs to be added to the `apispec` instance manually. """ assert self.func is not None, "This object must be used in a decorator environment." assert self.operation_id is not None, "This object must be used in a decorator environment." module_obj = import_string(self.func.__module__) response_headers: Dict[str, OpenAPIParameter] = {} content_type_header = to_openapi([CONTENT_TYPE], "header")[0] del content_type_header["in"] response_headers[content_type_header.pop("name")] = content_type_header if self.etag in ("output", "both"): etag_header = to_openapi([ETAG_HEADER_PARAM], "header")[0] del etag_header["in"] response_headers[etag_header.pop("name")] = etag_header responses: ResponseType = {} if self.tag_group == "Setup": responses["403"] = self._path_item( 403, "Configuration via WATO is disabled") if 404 in self._expected_status_codes: responses["404"] = self._path_item( 404, "The requested object has not been found.") if 422 in self._expected_status_codes: responses["422"] = self._path_item( 422, "The request could not be processed.") if 405 in self._expected_status_codes: responses["405"] = _path_item( 405, "Method not allowed: This request is only allowed " "with other HTTP methods") if 409 in self._expected_status_codes: responses["409"] = self._path_item( 409, "The request is in conflict with the stored resource.", ) if 415 in self._expected_status_codes: responses["415"] = self._path_item( 415, "The submitted content-type is not supported.") if 302 in self._expected_status_codes: responses["302"] = self._path_item( 302, "Either the resource has moved or has not yet completed. Please see this " "resource for further information.", ) if 400 in self._expected_status_codes: responses["400"] = self._path_item( 400, "Parameter or validation failure.") # We don't(!) support any endpoint without an output schema. # Just define one! if 200 in self._expected_status_codes: if self.response_schema: content: ContentObject content = {self.content_type: {"schema": self.response_schema}} elif self.content_type == "application/octet-stream" or self.content_type.startswith( "image/"): content = { self.content_type: { "schema": { "type": "string", "format": "binary", } } } else: raise ValueError( f"Unknown content-type: {self.content_type} Please add condition." ) responses["200"] = self._path_item( 200, "The operation was done successfully.", content=content, headers=response_headers, ) if 204 in self._expected_status_codes: responses["204"] = self._path_item( 204, "Operation done successfully. No further output.") if 412 in self._expected_status_codes: responses["412"] = self._path_item( 412, "The value of the If-Match header doesn't match the object's ETag.", ) if 428 in self._expected_status_codes: responses["428"] = self._path_item( 428, "The required If-Match header is missing.") docstring_name = _docstring_name(module_obj.__doc__) tag_obj: OpenAPITag = { "name": docstring_name, "x-displayName": docstring_name, } docstring_desc = _docstring_description(module_obj.__doc__) if docstring_desc: tag_obj["description"] = docstring_desc _add_tag(tag_obj, tag_group=self.tag_group) operation_spec: OperationSpecType = { "operationId": self.operation_id, "tags": [docstring_name], "description": "", } header_params: List[RawParameter] = [] query_params: Sequence[RawParameter] = ( self.query_params if self.query_params is not None else []) path_params: Sequence[RawParameter] = ( self.path_params if self.path_params is not None else []) if config.rest_api_etag_locking and self.etag in ("input", "both"): header_params.append(ETAG_IF_MATCH_HEADER) if self.request_schema: header_params.append(CONTENT_TYPE) # While we define the parameters separately to be able to use them for validation, the # OpenAPI spec expects them to be listed in on place, so here we bunch them together. operation_spec["parameters"] = coalesce_schemas([ ("header", header_params), ("query", query_params), ("path", path_params), ]) operation_spec["responses"] = responses if self.request_schema is not None: operation_spec["requestBody"] = { "required": True, "content": { "application/json": { "schema": self.request_schema, } }, } operation_spec["x-codeSamples"] = code_samples( self, header_params=header_params, path_params=path_params, query_params=query_params, ) # If we don't have any parameters we remove the empty list, so the spec will not have it. if not operation_spec["parameters"]: del operation_spec["parameters"] docstring_name = _docstring_name(self.func.__doc__) if docstring_name: operation_spec["summary"] = docstring_name else: raise RuntimeError( f"Please put a docstring onto {self.operation_id}") docstring_desc = _docstring_description(self.func.__doc__) if docstring_desc: operation_spec["description"] = docstring_desc apispec.utils.deepupdate(operation_spec, self.options) return {self.method: operation_spec} # type: ignore[misc]
def to_operation_dict(self) -> OperationSpecType: """Generate the openapi spec part of this endpoint. The result needs to be added to the `apispec` instance manually. """ assert self.func is not None, "This object must be used in a decorator environment." assert self.operation_id is not None, "This object must be used in a decorator environment." module_obj = import_string(self.func.__module__) module_name = module_obj.__name__ headers: Dict[str, OpenAPIParameter] = {} if self.etag in ('output', 'both'): etag_header = to_openapi([ETAG_HEADER_PARAM], 'header')[0] del etag_header['in'] headers[etag_header.pop('name')] = etag_header responses: ResponseType = {} # We don't(!) support any endpoint without an output schema. # Just define one! if self.response_schema is not None: responses['200'] = { 'content': { self.content_type: { 'schema': self.response_schema }, }, 'description': apispec.utils.dedent(self.response_schema.__doc__ or ''), 'headers': headers, } if self.will_do_redirects: responses['302'] = { 'description': ('Either the resource has moved or has not yet completed. Please see this ' 'resource for further information.') } # Actually, iff you don't want to give out anything, then we don't need a schema. if self.output_empty: responses['204'] = { 'description': 'Operation done successfully. No further output.', 'headers': headers, } tag_obj: OpenAPITag = { 'name': module_name, } docstring_name = _docstring_name(module_obj.__doc__) if docstring_name: tag_obj['x-displayName'] = docstring_name docstring_desc = _docstring_description(module_obj.__doc__) if docstring_desc: tag_obj['description'] = docstring_desc _add_tag(tag_obj, tag_group=self.tag_group) operation_spec: OperationSpecType = { 'operationId': self.operation_id, 'tags': [module_name], 'description': '', 'responses': { 'default': { 'description': 'Any unsuccessful or unexpected result.', 'content': { 'application/problem+json': { 'schema': self.error_schema, } } } }, } header_params: List[RawParameter] = [] query_params: Sequence[ RawParameter] = self.query_params if self.query_params is not None else [] path_params: Sequence[ RawParameter] = self.path_params if self.path_params is not None else [] if self.etag in ('input', 'both'): header_params.append(ETAG_IF_MATCH_HEADER) operation_spec['parameters'] = coalesce_schemas([ ('header', header_params), ('query', query_params), ('path', path_params), ]) operation_spec['responses'].update(responses) if self.request_schema is not None: operation_spec['requestBody'] = { 'required': self.request_body_required, 'content': { 'application/json': { 'schema': self.request_schema, } } } operation_spec['x-codeSamples'] = code_samples(self) # If we don't have any parameters we remove the empty list, so the spec will not have it. if not operation_spec['parameters']: del operation_spec['parameters'] docstring_name = _docstring_name(self.func.__doc__) if docstring_name: operation_spec['summary'] = docstring_name else: raise RuntimeError(f"Please put a docstring onto {self.operation_id}") docstring_desc = _docstring_description(self.func.__doc__) if docstring_desc: operation_spec['description'] = docstring_desc apispec.utils.deepupdate(operation_spec, self.options) return {self.method: operation_spec} # type: ignore[misc]
def _add_api_spec(func): module_obj = import_string(func.__module__) module_name = module_obj.__name__ operation_id = func.__module__ + "." + func.__name__ if not output_empty and response_schema is None: raise ValueError( "%s: 'response_schema' required when output is to be sent!" % operation_id) if output_empty and response_schema: raise ValueError( "%s: On empty output 'output_schema' may not be used." % operation_id) # We don't(!) support any endpoint without an output schema. # Just define one! if response_schema is not None: path_item = { '200': { 'content': { content_type: { 'schema': response_schema }, }, 'description': apispec.utils.dedent(response_schema.__doc__ or ''), } } # Actually, iff you don't want to give out anything, then we don't need a schema. if output_empty: path_item = { '204': { 'description': 'Operation done successfully. No further output.' } } tag_obj = {'name': module_name} tag_obj.update( _docstring_keys(module_obj.__doc__, 'x-displayName', 'description')) _add_tag(tag_obj, tag_group='Endpoints') operation_spec = { 'operationId': operation_id, 'tags': [module_name], 'description': '', 'responses': { 'default': { 'description': 'Any unsuccessful or unexpected result.', 'content': { 'application/problem+json': { 'schema': error_schema, } } } }, 'parameters': [], } if param_names: operation_spec['parameters'].extend(parameters) if etag in ('input', 'both'): operation_spec['parameters'].append(ETAG_IF_MATCH_HEADER) if etag in ('output', 'both'): # We can't put this completely in a schema because 'headers' is a map. We therefore # have to duplicate it every time. # NOTE: Be aware that this block only works under the assumption that only one(!) # http_status defined `operation_spec`. If this assumption no longer holds this block # needs to be refactored. only_key = list(path_item.keys())[0] path_item[only_key].setdefault('headers', {}) path_item[only_key]['headers'].update(ETAG_HEADER_PARAM) operation_spec['responses'].update(path_item) if request_schema is not None: tag = _tag_from_schema(request_schema) _add_tag(tag, tag_group='Request Schemas') operation_spec['requestBody'] = { 'required': request_body_required, 'content': { 'application/json': { 'schema': request_schema, } } } operation_spec['x-code-samples'] = code_samples( path, method, request_schema) # If we don't have any parameters we remove the empty list, so the spec will not have it. if not operation_spec['parameters']: del operation_spec['parameters'] operation_spec.update( _docstring_keys(func.__doc__, 'summary', 'description')) apispec.utils.deepupdate(operation_spec, options) add_operation(path, method, operation_spec) if response_schema is None and request_schema is None: return func return wrap_with_validation(func, request_schema, response_schema)
def _add_api_spec(func): module_obj = import_string(func.__module__) module_name = module_obj.__name__ operation_id = func.__module__ + "." + func.__name__ ENDPOINT_REGISTRY.add_endpoint( module_name, name, method, path, find_all_parameters(primitive_parameters), ) if not output_empty and response_schema is None: raise ValueError(f"{operation_id}: 'response_schema' required when " f"output will be sent!") if output_empty and response_schema: raise ValueError(f"{operation_id}: On empty output 'output_schema' may not be used.") headers: Dict[str, PrimitiveParameter] = {} if etag in ('output', 'both'): headers.update(ETAG_HEADER_PARAM.header_dict()) responses: ResponseType = {} # We don't(!) support any endpoint without an output schema. # Just define one! if response_schema is not None: responses['200'] = { 'content': { content_type: { 'schema': response_schema }, }, 'description': apispec.utils.dedent(response_schema.__doc__ or ''), 'headers': headers, } if will_do_redirects: responses['302'] = { 'description': ('Either the resource has moved or has not yet completed. Please see this ' 'resource for further information.') } # Actually, iff you don't want to give out anything, then we don't need a schema. if output_empty: responses['204'] = { 'description': 'Operation done successfully. No further output.', 'headers': headers, } tag_obj: OpenAPITag = { 'name': module_name, } docstring_name = _docstring_name(module_obj.__doc__) if docstring_name: tag_obj['x-displayName'] = docstring_name docstring_desc = _docstring_description(module_obj.__doc__) if docstring_desc: tag_obj['description'] = docstring_desc _add_tag(tag_obj, tag_group='Endpoints') operation_spec: OperationSpecType = { 'operationId': operation_id, 'tags': [module_name], 'description': '', 'responses': { 'default': { 'description': 'Any unsuccessful or unexpected result.', 'content': { 'application/problem+json': { 'schema': error_schema, } } } }, 'parameters': primitive_parameters, } if etag in ('input', 'both'): operation_spec['parameters'].append(ETAG_IF_MATCH_HEADER.to_dict()) operation_spec['responses'].update(responses) if request_schema is not None: tag = _tag_from_schema(request_schema) _add_tag(tag, tag_group='Request Schemas') operation_spec['requestBody'] = { 'required': request_body_required, 'content': { 'application/json': { 'schema': request_schema, } } } operation_spec['x-codeSamples'] = code_samples(path, method, request_schema, operation_spec) # If we don't have any parameters we remove the empty list, so the spec will not have it. if not operation_spec['parameters']: del operation_spec['parameters'] docstring_name = _docstring_name(func.__doc__) if docstring_name: operation_spec['summary'] = docstring_name docstring_desc = _docstring_description(func.__doc__) if docstring_desc: operation_spec['description'] = docstring_desc apispec.utils.deepupdate(operation_spec, options) if func not in _SEEN_ENDPOINTS: # NOTE: # Only add the endpoint to the spec if not already done. We don't want # to add it multiple times. While this shouldn't be happening, doctest # sometimes complains that it would be happening. Not sure why. Anyways, # it's not a big deal as long as the SPEC is written correctly. SPEC.path(path=path, operations={method.lower(): operation_spec}) _SEEN_ENDPOINTS.add(func) return wrap_with_validation(func, request_schema, response_schema)
def to_operation_dict(self) -> OperationSpecType: """Generate the openapi spec part of this endpoint. The result needs to be added to the `apispec` instance manually. """ assert self.func is not None, "This object must be used in a decorator environment." assert self.operation_id is not None, "This object must be used in a decorator environment." module_obj = import_string(self.func.__module__) module_name = module_obj.__name__ headers: Dict[str, PrimitiveParameter] = {} if self.etag in ('output', 'both'): headers.update(ETAG_HEADER_PARAM.header_dict()) responses: ResponseType = {} # We don't(!) support any endpoint without an output schema. # Just define one! if self.response_schema is not None: responses['200'] = { 'content': { self.content_type: { 'schema': self.response_schema }, }, 'description': apispec.utils.dedent(self.response_schema.__doc__ or ''), 'headers': headers, } if self.will_do_redirects: responses['302'] = { 'description': ('Either the resource has moved or has not yet completed. Please see this ' 'resource for further information.') } # Actually, iff you don't want to give out anything, then we don't need a schema. if self.output_empty: responses['204'] = { 'description': 'Operation done successfully. No further output.', 'headers': headers, } tag_obj: OpenAPITag = { 'name': module_name, } docstring_name = _docstring_name(module_obj.__doc__) if docstring_name: tag_obj['x-displayName'] = docstring_name docstring_desc = _docstring_description(module_obj.__doc__) if docstring_desc: tag_obj['description'] = docstring_desc _add_tag(tag_obj, tag_group='Endpoints') operation_spec: OperationSpecType = { 'operationId': self.operation_id, 'tags': [module_name], 'description': '', 'responses': { 'default': { 'description': 'Any unsuccessful or unexpected result.', 'content': { 'application/problem+json': { 'schema': self.error_schema, } } } }, 'parameters': _reduce_to_primitives(self.parameters), } if self.etag in ('input', 'both'): operation_spec['parameters'].append(ETAG_IF_MATCH_HEADER.to_dict()) operation_spec['responses'].update(responses) if self.request_schema is not None: tag = _tag_from_schema(self.request_schema) _add_tag(tag, tag_group='Request Schemas') operation_spec['requestBody'] = { 'required': self.request_body_required, 'content': { 'application/json': { 'schema': self.request_schema, } } } operation_spec['x-codeSamples'] = code_samples( self.path, self.method, self.request_schema, operation_spec, ) # If we don't have any parameters we remove the empty list, so the spec will not have it. if not operation_spec['parameters']: del operation_spec['parameters'] docstring_name = _docstring_name(self.func.__doc__) if docstring_name: operation_spec['summary'] = docstring_name docstring_desc = _docstring_description(self.func.__doc__) if docstring_desc: operation_spec['description'] = docstring_desc apispec.utils.deepupdate(operation_spec, self.options) return operation_spec