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 #118
openapi3 1.7.4
Cristi Vîjdea 2018-05-14 19:15:14 +03:00 committed by GitHub
parent 3077195396
commit aca0c4713e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 68 additions and 16 deletions

View File

@ -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**

View File

@ -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 = [] #:

View File

@ -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())

View File

@ -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(
manual_parameters=[
openapi.Parameter( openapi.Parameter(
name='id', in_=openapi.IN_PATH, name='id', in_=openapi.IN_PATH,
type=openapi.TYPE_INTEGER, type=openapi.TYPE_INTEGER,
description="path parameter override", description="path parameter override",
required=True required=True
), ),
], responses={ openapi.Parameter(
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( status.HTTP_204_NO_CONTENT: openapi.Response(
description="This should not crash" 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)

View File

@ -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: