From e28c6e53753db3e10a2326e56f1c1814db42a492 Mon Sep 17 00:00:00 2001 From: Denis Kirillov Date: Thu, 7 Jul 2022 12:29:51 +0300 Subject: [PATCH] [#15] Use status code 200 with payload on success Signed-off-by: Denis Kirillov --- cmd/neofs-rest-gw/integration_test.go | 12 +++- gen/models/success_response.go | 71 +++++++++++++++++++ gen/restapi/embedded_spec.go | 60 +++++++++++++--- .../operations/delete_container_responses.go | 44 ++++++++---- .../operations/delete_object_responses.go | 44 ++++++++---- .../put_container_e_acl_responses.go | 26 ++++++- handlers/containers.go | 4 +- handlers/objects.go | 2 +- internal/util/transformers.go | 12 ++++ spec/rest.yaml | 21 ++++-- 10 files changed, 249 insertions(+), 47 deletions(-) create mode 100644 gen/models/success_response.go diff --git a/cmd/neofs-rest-gw/integration_test.go b/cmd/neofs-rest-gw/integration_test.go index 665db4d..05ef6b0 100644 --- a/cmd/neofs-rest-gw/integration_test.go +++ b/cmd/neofs-rest-gw/integration_test.go @@ -464,7 +464,9 @@ func restObjectDelete(ctx context.Context, t *testing.T, p *pool.Pool, cnrID *ci require.NoError(t, err) prepareCommonHeaders(request.Header, bearerToken) - doRequest(t, httpClient, request, http.StatusNoContent, nil) + resp := &models.SuccessResponse{} + doRequest(t, httpClient, request, http.StatusOK, resp) + require.True(t, *resp.Success) var addr address.Address addr.SetContainerID(cnrID) @@ -605,7 +607,9 @@ func restContainerDelete(ctx context.Context, t *testing.T, clientPool *pool.Poo request = request.WithContext(ctx) prepareCommonHeaders(request.Header, bearerToken) - doRequest(t, httpClient, request, http.StatusNoContent, nil) + resp := &models.SuccessResponse{} + doRequest(t, httpClient, request, http.StatusOK, resp) + require.True(t, *resp.Success) var prm pool.PrmContainerGet prm.SetContainerID(*cnrID) @@ -649,7 +653,9 @@ func restContainerEACLPut(ctx context.Context, t *testing.T, clientPool *pool.Po request = request.WithContext(ctx) prepareCommonHeaders(request.Header, bearerToken) - doRequest(t, httpClient, request, http.StatusOK, nil) + resp := &models.SuccessResponse{} + doRequest(t, httpClient, request, http.StatusOK, resp) + require.True(t, *resp.Success) var prm pool.PrmContainerEACL prm.SetContainerID(*cnrID) diff --git a/gen/models/success_response.go b/gen/models/success_response.go new file mode 100644 index 0000000..de2d1f9 --- /dev/null +++ b/gen/models/success_response.go @@ -0,0 +1,71 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// SuccessResponse success response +// +// swagger:model SuccessResponse +type SuccessResponse struct { + + // success + // Required: true + Success *bool `json:"success"` +} + +// Validate validates this success response +func (m *SuccessResponse) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateSuccess(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *SuccessResponse) validateSuccess(formats strfmt.Registry) error { + + if err := validate.Required("success", "body", m.Success); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this success response based on context it is used +func (m *SuccessResponse) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *SuccessResponse) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *SuccessResponse) UnmarshalBinary(b []byte) error { + var res SuccessResponse + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/gen/restapi/embedded_spec.go b/gen/restapi/embedded_spec.go index c713a56..0ac4a4d 100644 --- a/gen/restapi/embedded_spec.go +++ b/gen/restapi/embedded_spec.go @@ -241,8 +241,11 @@ func init() { } ], "responses": { - "204": { - "description": "Successul deletion" + "200": { + "description": "Successful deletion", + "schema": { + "$ref": "#/definitions/SuccessResponse" + } }, "400": { "description": "Bad request", @@ -303,7 +306,10 @@ func init() { ], "responses": { "200": { - "description": "Successfule EACL upading" + "description": "Successful EACL updating", + "schema": { + "$ref": "#/definitions/SuccessResponse" + } }, "400": { "description": "Bad request", @@ -472,8 +478,11 @@ func init() { "summary": "Remove object from NeoFS", "operationId": "deleteObject", "responses": { - "204": { - "description": "Successful deletion" + "200": { + "description": "Successful deletion", + "schema": { + "$ref": "#/definitions/SuccessResponse" + } }, "400": { "description": "Bad request", @@ -950,6 +959,17 @@ func init() { "MatchCommonPrefix" ] }, + "SuccessResponse": { + "type": "object", + "required": [ + "success" + ], + "properties": { + "success": { + "type": "boolean" + } + } + }, "Target": { "type": "object", "required": [ @@ -1318,8 +1338,11 @@ func init() { } ], "responses": { - "204": { - "description": "Successul deletion" + "200": { + "description": "Successful deletion", + "schema": { + "$ref": "#/definitions/SuccessResponse" + } }, "400": { "description": "Bad request", @@ -1396,7 +1419,10 @@ func init() { ], "responses": { "200": { - "description": "Successfule EACL upading" + "description": "Successful EACL updating", + "schema": { + "$ref": "#/definitions/SuccessResponse" + } }, "400": { "description": "Bad request", @@ -1600,8 +1626,11 @@ func init() { "summary": "Remove object from NeoFS", "operationId": "deleteObject", "responses": { - "204": { - "description": "Successful deletion" + "200": { + "description": "Successful deletion", + "schema": { + "$ref": "#/definitions/SuccessResponse" + } }, "400": { "description": "Bad request", @@ -2098,6 +2127,17 @@ func init() { "MatchCommonPrefix" ] }, + "SuccessResponse": { + "type": "object", + "required": [ + "success" + ], + "properties": { + "success": { + "type": "boolean" + } + } + }, "Target": { "type": "object", "required": [ diff --git a/gen/restapi/operations/delete_container_responses.go b/gen/restapi/operations/delete_container_responses.go index 08ecd32..01cbd85 100644 --- a/gen/restapi/operations/delete_container_responses.go +++ b/gen/restapi/operations/delete_container_responses.go @@ -13,28 +13,48 @@ import ( "github.com/nspcc-dev/neofs-rest-gw/gen/models" ) -// DeleteContainerNoContentCode is the HTTP code returned for type DeleteContainerNoContent -const DeleteContainerNoContentCode int = 204 +// DeleteContainerOKCode is the HTTP code returned for type DeleteContainerOK +const DeleteContainerOKCode int = 200 -/*DeleteContainerNoContent Successul deletion +/*DeleteContainerOK Successful deletion -swagger:response deleteContainerNoContent +swagger:response deleteContainerOK */ -type DeleteContainerNoContent struct { +type DeleteContainerOK struct { + + /* + In: Body + */ + Payload *models.SuccessResponse `json:"body,omitempty"` } -// NewDeleteContainerNoContent creates DeleteContainerNoContent with default headers values -func NewDeleteContainerNoContent() *DeleteContainerNoContent { +// NewDeleteContainerOK creates DeleteContainerOK with default headers values +func NewDeleteContainerOK() *DeleteContainerOK { - return &DeleteContainerNoContent{} + return &DeleteContainerOK{} +} + +// WithPayload adds the payload to the delete container o k response +func (o *DeleteContainerOK) WithPayload(payload *models.SuccessResponse) *DeleteContainerOK { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the delete container o k response +func (o *DeleteContainerOK) SetPayload(payload *models.SuccessResponse) { + o.Payload = payload } // WriteResponse to the client -func (o *DeleteContainerNoContent) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { +func (o *DeleteContainerOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { - rw.Header().Del(runtime.HeaderContentType) //Remove Content-Type on empty responses - - rw.WriteHeader(204) + rw.WriteHeader(200) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } } // DeleteContainerBadRequestCode is the HTTP code returned for type DeleteContainerBadRequest diff --git a/gen/restapi/operations/delete_object_responses.go b/gen/restapi/operations/delete_object_responses.go index ac6e64c..fc4c292 100644 --- a/gen/restapi/operations/delete_object_responses.go +++ b/gen/restapi/operations/delete_object_responses.go @@ -13,28 +13,48 @@ import ( "github.com/nspcc-dev/neofs-rest-gw/gen/models" ) -// DeleteObjectNoContentCode is the HTTP code returned for type DeleteObjectNoContent -const DeleteObjectNoContentCode int = 204 +// DeleteObjectOKCode is the HTTP code returned for type DeleteObjectOK +const DeleteObjectOKCode int = 200 -/*DeleteObjectNoContent Successful deletion +/*DeleteObjectOK Successful deletion -swagger:response deleteObjectNoContent +swagger:response deleteObjectOK */ -type DeleteObjectNoContent struct { +type DeleteObjectOK struct { + + /* + In: Body + */ + Payload *models.SuccessResponse `json:"body,omitempty"` } -// NewDeleteObjectNoContent creates DeleteObjectNoContent with default headers values -func NewDeleteObjectNoContent() *DeleteObjectNoContent { +// NewDeleteObjectOK creates DeleteObjectOK with default headers values +func NewDeleteObjectOK() *DeleteObjectOK { - return &DeleteObjectNoContent{} + return &DeleteObjectOK{} +} + +// WithPayload adds the payload to the delete object o k response +func (o *DeleteObjectOK) WithPayload(payload *models.SuccessResponse) *DeleteObjectOK { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the delete object o k response +func (o *DeleteObjectOK) SetPayload(payload *models.SuccessResponse) { + o.Payload = payload } // WriteResponse to the client -func (o *DeleteObjectNoContent) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { +func (o *DeleteObjectOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { - rw.Header().Del(runtime.HeaderContentType) //Remove Content-Type on empty responses - - rw.WriteHeader(204) + rw.WriteHeader(200) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } } // DeleteObjectBadRequestCode is the HTTP code returned for type DeleteObjectBadRequest diff --git a/gen/restapi/operations/put_container_e_acl_responses.go b/gen/restapi/operations/put_container_e_acl_responses.go index 7c9942d..137d618 100644 --- a/gen/restapi/operations/put_container_e_acl_responses.go +++ b/gen/restapi/operations/put_container_e_acl_responses.go @@ -16,11 +16,16 @@ import ( // PutContainerEACLOKCode is the HTTP code returned for type PutContainerEACLOK const PutContainerEACLOKCode int = 200 -/*PutContainerEACLOK Successfule EACL upading +/*PutContainerEACLOK Successful EACL updating swagger:response putContainerEAclOK */ type PutContainerEACLOK struct { + + /* + In: Body + */ + Payload *models.SuccessResponse `json:"body,omitempty"` } // NewPutContainerEACLOK creates PutContainerEACLOK with default headers values @@ -29,12 +34,27 @@ func NewPutContainerEACLOK() *PutContainerEACLOK { return &PutContainerEACLOK{} } +// WithPayload adds the payload to the put container e Acl o k response +func (o *PutContainerEACLOK) WithPayload(payload *models.SuccessResponse) *PutContainerEACLOK { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the put container e Acl o k response +func (o *PutContainerEACLOK) SetPayload(payload *models.SuccessResponse) { + o.Payload = payload +} + // WriteResponse to the client func (o *PutContainerEACLOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { - rw.Header().Del(runtime.HeaderContentType) //Remove Content-Type on empty responses - rw.WriteHeader(200) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } } // PutContainerEACLBadRequestCode is the HTTP code returned for type PutContainerEACLBadRequest diff --git a/handlers/containers.go b/handlers/containers.go index ad8fa50..3e87e08 100644 --- a/handlers/containers.go +++ b/handlers/containers.go @@ -109,7 +109,7 @@ func (a *API) PutContainerEACL(params operations.PutContainerEACLParams, princip return operations.NewPutContainerEACLBadRequest().WithPayload(util.NewError(err)) } - return operations.NewPutContainerEACLOK() + return operations.NewPutContainerEACLOK().WithPayload(util.NewSuccessResponse()) } // GetContainerEACL handler that returns container eacl. @@ -208,7 +208,7 @@ func (a *API) DeleteContainer(params operations.DeleteContainerParams, principal return operations.NewDeleteContainerBadRequest().WithPayload(util.NewError(err)) } - return operations.NewDeleteContainerNoContent() + return operations.NewDeleteContainerOK().WithPayload(util.NewSuccessResponse()) } func getContainerBaseInfo(ctx context.Context, p *pool.Pool, cnrID cid.ID) (*models.ContainerBaseInfo, error) { diff --git a/handlers/objects.go b/handlers/objects.go index 24249db..ec54232 100644 --- a/handlers/objects.go +++ b/handlers/objects.go @@ -199,7 +199,7 @@ func (a *API) DeleteObject(params operations.DeleteObjectParams, principal *mode return errorResponse.WithPayload(util.NewError(err)) } - return operations.NewDeleteObjectNoContent() + return operations.NewDeleteObjectOK().WithPayload(util.NewSuccessResponse()) } // SearchObjects handler that removes object from NeoFS. diff --git a/internal/util/transformers.go b/internal/util/transformers.go index 8258dd8..600c6f3 100644 --- a/internal/util/transformers.go +++ b/internal/util/transformers.go @@ -440,7 +440,19 @@ func NewInteger(val int64) *int64 { return &val } +// NewBool returns pointer to provided bool. +func NewBool(val bool) *bool { + return &val +} + // NewError wraps error into models.Error. func NewError(err error) models.Error { return models.Error(err.Error()) } + +// NewSuccessResponse forms model.SuccessResponse. +func NewSuccessResponse() *models.SuccessResponse { + return &models.SuccessResponse{ + Success: NewBool(true), + } +} diff --git a/spec/rest.yaml b/spec/rest.yaml index 541a945..cfa011e 100644 --- a/spec/rest.yaml +++ b/spec/rest.yaml @@ -202,8 +202,10 @@ paths: operationId: deleteObject summary: Remove object from NeoFS responses: - 204: + 200: description: Successful deletion + schema: + $ref: '#/definitions/SuccessResponse' 400: description: Bad request schema: @@ -312,8 +314,10 @@ paths: - $ref: '#/parameters/signatureKeyParam' - $ref: '#/parameters/signatureScheme' responses: - 204: - description: Successul deletion + 200: + description: Successful deletion + schema: + $ref: '#/definitions/SuccessResponse' 400: description: Bad request schema: @@ -336,7 +340,9 @@ paths: $ref: '#/definitions/Eacl' responses: 200: - description: Successfule EACL upading + description: Successful EACL updating + schema: + $ref: '#/definitions/SuccessResponse' 400: description: Bad request schema: @@ -706,3 +712,10 @@ definitions: type: string Error: type: string + SuccessResponse: + type: object + properties: + success: + type: boolean + required: + - success