Allow body on HTTP DELETE view methods (#122)
* Allow body in delete requests * Do not add request body to DELETE by default * Check manual form parameters against body_methods * Add tests * Add changelog Closes #118openapi3 1.7.4
parent
3077195396
commit
aca0c4713e
|
|
@ -12,6 +12,7 @@ Changelog
|
||||||
- **IMPROVED:** updated ``swagger-ui`` to version 3.14.2
|
- **IMPROVED:** updated ``swagger-ui`` to version 3.14.2
|
||||||
- **IMPROVED:** updated ``ReDoc`` to version 2.0.0-alpha.20
|
- **IMPROVED:** updated ``ReDoc`` to version 2.0.0-alpha.20
|
||||||
- **FIXED:** ignore ``None`` return from ``get_operation`` to avoid empty ``Path`` objects in output
|
- **FIXED:** ignore ``None`` return from ``get_operation`` to avoid empty ``Path`` objects in output
|
||||||
|
- **FIXED:** request body is now allowed on ``DELETE`` endpoints (:issue:`118`)
|
||||||
|
|
||||||
*********
|
*********
|
||||||
**1.7.3**
|
**1.7.3**
|
||||||
|
|
|
||||||
|
|
@ -276,7 +276,10 @@ class SerializerInspector(FieldInspector):
|
||||||
|
|
||||||
|
|
||||||
class ViewInspector(BaseInspector):
|
class ViewInspector(BaseInspector):
|
||||||
body_methods = ('PUT', 'PATCH', 'POST') #: methods that are allowed to have a request body
|
body_methods = ('PUT', 'PATCH', 'POST', 'DELETE') #: methods that are allowed to have a request body
|
||||||
|
|
||||||
|
#: methods that are assumed to require a request body determined by the view's ``serializer_class``
|
||||||
|
implicit_body_methods = ('PUT', 'PATCH', 'POST')
|
||||||
|
|
||||||
# real values set in __init__ to prevent import errors
|
# real values set in __init__ to prevent import errors
|
||||||
field_inspectors = [] #:
|
field_inspectors = [] #:
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@ class SwaggerAutoSchema(ViewInspector):
|
||||||
if isinstance(body_override, openapi.Schema.OR_REF):
|
if isinstance(body_override, openapi.Schema.OR_REF):
|
||||||
return body_override
|
return body_override
|
||||||
return force_serializer_instance(body_override)
|
return force_serializer_instance(body_override)
|
||||||
elif self.method in self.body_methods:
|
elif self.method in self.implicit_body_methods:
|
||||||
return self.get_view_serializer()
|
return self.get_view_serializer()
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
@ -144,8 +144,11 @@ class SwaggerAutoSchema(ViewInspector):
|
||||||
raise SwaggerGenerationError("specify the body parameter as a Schema or Serializer in request_body")
|
raise SwaggerGenerationError("specify the body parameter as a Schema or Serializer in request_body")
|
||||||
if any(param.in_ == openapi.IN_FORM for param in manual_parameters): # pragma: no cover
|
if any(param.in_ == openapi.IN_FORM for param in manual_parameters): # pragma: no cover
|
||||||
if any(param.in_ == openapi.IN_BODY for param in parameters.values()):
|
if any(param.in_ == openapi.IN_BODY for param in parameters.values()):
|
||||||
raise SwaggerGenerationError("cannot add form parameters when the request has a request schema; "
|
raise SwaggerGenerationError("cannot add form parameters when the request has a request body; "
|
||||||
"did you forget to set an appropriate parser class on the view?")
|
"did you forget to set an appropriate parser class on the view?")
|
||||||
|
if self.method not in self.body_methods:
|
||||||
|
raise SwaggerGenerationError("form parameters can only be applied to (" + ','.join(self.body_methods) +
|
||||||
|
") HTTP methods")
|
||||||
|
|
||||||
parameters.update(param_list_to_odict(manual_parameters))
|
parameters.update(param_list_to_odict(manual_parameters))
|
||||||
return list(parameters.values())
|
return list(parameters.values())
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,21 @@ class SnippetList(generics.ListCreateAPIView):
|
||||||
"""post method docstring"""
|
"""post method docstring"""
|
||||||
return super(SnippetList, self).post(request, *args, **kwargs)
|
return super(SnippetList, self).post(request, *args, **kwargs)
|
||||||
|
|
||||||
|
@swagger_auto_schema(
|
||||||
|
operation_id='snippets_delete_bulk',
|
||||||
|
request_body=openapi.Schema(
|
||||||
|
type=openapi.TYPE_OBJECT,
|
||||||
|
properties={
|
||||||
|
'body': openapi.Schema(
|
||||||
|
type=openapi.TYPE_STRING,
|
||||||
|
description='this should not crash (request body on DELETE method)'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
def delete(self, *args, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
|
class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||||
"""
|
"""
|
||||||
|
|
@ -56,18 +71,26 @@ class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||||
"""patch method docstring"""
|
"""patch method docstring"""
|
||||||
return super(SnippetDetail, self).patch(request, *args, **kwargs)
|
return super(SnippetDetail, self).patch(request, *args, **kwargs)
|
||||||
|
|
||||||
@swagger_auto_schema(manual_parameters=[
|
@swagger_auto_schema(
|
||||||
openapi.Parameter(
|
manual_parameters=[
|
||||||
name='id', in_=openapi.IN_PATH,
|
openapi.Parameter(
|
||||||
type=openapi.TYPE_INTEGER,
|
name='id', in_=openapi.IN_PATH,
|
||||||
description="path parameter override",
|
type=openapi.TYPE_INTEGER,
|
||||||
required=True
|
description="path parameter override",
|
||||||
),
|
required=True
|
||||||
], responses={
|
),
|
||||||
status.HTTP_204_NO_CONTENT: openapi.Response(
|
openapi.Parameter(
|
||||||
description="This should not crash"
|
name='delete_form_param', in_=openapi.IN_FORM,
|
||||||
)
|
type=openapi.TYPE_INTEGER,
|
||||||
})
|
description="this should not crash (form parameter on DELETE method)"
|
||||||
|
),
|
||||||
|
],
|
||||||
|
responses={
|
||||||
|
status.HTTP_204_NO_CONTENT: openapi.Response(
|
||||||
|
description="this should not crash (response object with no schema)"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
def delete(self, request, *args, **kwargs):
|
def delete(self, request, *args, **kwargs):
|
||||||
"""delete method docstring"""
|
"""delete method docstring"""
|
||||||
return super(SnippetDetail, self).patch(request, *args, **kwargs)
|
return super(SnippetDetail, self).patch(request, *args, **kwargs)
|
||||||
|
|
|
||||||
|
|
@ -388,6 +388,24 @@ paths:
|
||||||
$ref: '#/definitions/Snippet'
|
$ref: '#/definitions/Snippet'
|
||||||
tags:
|
tags:
|
||||||
- snippets
|
- snippets
|
||||||
|
delete:
|
||||||
|
operationId: snippetsDeleteBulk
|
||||||
|
description: SnippetList classdoc
|
||||||
|
parameters:
|
||||||
|
- name: data
|
||||||
|
in: body
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
body:
|
||||||
|
description: this should not crash (request body on DELETE method)
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
'204':
|
||||||
|
description: ''
|
||||||
|
tags:
|
||||||
|
- snippets
|
||||||
parameters: []
|
parameters: []
|
||||||
/snippets/{id}/:
|
/snippets/{id}/:
|
||||||
get:
|
get:
|
||||||
|
|
@ -442,9 +460,13 @@ paths:
|
||||||
description: path parameter override
|
description: path parameter override
|
||||||
required: true
|
required: true
|
||||||
type: integer
|
type: integer
|
||||||
|
- name: delete_form_param
|
||||||
|
in: formData
|
||||||
|
description: this should not crash (form parameter on DELETE method)
|
||||||
|
type: integer
|
||||||
responses:
|
responses:
|
||||||
'204':
|
'204':
|
||||||
description: This should not crash
|
description: this should not crash (response object with no schema)
|
||||||
tags:
|
tags:
|
||||||
- snippets
|
- snippets
|
||||||
parameters:
|
parameters:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue