From: puthuparambil.aditya Date: Wed, 24 Nov 2021 13:35:10 +0000 (+0000) Subject: Adding examples in openapi for cps-core X-Git-Tag: mr/823/126723/7~27^2 X-Git-Url: https://gerrit.onap.org/r/gitweb?p=cps.git;a=commitdiff_plain;h=5d8b24107ad579db89bcdad63476143f4a2db755 Adding examples in openapi for cps-core 1. Added examples for all parameters, request body and response body 2. Changed the response/request type to Object from String for all json objects 3. Passed json format data in all tests 4. PUT and PATCH operations at present return empty response, hence examples are changed to be in sync Issue-ID: CPS-780 Signed-off-by: puthuparambil.aditya Change-Id: If6dd5bb48df4e1bbf1026eaadf315df8f972e282 --- diff --git a/cps-rest/docs/openapi/components.yml b/cps-rest/docs/openapi/components.yml index 3d2eb57e4..ff2816af6 100644 --- a/cps-rest/docs/openapi/components.yml +++ b/cps-rest/docs/openapi/components.yml @@ -25,13 +25,13 @@ components: properties: name: type: string - example: my_anchor + example: my-anchor dataspaceName: type: string - example: my_dataspace + example: my-dataspace schemaSetName: type: string - example: my_schema_set + example: my-schema-set ErrorMessage: type: object @@ -39,13 +39,10 @@ components: properties: status: type: string - example: 400 message: type: string - example: Dataspace not found details: type: string - example: Dataspace with name D1 does not exist. MultipartFile: type: object @@ -56,7 +53,7 @@ components: type: string description: multipartFile format: binary - example: http://example.com/examples/example.yang + example: 'https://github.com/onap/cps/blob/master/cps-service/src/test/resources/bookstore.yang' ModuleReferences: type: object @@ -64,13 +61,13 @@ components: properties: name: type: string - example: module_reference_name + example: my-module-reference-name namespace: type: string - example: module_reference_namespace + example: my-module-reference-namespace revision: type: string - example: module_reference_revision + example: my-module-reference-revision SchemaSetDetails: type: object @@ -78,14 +75,35 @@ components: properties: dataspaceName: type: string - example: my_dataspace + example: my-dataspace moduleReferences: type: array items: $ref: '#/components/schemas/ModuleReferences' name: type: string - example: my_schema_set + example: my-schema-set + + examples: + dataSampleRequest: + value: + test:bookstore: + bookstore-name: Chapters + categories: + - code: 01 + name: SciFi + - code: 02 + name: kids + + dataSampleResponse: + summary: The data node returned does not include the root node. This is being investigated as a part of CPS-461 + value: + bookstore-name: Chapters + categories: + - code: 01 + name: SciFi + - code: 02 + name: kids parameters: dataspaceNameInQuery: @@ -95,6 +113,7 @@ components: required: true schema: type: string + example: my-dataspace dataspaceNameInPath: name: dataspace-name in: path @@ -102,6 +121,7 @@ components: required: true schema: type: string + example: my-dataspace anchorNameInPath: name: anchor-name in: path @@ -109,6 +129,7 @@ components: required: true schema: type: string + example: my-anchor schemaSetNameInQuery: name: schema-set-name in: query @@ -116,6 +137,7 @@ components: required: true schema: type: string + example: my-schema-set schemaSetNameInPath: name: schema-set-name in: path @@ -123,6 +145,7 @@ components: required: true schema: type: string + example: my-schema-set anchorNameInQuery: name: anchor-name in: query @@ -130,29 +153,45 @@ components: required: true schema: type: string + example: my-anchor xpathInQuery: name: xpath in: query - description: xpath + description: For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html required: false schema: type: string default: / + examples: + container xpath: + value: /shops/bookstore + list attributes xpath: + value: /shops/bookstore/categories[@code=1] requiredXpathInQuery: name: xpath in: query - description: xpath + description: For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html required: true schema: type: string + examples: + container xpath: + value: /shops/bookstore + list attributes xpath: + value: /shops/bookstore/categories[@code=1] cpsPathInQuery: name: cps-path in: query - description: cps-path + description: For more details on cps path, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html required: false schema: type: string default: / + examples: + container cps path: + value: //bookstore + list attributes cps path: + value: //categories[@code=1] includeDescendantsOptionInQuery: name: include-descendants in: query @@ -161,6 +200,7 @@ components: schema: type: boolean default: false + example: false observedTimestampInQuery: name: observed-timestamp in: query @@ -177,43 +217,66 @@ components: application/json: schema: $ref: '#/components/schemas/ErrorMessage' + example: + status: 404 + message: Resource Not Found + details: The requested resource is not found Unauthorized: description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ErrorMessage' + example: + status: 401 + message: Unauthorized request + details: This request is unauthorized Forbidden: description: Forbidden content: application/json: schema: $ref: '#/components/schemas/ErrorMessage' + example: + status: 403 + message: Request Forbidden + details: This request is forbidden BadRequest: description: Bad Request content: application/json: schema: $ref: '#/components/schemas/ErrorMessage' + example: + status: 400 + message: Bad Request + details: The provided request is not valid Conflict: description: Conflict content: application/json: schema: $ref: '#/components/schemas/ErrorMessage' + example: + status: 409 + message: Conflicting request + details: The request cannot be processed as the resource is in use. Ok: description: OK content: application/json: schema: type: object - example: { "key": "value" } + examples: + dataSampleResponse: + value: "" Created: description: Created content: text/plain: schema: type: string + example: my-resource NoContent: description: No Content content: {} diff --git a/cps-rest/docs/openapi/cpsData.yml b/cps-rest/docs/openapi/cpsData.yml index 2b65ae440..15f8a1c71 100644 --- a/cps-rest/docs/openapi/cpsData.yml +++ b/cps-rest/docs/openapi/cpsData.yml @@ -35,7 +35,9 @@ nodeByDataspaceAndAnchor: application/json: schema: type: object - example: { "child": my_child,"leafList": "leafListElement1, leafListElement2", "leaf": my_leaf } + examples: + dataSampleResponse: + $ref: 'components.yml#/components/examples/dataSampleResponse' '400': $ref: 'components.yml#/components/responses/BadRequest' '401': @@ -63,7 +65,10 @@ listElementByDataspaceAndAnchor: content: application/json: schema: - type: string + type: object + examples: + dataSampleRequest: + $ref: 'components.yml#/components/examples/dataSampleRequest' responses: '201': $ref: 'components.yml#/components/responses/Created' @@ -90,10 +95,13 @@ listElementByDataspaceAndAnchor: content: application/json: schema: - type: string + type: object + examples: + dataSampleRequest: + $ref: 'components.yml#/components/examples/dataSampleRequest' responses: '200': - $ref: 'components.yml#/components/responses/Created' + $ref: 'components.yml#/components/responses/Ok' '400': $ref: 'components.yml#/components/responses/BadRequest' '401': @@ -140,7 +148,10 @@ nodesByDataspaceAndAnchor: content: application/json: schema: - type: string + type: object + examples: + dataSampleRequest: + $ref: 'components.yml#/components/examples/dataSampleRequest' responses: '201': $ref: 'components.yml#/components/responses/Created' @@ -167,7 +178,10 @@ nodesByDataspaceAndAnchor: content: application/json: schema: - type: string + type: object + examples: + dataSampleRequest: + $ref: 'components.yml#/components/examples/dataSampleRequest' responses: '200': $ref: 'components.yml#/components/responses/Ok' @@ -216,7 +230,10 @@ nodesByDataspaceAndAnchor: content: application/json: schema: - type: string + type: object + examples: + dataSampleRequest: + $ref: 'components.yml#/components/examples/dataSampleRequest' responses: '200': $ref: 'components.yml#/components/responses/Ok' diff --git a/cps-rest/docs/openapi/cpsQuery.yml b/cps-rest/docs/openapi/cpsQuery.yml index f45f3f41a..4f938aa89 100644 --- a/cps-rest/docs/openapi/cpsQuery.yml +++ b/cps-rest/docs/openapi/cpsQuery.yml @@ -30,7 +30,14 @@ nodesByDataspaceAndAnchorAndCpsPath: - $ref: 'components.yml#/components/parameters/includeDescendantsOptionInQuery' responses: '200': - $ref: 'components.yml#/components/responses/Ok' + description: OK + content: + application/json: + schema: + type: object + examples: + dataSampleResponse: + $ref: 'components.yml#/components/examples/dataSampleResponse' '400': $ref: 'components.yml#/components/responses/BadRequest' '401': diff --git a/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java b/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java index e57fb3c8c..73c2c27c9 100755 --- a/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java +++ b/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java @@ -49,11 +49,12 @@ public class DataRestController implements CpsDataApi { @Override public ResponseEntity createNode(final String dataspaceName, final String anchorName, - final String jsonData, final String parentNodeXpath, final String observedTimestamp) { + final Object jsonData, final String parentNodeXpath, final String observedTimestamp) { if (isRootXpath(parentNodeXpath)) { - cpsDataService.saveData(dataspaceName, anchorName, jsonData, toOffsetDateTime(observedTimestamp)); + cpsDataService.saveData(dataspaceName, anchorName, jsonData.toString(), + toOffsetDateTime(observedTimestamp)); } else { - cpsDataService.saveData(dataspaceName, anchorName, parentNodeXpath, jsonData, + cpsDataService.saveData(dataspaceName, anchorName, parentNodeXpath, jsonData.toString(), toOffsetDateTime(observedTimestamp)); } return new ResponseEntity<>(HttpStatus.CREATED); @@ -61,7 +62,7 @@ public class DataRestController implements CpsDataApi { @Override public ResponseEntity deleteDataNode(final String dataspaceName, final String anchorName, - final String xpath, final String observedTimestamp) { + final String xpath, final String observedTimestamp) { cpsDataService.deleteDataNode(dataspaceName, anchorName, xpath, toOffsetDateTime(observedTimestamp)); return new ResponseEntity<>(HttpStatus.NO_CONTENT); @@ -69,8 +70,8 @@ public class DataRestController implements CpsDataApi { @Override public ResponseEntity addListElements(final String parentNodeXpath, - final String dataspaceName, final String anchorName, final String jsonData, final String observedTimestamp) { - cpsDataService.saveListElements(dataspaceName, anchorName, parentNodeXpath, jsonData, + final String dataspaceName, final String anchorName, final Object jsonData, final String observedTimestamp) { + cpsDataService.saveListElements(dataspaceName, anchorName, parentNodeXpath, jsonData.toString(), toOffsetDateTime(observedTimestamp)); return new ResponseEntity<>(HttpStatus.CREATED); } @@ -87,25 +88,26 @@ public class DataRestController implements CpsDataApi { @Override public ResponseEntity updateNodeLeaves(final String dataspaceName, - final String anchorName, final String jsonData, final String parentNodeXpath, final String observedTimestamp) { - cpsDataService.updateNodeLeaves(dataspaceName, anchorName, parentNodeXpath, jsonData, + final String anchorName, final Object jsonData, final String parentNodeXpath, final String observedTimestamp) { + cpsDataService.updateNodeLeaves(dataspaceName, anchorName, parentNodeXpath, jsonData.toString(), toOffsetDateTime(observedTimestamp)); return new ResponseEntity<>(HttpStatus.OK); } @Override public ResponseEntity replaceNode(final String dataspaceName, final String anchorName, - final String jsonData, final String parentNodeXpath, final String observedTimestamp) { + final Object jsonData, final String parentNodeXpath, final String observedTimestamp) { cpsDataService - .replaceNodeTree(dataspaceName, anchorName, parentNodeXpath, jsonData, toOffsetDateTime(observedTimestamp)); + .replaceNodeTree(dataspaceName, anchorName, parentNodeXpath, jsonData.toString(), + toOffsetDateTime(observedTimestamp)); return new ResponseEntity<>(HttpStatus.OK); } @Override - public ResponseEntity replaceListContent(final String parentNodeXpath, - final String dataspaceName, final String anchorName, final String jsonData, + public ResponseEntity replaceListContent(final String parentNodeXpath, + final String dataspaceName, final String anchorName, final Object jsonData, final String observedTimestamp) { - cpsDataService.replaceListContent(dataspaceName, anchorName, parentNodeXpath, jsonData, + cpsDataService.replaceListContent(dataspaceName, anchorName, parentNodeXpath, jsonData.toString(), toOffsetDateTime(observedTimestamp)); return new ResponseEntity<>(HttpStatus.OK); } diff --git a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy index 2c288344c..445b2a2bd 100755 --- a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy +++ b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy @@ -60,6 +60,8 @@ class DataRestControllerSpec extends Specification { def dataspaceName = 'my_dataspace' def anchorName = 'my_anchor' def noTimestamp = null + def jsonString = '{"some-key" : "some-value"}' + def jsonObject @Shared static DataNode dataNodeWithLeavesNoChildren = new DataNodeBuilder().withXpath('/xpath') @@ -71,24 +73,24 @@ class DataRestControllerSpec extends Specification { def setup() { dataNodeBaseEndpoint = "$basePath/v1/dataspaces/$dataspaceName" + jsonObject = groovy.json.JsonOutput.toJson(jsonString); } def 'Create a node: #scenario.'() { - given: 'some json to create a data node' + given: 'endpoint to create a node' def endpoint = "$dataNodeBaseEndpoint/anchors/$anchorName/nodes" - def json = 'some json (this is not validated)' when: 'post is invoked with datanode endpoint and json' def response = mvc.perform( post(endpoint) .contentType(MediaType.APPLICATION_JSON) .param('xpath', parentNodeXpath) - .content(json) + .content(jsonObject) ).andReturn().response then: 'a created response is returned' response.status == HttpStatus.CREATED.value() then: 'the java API was called with the correct parameters' - 1 * mockCpsDataService.saveData(dataspaceName, anchorName, json, noTimestamp) + 1 * mockCpsDataService.saveData(dataspaceName, anchorName, jsonString, noTimestamp) where: 'following xpath parameters are are used' scenario | parentNodeXpath 'no xpath parameter' | '' @@ -96,9 +98,8 @@ class DataRestControllerSpec extends Specification { } def 'Create a node with observed-timestamp'() { - given: 'some json to create a data node' + given: 'endpoint to create a node' def endpoint = "$dataNodeBaseEndpoint/anchors/$anchorName/nodes" - def json = 'some json (this is not validated)' when: 'post is invoked with datanode endpoint and json' def response = mvc.perform( @@ -106,12 +107,12 @@ class DataRestControllerSpec extends Specification { .contentType(MediaType.APPLICATION_JSON) .param('xpath', '') .param('observed-timestamp', observedTimestamp) - .content(json) + .content(jsonObject) ).andReturn().response then: 'a created response is returned' response.status == expectedHttpStatus.value() then: 'the java API was called with the correct parameters' - expectedApiCount * mockCpsDataService.saveData(dataspaceName, anchorName, json, + expectedApiCount * mockCpsDataService.saveData(dataspaceName, anchorName, jsonString, { it == DateTimeUtility.toOffsetDateTime(observedTimestamp) }) where: scenario | observedTimestamp || expectedApiCount | expectedHttpStatus @@ -120,16 +121,15 @@ class DataRestControllerSpec extends Specification { } def 'Create a child node'() { - given: 'some json to create a data node' + given: 'endpoint to create a node' def endpoint = "$dataNodeBaseEndpoint/anchors/$anchorName/nodes" - def json = 'some json (this is not validated)' and: 'parent node xpath' def parentNodeXpath = 'some xpath' when: 'post is invoked with datanode endpoint and json' def postRequestBuilder = post(endpoint) .contentType(MediaType.APPLICATION_JSON) .param('xpath', parentNodeXpath) - .content(json) + .content(jsonObject) if (observedTimestamp != null) postRequestBuilder.param('observed-timestamp', observedTimestamp) def response = @@ -137,7 +137,7 @@ class DataRestControllerSpec extends Specification { then: 'a created response is returned' response.status == HttpStatus.CREATED.value() then: 'the java API was called with the correct parameters' - 1 * mockCpsDataService.saveData(dataspaceName, anchorName, parentNodeXpath, json, + 1 * mockCpsDataService.saveData(dataspaceName, anchorName, parentNodeXpath, jsonString, DateTimeUtility.toOffsetDateTime(observedTimestamp)) where: scenario | observedTimestamp @@ -146,21 +146,20 @@ class DataRestControllerSpec extends Specification { } def 'Save list elements #scenario.'() { - given: 'parent node xpath and json data inputs' + given: 'parent node xpath ' def parentNodeXpath = 'parent node xpath' - def jsonData = 'json data' when: 'list-node endpoint is invoked with post (create) operation' def postRequestBuilder = post("$dataNodeBaseEndpoint/anchors/$anchorName/list-nodes") .contentType(MediaType.APPLICATION_JSON) .param('xpath', parentNodeXpath) - .content(jsonData) + .content(jsonObject) if (observedTimestamp != null) postRequestBuilder.param('observed-timestamp', observedTimestamp) def response = mvc.perform(postRequestBuilder).andReturn().response then: 'a created response is returned' response.status == expectedHttpStatus.value() then: 'the java API was called with the correct parameters' - expectedApiCount * mockCpsDataService.saveListElements(dataspaceName, anchorName, parentNodeXpath, jsonData, + expectedApiCount * mockCpsDataService.saveListElements(dataspaceName, anchorName, parentNodeXpath, jsonString, { it == DateTimeUtility.toOffsetDateTime(observedTimestamp) }) where: scenario | observedTimestamp || expectedApiCount | expectedHttpStatus @@ -210,19 +209,18 @@ class DataRestControllerSpec extends Specification { } def 'Update data node leaves: #scenario.'() { - given: 'json data' - def jsonData = 'json data' + given: 'endpoint to update a node ' def endpoint = "$dataNodeBaseEndpoint/anchors/$anchorName/nodes" when: 'patch request is performed' def response = mvc.perform( patch(endpoint) .contentType(MediaType.APPLICATION_JSON) - .content(jsonData) + .content(jsonObject) .param('xpath', inputXpath) ).andReturn().response then: 'the service method is invoked with expected parameters' - 1 * mockCpsDataService.updateNodeLeaves(dataspaceName, anchorName, xpathServiceParameter, jsonData, null) + 1 * mockCpsDataService.updateNodeLeaves(dataspaceName, anchorName, xpathServiceParameter, jsonString, null) and: 'response status indicates success' response.status == HttpStatus.OK.value() where: @@ -233,20 +231,19 @@ class DataRestControllerSpec extends Specification { } def 'Update data node leaves with observedTimestamp'() { - given: 'json data' - def jsonData = 'json data' + given: 'endpoint to update a node leaves ' def endpoint = "$dataNodeBaseEndpoint/anchors/$anchorName/nodes" when: 'patch request is performed' def response = mvc.perform( patch(endpoint) .contentType(MediaType.APPLICATION_JSON) - .content(jsonData) + .content(jsonObject) .param('xpath', '/') .param('observed-timestamp', observedTimestamp) ).andReturn().response then: 'the service method is invoked with expected parameters' - expectedApiCount * mockCpsDataService.updateNodeLeaves(dataspaceName, anchorName, '/', jsonData, + expectedApiCount * mockCpsDataService.updateNodeLeaves(dataspaceName, anchorName, '/', jsonString, { it == DateTimeUtility.toOffsetDateTime(observedTimestamp) }) and: 'response status indicates success' response.status == expectedHttpStatus.value() @@ -257,19 +254,18 @@ class DataRestControllerSpec extends Specification { } def 'Replace data node tree: #scenario.'() { - given: 'json data' - def jsonData = 'json data' + given: 'endpoint to replace node' def endpoint = "$dataNodeBaseEndpoint/anchors/$anchorName/nodes" when: 'put request is performed' def response = mvc.perform( put(endpoint) .contentType(MediaType.APPLICATION_JSON) - .content(jsonData) + .content(jsonObject) .param('xpath', inputXpath)) .andReturn().response then: 'the service method is invoked with expected parameters' - 1 * mockCpsDataService.replaceNodeTree(dataspaceName, anchorName, xpathServiceParameter, jsonData, noTimestamp) + 1 * mockCpsDataService.replaceNodeTree(dataspaceName, anchorName, xpathServiceParameter, jsonString, noTimestamp) and: 'response status indicates success' response.status == HttpStatus.OK.value() where: @@ -280,20 +276,19 @@ class DataRestControllerSpec extends Specification { } def 'Replace data node tree with observedTimestamp.'() { - given: 'json data' - def jsonData = 'json data' + given: 'endpoint to replace node' def endpoint = "$dataNodeBaseEndpoint/anchors/$anchorName/nodes" when: 'put request is performed' def response = mvc.perform( put(endpoint) .contentType(MediaType.APPLICATION_JSON) - .content(jsonData) + .content(jsonObject) .param('xpath', '') .param('observed-timestamp', observedTimestamp)) .andReturn().response then: 'the service method is invoked with expected parameters' - expectedApiCount * mockCpsDataService.replaceNodeTree(dataspaceName, anchorName, '/', jsonData, + expectedApiCount * mockCpsDataService.replaceNodeTree(dataspaceName, anchorName, '/', jsonString, { it == DateTimeUtility.toOffsetDateTime(observedTimestamp) }) and: 'response status indicates success' response.status == expectedHttpStatus.value() @@ -308,14 +303,14 @@ class DataRestControllerSpec extends Specification { def putRequestBuilder = put("$dataNodeBaseEndpoint/anchors/$anchorName/list-nodes") .contentType(MediaType.APPLICATION_JSON) .param('xpath', 'parent xpath') - .content('json data') + .content(jsonObject) if (observedTimestamp != null) putRequestBuilder.param('observed-timestamp', observedTimestamp) def response = mvc.perform(putRequestBuilder).andReturn().response then: 'a success response is returned' response.status == expectedHttpStatus.value() and: 'the java API was called with the correct parameters' - expectedApiCount * mockCpsDataService.replaceListContent(dataspaceName, anchorName, 'parent xpath', 'json data', + expectedApiCount * mockCpsDataService.replaceListContent(dataspaceName, anchorName, 'parent xpath', jsonString, { it == DateTimeUtility.toOffsetDateTime(observedTimestamp) }) where: scenario | observedTimestamp || expectedApiCount | expectedHttpStatus diff --git a/cps-rest/src/test/groovy/org/onap/cps/rest/exceptions/CpsRestExceptionHandlerSpec.groovy b/cps-rest/src/test/groovy/org/onap/cps/rest/exceptions/CpsRestExceptionHandlerSpec.groovy index f5968442d..658dcaa70 100644 --- a/cps-rest/src/test/groovy/org/onap/cps/rest/exceptions/CpsRestExceptionHandlerSpec.groovy +++ b/cps-rest/src/test/groovy/org/onap/cps/rest/exceptions/CpsRestExceptionHandlerSpec.groovy @@ -163,7 +163,7 @@ class CpsRestExceptionHandlerSpec extends Specification { post("$basePath/v1/dataspaces/dataspace-name/anchors/anchor-name/nodes") .contentType(MediaType.APPLICATION_JSON) .param('xpath', 'parent node xpath') - .content('json data') + .content(groovy.json.JsonOutput.toJson('{"some-key" : "some-value"}')) ).andReturn().response then: 'response code indicates bad input parameters' response.status == BAD_REQUEST.value()