diff --git a/api.yaml b/api.yaml index 9c6ca107..5a526823 100755 --- a/api.yaml +++ b/api.yaml @@ -202,6 +202,32 @@ paths: type: array items: $ref: "#/components/schemas/Blog" + delete: + operationId: Delete Blog + parameters: + - in: query + name: id + schema: + type: string + required: true + description: blog id + requestBody: + description: Blog info that is submitted + required: false + content: + application/json: + schema: + $ref: "#/components/schemas/Blog" + responses: + 200: + description: Update blog + content: + application/json: + schema: + $ref: "#/components/schemas/Blog" + 400: + description: Invalid blog submitted + /blogs/{id}: get: parameters: @@ -280,6 +306,13 @@ paths: type: string required: true description: blog id + requestBody: + description: Blog info that is submitted + required: false + content: + application/json: + schema: + $ref: "#/components/schemas/Blog" summary: Delete blog operationId: Delete Blog responses: diff --git a/controllers/rest/api_test.go b/controllers/rest/api_test.go index f96e75a8..776fd445 100644 --- a/controllers/rest/api_test.go +++ b/controllers/rest/api_test.go @@ -296,3 +296,28 @@ func TestRESTAPI_Initialize_ListAddedToGet(t *testing.T) { } os.Remove("test.db") } + +func TestRESTAPI_Initialize_DeleteAdded(t *testing.T) { + os.Remove("test.db") + e := echo.New() + tapi := api.RESTAPI{} + _, err := api.Initialize(e, &tapi, "./fixtures/blog.yaml") + if err != nil { + t.Fatalf("unexpected error '%s'", err) + } + + found := false + method := "DELETE" + path := "/blogs/:id" + middleware := "Delete" + routes := e.Routes() + for _, route := range routes { + if route.Method == method && route.Path == path && strings.Contains(route.Name, middleware) { + found = true + break + } + } + if !found { + t.Errorf("expected to find delete path") + } +} diff --git a/controllers/rest/controller_standard.go b/controllers/rest/controller_standard.go index 3295e45a..ed53162e 100644 --- a/controllers/rest/controller_standard.go +++ b/controllers/rest/controller_standard.go @@ -433,9 +433,9 @@ func (c *StandardControllers) List(app model.Service, spec *openapi3.Swagger, pa } func (c *StandardControllers) Delete(app model.Service, spec *openapi3.Swagger, path *openapi3.PathItem, operation *openapi3.Operation) echo.HandlerFunc { - return func(context echo.Context) error { + return func(ctxt echo.Context) error { - return nil + return ctxt.JSON(http.StatusOK, "Deleted") } } diff --git a/controllers/rest/fixtures/blog.yaml b/controllers/rest/fixtures/blog.yaml index 0dca1da1..77d23c1d 100644 --- a/controllers/rest/fixtures/blog.yaml +++ b/controllers/rest/fixtures/blog.yaml @@ -303,6 +303,7 @@ paths: type: string required: true description: blog id + x-content-type: Blog summary: Delete blog operationId: Delete Blog responses: @@ -421,6 +422,12 @@ paths: schema: type: string required: true + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/Post" summary: Delete post responses: 200: @@ -519,6 +526,12 @@ paths: schema: type: string required: true + requestBody: + required: false + content: + application/json: + schema: + $ref: "#/components/schemas/Category" summary: Delete category responses: 200: @@ -634,6 +647,12 @@ paths: type: string format: email required: true + requestBody: + required: false + content: + application/json: + schema: + $ref: "#/components/schemas/Author" summary: Delete author responses: 200: diff --git a/controllers/rest/middleware_initialize.go b/controllers/rest/middleware_initialize.go index 2306f90f..1303f297 100644 --- a/controllers/rest/middleware_initialize.go +++ b/controllers/rest/middleware_initialize.go @@ -419,6 +419,84 @@ func AddStandardController(e *echo.Echo, pathData *openapi3.PathItem, method str } } + case "DELETE": + var strContentType string + allParam := true + contentTypeExt := pathData.Delete.ExtensionProps.Extensions[ContentTypeExtension] + + if pathData.Delete.RequestBody == nil && contentTypeExt == nil { + break + } + + var identifiers []string + var contextName string + var identifierExtension interface{} + + if contentTypeExt != nil { + jsonContentType := contentTypeExt.(json.RawMessage) + err := json.Unmarshal(jsonContentType, &strContentType) + if err != nil { + return autoConfigure, nil + } + identifierExtension = swagger.Components.Schemas[strContentType].Value.ExtensionProps.Extensions[IdentifierExtension] + } else { + //check to see if the path can be autoconfigured. If not show a warning to the developer is made aware + for _, value := range pathData.Delete.RequestBody.Value.Content { + if !strings.Contains(value.Schema.Ref, "#/components/schemas/") { + return autoConfigure, nil + } + identifierExtension = swagger.Components.Schemas[strings.Replace(value.Schema.Ref, "#/components/schemas/", "", -1)].Value.ExtensionProps.Extensions[IdentifierExtension] + break + } + } + + if identifierExtension != nil { + bytesId := identifierExtension.(json.RawMessage) + json.Unmarshal(bytesId, &identifiers) + } + //check for identifiers + if identifiers != nil && len(identifiers) > 0 { + for _, identifier := range identifiers { + foundIdentifier := false + //check the parameters for the identifiers + for _, param := range pathData.Delete.Parameters { + cName := param.Value.ExtensionProps.Extensions[ContextNameExtension] + if identifier == param.Value.Name || (cName != nil && identifier == cName.(string)) { + foundIdentifier = true + break + } + } + if !foundIdentifier { + allParam = false + e.Logger.Warnf("unexpected error: a parameter for each part of the identifier must be set") + return autoConfigure, nil + } + } + if allParam { + operationConfig.Handler = "Delete" + autoConfigure = true + break + } + } + //if there is no identifiers then id is the default identifier + for _, param := range pathData.Delete.Parameters { + + if "id" == param.Value.Name { + operationConfig.Handler = "Delete" + autoConfigure = true + break + } + interfaceContext := param.Value.ExtensionProps.Extensions[ContextNameExtension] + if interfaceContext != nil { + bytesContext := interfaceContext.(json.RawMessage) + json.Unmarshal(bytesContext, &contextName) + if "id" == contextName { + operationConfig.Handler = "Delete" + autoConfigure = true + break + } + } + } } return autoConfigure, nil diff --git a/controllers/rest/openapi_extensions.go b/controllers/rest/openapi_extensions.go index 57bb3d60..cb434688 100644 --- a/controllers/rest/openapi_extensions.go +++ b/controllers/rest/openapi_extensions.go @@ -23,3 +23,6 @@ const IdentifierExtension = "x-identifier" //AliasExtension alias parameter name to a different name in the controller const AliasExtension = "x-alias" + +//ContentTypeExtension alias for specifying the content type instead of the request body +const ContentTypeExtension = "x-content-type" diff --git a/end2end_test.go b/end2end_test.go index c4d46881..b8886dd5 100644 --- a/end2end_test.go +++ b/end2end_test.go @@ -822,7 +822,6 @@ func TestBDD(t *testing.T) { Options: &godog.Options{ Format: "pretty", Tags: "~skipped && ~long", - //Tags: "long", }, }.Run() if status != 0 { diff --git a/features/define-delete-endpoint-oas.feature b/features/define-delete-endpoint-oas.feature index 823e7333..f0880ca9 100644 --- a/features/define-delete-endpoint-oas.feature +++ b/features/define-delete-endpoint-oas.feature @@ -1,4 +1,4 @@ -@WEOS-1178 @skipped +@WEOS-1178 Feature: Delete content endpoints As developer you can create an endpoint that should be used to delete content of a specific type. The HTTP method and the @@ -50,14 +50,10 @@ Feature: Delete content endpoints type: array items: $ref: "#/components/schemas/Category" - x-identifier: - - id - - title + x-identifier: + - id + - title """ - And blogs in the api - | id | title | description | - | 1234 | Blog 1 | Some Blog | - | 4567 | Blog 2 | Some Blog 2 | Scenario: Create a basic delete endpoint with the identifier in the path @@ -67,37 +63,38 @@ Feature: Delete content endpoints Given "Sojourner" adds an endpoint to the "OpenAPI 3.0" specification """ - /blogs/{id}: - delete: - operationId: Delete Blog - parameters: - - in: path - name: id - schema: - type: string - required: true - description: blog id - requestBody: - description: Blog info that is submitted - required: false - content: - application/json: + /blogs/{id}: + delete: + operationId: Delete Blog + parameters: + - in: path + name: id schema: - $ref: "#/components/schemas/Blog" - responses: - 200: - description: Update blog + type: string + required: true + description: blog id + requestBody: + description: Blog info that is submitted + required: false content: application/json: schema: $ref: "#/components/schemas/Blog" - 400: - description: Invalid blog submitted + responses: + 200: + description: Update blog + content: + application/json: + schema: + $ref: "#/components/schemas/Blog" + 400: + description: Invalid blog submitted """ When the "OpenAPI 3.0" specification is parsed Then a "DELETE" route should be added to the api And a "Delete" middleware should be added to the route + Scenario: Create a basic delete endpoint with the entity explicitly declared A developer should be able to declare what the entity type is explicitly (as an alternative to using the requestBody @@ -105,26 +102,26 @@ Feature: Delete content endpoints Given "Sojourner" adds an endpoint to the "OpenAPI 3.0" specification """ - /blogs/{id}: - delete: - operationId: Delete Blog - parameters: - - in: path - name: id - schema: - type: string - required: true - description: blog id - x-content-type: Blog - responses: - 200: - description: Update blog - content: - application/json: - schema: - $ref: "#/components/schemas/Blog" - 400: - description: Invalid blog submitted + /blogs/{id}: + delete: + operationId: Delete Blog + parameters: + - in: path + name: id + schema: + type: string + required: true + description: blog id + x-content-type: Blog + responses: + 200: + description: Update blog + content: + application/json: + schema: + $ref: "#/components/schemas/Blog" + 400: + description: Invalid blog submitted """ When the "OpenAPI 3.0" specification is parsed Then a "DELETE" route should be added to the api @@ -134,32 +131,32 @@ Feature: Delete content endpoints Given "Sojourner" adds an endpoint to the "OpenAPI 3.0" specification """ - /blogs: - delete: - operationId: Delete Blog - parameters: - - in: query - name: id - schema: - type: string - required: true - description: blog id - requestBody: - description: Blog info that is submitted - required: false - content: - application/json: + /blogs: + delete: + operationId: Delete Blog + parameters: + - in: query + name: id schema: - $ref: "#/components/schemas/Blog" - responses: - 200: - description: Update blog + type: string + required: true + description: blog id + requestBody: + description: Blog info that is submitted + required: false content: application/json: schema: $ref: "#/components/schemas/Blog" - 400: - description: Invalid blog submitted + responses: + 200: + description: Update blog + content: + application/json: + schema: + $ref: "#/components/schemas/Blog" + 400: + description: Invalid blog submitted """ When the "OpenAPI 3.0" specification is parsed Then a "DELETE" route should be added to the api @@ -169,33 +166,33 @@ Feature: Delete content endpoints Given "Sojourner" adds an endpoint to the "OpenAPI 3.0" specification """ - /blogs: - delete: - operationId: Delete Blog - parameters: - - in: header - name: X-Item-Id - schema: - type: string - required: true - description: blog id - x-context-name: id - requestBody: - description: Blog info to be deleted - required: false - content: - application/json: + /blogs: + delete: + operationId: Delete Blog + parameters: + - in: header + name: X-Item-Id schema: - $ref: "#/components/schemas/Blog" - responses: - 200: - description: Update blog + type: string + required: true + description: blog id + x-context-name: id + requestBody: + description: Blog info to be deleted + required: false content: application/json: schema: $ref: "#/components/schemas/Blog" - 400: - description: Invalid blog submitted + responses: + 200: + description: Update blog + content: + application/json: + schema: + $ref: "#/components/schemas/Blog" + 400: + description: Invalid blog submitted` """ When the "OpenAPI 3.0" specification is parsed Then a "DELETE" route should be added to the api @@ -208,33 +205,33 @@ Feature: Delete content endpoints Given "Sojourner" adds an endpoint to the "OpenAPI 3.0" specification """ - /blogs/{id}: - patch: - operationId: Delete Blog - parameters: - - in: path - name: id - schema: - type: string - required: true - description: blog id - x-controller: Delete - requestBody: - description: Blog info that is submitted - required: false - content: - application/json: + /blogs/{id}: + delete: + operationId: Delete Blog + parameters: + - in: path + name: id schema: - $ref: "#/components/schemas/Blog" - responses: - 200: - description: Update blog - 400: - description: Invalid blog submitted + type: string + required: true + description: blog id + x-controller: Delete + requestBody: + description: Blog info that is submitted + required: false + content: + application/json: + schema: + $ref: "#/components/schemas/Blog" + responses: + 200: + description: Update blog + 400: + description: Invalid blog submitted """ When the "OpenAPI 3.0" specification is parsed - Then a "PATCH" route "/blogs/:id" should be added to the api - And a "edit" middleware should be added to the route + Then a "DELETE" route "/blogs/:id" should be added to the api + And a "Delete" middleware should be added to the route Scenario: Create an endpoint that does not have parameters for all parts of identifier @@ -243,26 +240,26 @@ Feature: Delete content endpoints Given "Sojourner" adds an endpoint to the "OpenAPI 3.0" specification """ - /posts/{id}: - delete: - operationId: Delete Post - parameters: - - in: path - name: id - schema: - type: string - required: true - description: post id - x-content-type: Post - responses: - 201: - description: Add Blog to Aggregator - content: - application/json: - schema: - $ref: "#/components/schemas/Post" - 400: - description: Invalid blog submitted + /posts/{id}: + delete: + operationId: Delete Post + parameters: + - in: path + name: id + schema: + type: string + required: true + description: post id + x-content-type: Post + responses: + 201: + description: Add Blog to Aggregator + content: + application/json: + schema: + $ref: "#/components/schemas/Post" + 400: + description: Invalid blog submitted """ When the "OpenAPI 3.0" specification is parsed Then a warning should be output to logs letting the developer know that a parameter for each part of the idenfier must be set @@ -274,25 +271,25 @@ Feature: Delete content endpoints Given "Sojourner" adds an endpoint to the "OpenAPI 3.0" specification """ - /blogs/{id}: - delete: - operationId: Delete Blog - parameters: - - in: path - name: id - schema: - type: string - required: true - description: blog id - responses: - 201: - description: Add Blog to Aggregator - content: - application/json: - schema: - $ref: "#/components/schemas/Blog" - 400: - description: Invalid blog submitted + /blogs/{id}: + delete: + operationId: Delete Blog + parameters: + - in: path + name: id + schema: + type: string + required: true + description: blog id + responses: + 201: + description: Add Blog to Aggregator + content: + application/json: + schema: + $ref: "#/components/schemas/Blog" + 400: + description: Invalid blog submitted """ When the "OpenAPI 3.0" specification is parsed Then a warning should be output to logs letting the developer know that a handler needs to be set @@ -304,39 +301,39 @@ Feature: Delete content endpoints Given "Sojourner" adds an endpoint to the "OpenAPI 3.0" specification """ - /blogs/{id}: - delete: - operationId: Add Blog - parameters: - - in: path - name: id - schema: - type: string - required: true - description: blog id - requestBody: - description: Blog to add - required: true - content: - application/json: + /blogs/{id}: + delete: + operationId: Add Blog + parameters: + - in: path + name: id schema: - type: object - properties: - id: - type: integer - description: blog id - title: - type: string - description: blog description - responses: - 201: - description: Add Blog to Aggregator + type: string + required: true + description: blog id + requestBody: + description: Blog to add + required: true content: application/json: schema: - $ref: "#/components/schemas/Blog" - 400: - description: Invalid blog submitted + type: object + properties: + id: + type: integer + description: blog id + title: + type: string + description: blog description + responses: + 201: + description: Add Blog to Aggregator + content: + application/json: + schema: + $ref: "#/components/schemas/Blog" + 400: + description: Invalid blog submitted """ When the "OpenAPI 3.0" specification is parsed Then a warning should be output to logs letting the developer know that a handler needs to be set \ No newline at end of file