Enhance the Multipart Delta API to support JSON file 68/140268/20
authorRudrangi Anupriya <ra00745022@techmahindra.com>
Wed, 9 Apr 2025 09:55:17 +0000 (15:25 +0530)
committerRudrangi Anupriya <ra00745022@techmahindra.com>
Wed, 14 May 2025 09:50:05 +0000 (15:20 +0530)
Here we upload Json file as payloads instead of  JSON data as text input

Issue-ID: CPS-2657
Change-Id: Ibc9bbb99aabb07302366321c6d5c2eade0e7e5fb
Signed-off-by: Rudrangi Anupriya <ra00745022@techmahindra.com>
cps-rest/docs/openapi/components.yml
cps-rest/docs/openapi/cpsDelta.yml
cps-rest/src/main/java/org/onap/cps/rest/controller/DeltaRestController.java
cps-rest/src/main/java/org/onap/cps/rest/exceptions/CpsRestExceptionHandler.java
cps-rest/src/main/java/org/onap/cps/rest/utils/MultipartFileUtil.java
cps-rest/src/test/groovy/org/onap/cps/rest/controller/DeltaRestControllerSpec.groovy
docs/api/swagger/cps/openapi.yaml
docs/api/swagger/ncmp/openapi.yaml

index 43a3118..939e2d7 100644 (file)
@@ -65,6 +65,16 @@ components:
           description: multipartFile
           format: binary
 
+    TargetDataAsJsonFile:
+      type: object
+      required:
+        - file
+      properties:
+        file:
+          type: string
+          description: multipartFile
+          format: binary
+
     ModuleReferences:
       type: object
       title: Module reference object
index 67535ce..644dc27 100644 (file)
@@ -62,21 +62,18 @@ delta:
           schema:
             type: object
             properties:
-              json:
-                type: object
-                example:
-                  test:bookstore:
-                    bookstore-name: Chapters
-                    categories:
-                      - code: 01
-                        name: SciFi
-                      - code: 02
-                        name: kids
-              file:
-                type: string
-                format: binary
+              targetDataAsJsonFile:
+                   type: string
+                   format: binary
+                   example:
+                     $ref: 'components.yml#/components/schemas/TargetDataAsJsonFile'
+              yangResourceFile:
+                    type: string
+                    format: binary
+                    example:
+                      $ref: 'components.yml#/components/schemas/MultipartFile'
             required:
-              - json
+              - targetDataAsJsonFile
     responses:
       '200':
         description: OK
index f27346c..641a4db 100644 (file)
@@ -32,6 +32,7 @@ import org.onap.cps.api.CpsDeltaService;
 import org.onap.cps.api.model.DeltaReport;
 import org.onap.cps.api.parameters.FetchDescendantsOption;
 import org.onap.cps.rest.api.CpsDeltaApi;
+import org.onap.cps.rest.utils.MultipartFileUtil;
 import org.onap.cps.utils.JsonObjectMapper;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
@@ -69,21 +70,20 @@ public class DeltaRestController implements CpsDeltaApi {
     @Override
     public ResponseEntity<Object> getDeltaByDataspaceAnchorAndPayload(final String dataspaceName,
                                                                       final String sourceAnchorName,
-                                                                      final Object jsonPayload,
+                                                                      final MultipartFile targetDataAsJsonFile,
                                                                       final String xpath,
-                                                                      final MultipartFile multipartFile) {
+                                                                      final MultipartFile yangResourceFile) {
         final FetchDescendantsOption fetchDescendantsOption = FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS;
-
+        final String targetData = MultipartFileUtil.extractJsonContent(targetDataAsJsonFile, jsonObjectMapper);
         final Map<String, String> yangResourceMap;
-        if (multipartFile == null) {
+        if (yangResourceFile == null) {
             yangResourceMap = Collections.emptyMap();
         } else {
-            yangResourceMap = extractYangResourcesMap(multipartFile);
+            yangResourceMap = extractYangResourcesMap(yangResourceFile);
         }
         final Collection<DeltaReport> deltaReports = Collections.unmodifiableList(
             cpsDeltaService.getDeltaByDataspaceAnchorAndPayload(dataspaceName, sourceAnchorName,
-                xpath, yangResourceMap, jsonPayload.toString(), fetchDescendantsOption));
+                xpath, yangResourceMap, targetData, fetchDescendantsOption));
         return new ResponseEntity<>(jsonObjectMapper.asJsonString(deltaReports), HttpStatus.OK);
     }
-
 }
index 7e1d641..28d74af 100755 (executable)
@@ -2,7 +2,7 @@
  *  ============LICENSE_START=======================================================
  *  Copyright (C) 2020 Pantheon.tech
  *  Modifications Copyright (C) 2021-2023 Nordix Foundation
- *  Modifications Copyright (C) 2022 TechMahindra Ltd.
+ *  Modifications Copyright (C) 2022-2025 TechMahindra Ltd.
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -38,6 +38,7 @@ import org.onap.cps.api.exceptions.ModelValidationException;
 import org.onap.cps.api.exceptions.NotFoundInDataspaceException;
 import org.onap.cps.rest.controller.AdminRestController;
 import org.onap.cps.rest.controller.DataRestController;
+import org.onap.cps.rest.controller.DeltaRestController;
 import org.onap.cps.rest.controller.QueryRestController;
 import org.onap.cps.rest.model.ErrorMessage;
 import org.springframework.http.HttpMethod;
@@ -49,7 +50,7 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
 
 @Slf4j
 @RestControllerAdvice(assignableTypes = {AdminRestController.class, DataRestController.class,
-    QueryRestController.class})
+    DeltaRestController.class, QueryRestController.class})
 @NoArgsConstructor(access = AccessLevel.PACKAGE)
 public class CpsRestExceptionHandler {
 
index 49f4f32..b41d78b 100644 (file)
@@ -3,6 +3,7 @@
  *  Copyright (C) 2020 Pantheon.tech
  *  Modifications Copyright (C) 2021 Bell Canada.
  *  Modifications Copyright (C) 2023 Nordix Foundation.
+ *  Modifications Copyright (C) 2025 TechMahindra Ltd.
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -23,6 +24,7 @@ package org.onap.cps.rest.utils;
 
 import static org.opendaylight.yangtools.yang.common.YangConstants.RFC6020_YANG_FILE_EXTENSION;
 
+import com.fasterxml.jackson.databind.JsonNode;
 import com.google.common.collect.ImmutableMap;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -35,7 +37,9 @@ import java.util.zip.ZipInputStream;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.onap.cps.api.exceptions.CpsException;
+import org.onap.cps.api.exceptions.DataValidationException;
 import org.onap.cps.api.exceptions.ModelValidationException;
+import org.onap.cps.utils.JsonObjectMapper;
 import org.springframework.web.multipart.MultipartFile;
 
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
@@ -68,12 +72,34 @@ public class MultipartFileUtil {
                 Arrays.asList(YANG_FILE_EXTENSION, ZIP_FILE_EXTENSION)));
     }
 
+    /**
+     * Extracts json content from multipart file instance.
+     *
+     * @param multipartFile the json file uploaded
+     * @return the string representation of the JSON content
+     * @throws IOException if the file is null or empty
+     */
+
+    public static String extractJsonContent(final MultipartFile multipartFile, final JsonObjectMapper
+        jsonObjectMapper) {
+        try {
+            if (multipartFile.isEmpty()) {
+                throw new IOException("JSON file is required");
+            }
+            final String jsonContent = new String(multipartFile.getBytes(), StandardCharsets.UTF_8);
+            final JsonNode jsonNode = jsonObjectMapper.convertToJsonNode(jsonContent);
+            return jsonNode.toString();
+        } catch (final IOException exception) {
+            throw new DataValidationException("Failed to read JSON file", exception.getMessage());
+        }
+    }
+
     private static Map<String, String> extractYangResourcesMapFromZipArchive(final MultipartFile multipartFile) {
         final ImmutableMap.Builder<String, String> yangResourceMapBuilder = ImmutableMap.builder();
         final var zipFileSizeValidator = new ZipFileSizeValidator();
         try (
             final var inputStream = multipartFile.getInputStream();
-            final var zipInputStream = new ZipInputStream(inputStream);
+            final var zipInputStream = new ZipInputStream(inputStream)
         ) {
             ZipEntry zipEntry;
             while ((zipEntry = zipInputStream.getNextEntry()) != null) {
index 18c0f13..db4ef57 100644 (file)
@@ -35,6 +35,10 @@ import org.springframework.test.web.servlet.MockMvc
 import org.springframework.web.multipart.MultipartFile
 import spock.lang.Shared
 import spock.lang.Specification
+import java.nio.charset.StandardCharsets
+import java.nio.file.Files
+import java.nio.file.Path
+import java.nio.file.StandardOpenOption
 
 import static org.onap.cps.api.parameters.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
 import static org.onap.cps.api.parameters.FetchDescendantsOption.OMIT_DESCENDANTS
@@ -65,10 +69,21 @@ class DeltaRestControllerSpec extends Specification {
     @Shared
     def expectedJsonData = '{"some-key":"some-value","categories":[{"books":[{"authors":["Iain M. Banks"]}]}]}'
     @Shared
-    static MultipartFile multipartYangFile = new MockMultipartFile('file', 'filename.yang', 'text/plain', 'content'.getBytes())
+    static MultipartFile multipartYangFile = new MockMultipartFile('yangResourceFile', 'filename.yang', 'text/plain', 'content'.getBytes())
+    @Shared
+    Path targetDataAsJsonFile
+    @Shared
+    MockMultipartFile multipartTargetDataAsJsonFile
 
     def setup() {
         dataNodeBaseEndpointV2 = "$basePath/v2/dataspaces/$dataspaceName/anchors/$anchorName/delta"
+        targetDataAsJsonFile = Files.createTempFile('requestBody', '.json')
+        Files.write(targetDataAsJsonFile, requestBodyJson.getBytes(StandardCharsets.UTF_8), StandardOpenOption.WRITE)
+        multipartTargetDataAsJsonFile = new MockMultipartFile('targetDataAsJsonFile', targetDataAsJsonFile.fileName.toString(), 'application/json', Files.readAllBytes(targetDataAsJsonFile))
+    }
+
+    def cleanup() {
+        Files.deleteIfExists(targetDataAsJsonFile)
     }
 
     def 'Get delta between two anchors'() {
@@ -88,7 +103,7 @@ class DeltaRestControllerSpec extends Specification {
             assert response.contentAsString.contains('[{\"action\":\"replace\",\"xpath\":\"some xpath\",\"sourceData\":{\"some key\":\"some value\"},\"targetData\":{\"some key\":\"some value\"}}]')
     }
 
-    def 'Get delta between anchor and JSON payload with multipart file'() {
+    def 'Get delta between anchor and JSON payload with yangResourceFile'() {
         given: 'sample delta report, xpath, yang model file and json payload'
             def deltaReports = new DeltaReportBuilder().actionCreate().withXpath('some xpath').build()
             def xpath = 'some xpath'
@@ -98,7 +113,7 @@ class DeltaRestControllerSpec extends Specification {
             def response =
                 mvc.perform(multipart(dataNodeBaseEndpointV2)
                     .file(multipartYangFile)
-                    .param('json', requestBodyJson)
+                    .file(multipartTargetDataAsJsonFile)
                     .param('xpath', xpath)
                     .contentType(MediaType.MULTIPART_FORM_DATA))
                     .andReturn().response
@@ -108,7 +123,7 @@ class DeltaRestControllerSpec extends Specification {
             assert response.contentAsString.contains('[{\"action\":\"create\",\"xpath\":\"some xpath\"}]')
     }
 
-    def 'Get delta between anchor and JSON payload without multipart file'() {
+    def 'Get delta between anchor and JSON payload without yangResourceFile'() {
         given: 'sample delta report, xpath, and json payload'
             def deltaReports = new DeltaReportBuilder().actionRemove().withXpath('some xpath').build()
             def xpath = 'some xpath'
@@ -117,7 +132,7 @@ class DeltaRestControllerSpec extends Specification {
         when: 'get delta request is performed using REST API'
             def response =
                 mvc.perform(multipart(dataNodeBaseEndpointV2)
-                    .param('json', requestBodyJson)
+                    .file(multipartTargetDataAsJsonFile)
                     .param('xpath', xpath)
                     .contentType(MediaType.MULTIPART_FORM_DATA))
                     .andReturn().response
@@ -126,4 +141,39 @@ class DeltaRestControllerSpec extends Specification {
         and: 'the response contains expected value'
             assert response.contentAsString.contains('[{\"action\":\"remove\",\"xpath\":\"some xpath\"}]')
     }
+
+    def 'Attempt to get delta between anchor and JSON payload with an Empty File'() {
+        given: 'xpath, yang model file and empty json payload'
+            def xpath = 'some xpath'
+            def emptyTargetDataAsJsonFile = new MockMultipartFile('targetDataAsJsonFile', 'empty.json', 'application/json', new byte[0])
+        when: 'get delta request is performed using REST API'
+            def response = mvc.perform(multipart(dataNodeBaseEndpointV2)
+                .file(emptyTargetDataAsJsonFile)
+                .param('xpath', xpath)
+                .contentType(MediaType.MULTIPART_FORM_DATA))
+                .andReturn()
+                .response
+        then: 'expected response code is returned'
+            assert response.status == HttpStatus.BAD_REQUEST.value()
+        then: 'the response contains expected error message'
+           assert response.contentAsString.contains("JSON file is required")
+    }
+
+    def 'Get delta between anchor and JSON payload with an invalid data'() {
+        given: 'xpath, yang model file and empty json payload'
+            def xpath = 'some xpath'
+            def invalidJsonContent = '{'
+            def invalidTargetDataAsJsonFile = new MockMultipartFile('targetDataAsJsonFile', 'invalid.json', 'application/json', invalidJsonContent.getBytes())
+        when: 'get delta request is performed using REST API'
+            def response = mvc.perform(multipart(dataNodeBaseEndpointV2)
+                .file(invalidTargetDataAsJsonFile)
+                .param('xpath', xpath)
+                .contentType(MediaType.MULTIPART_FORM_DATA))
+                .andReturn()
+                .response
+        then: 'expected response code is returned'
+            assert response.status == HttpStatus.BAD_REQUEST.value()
+        then: 'the response contains expected error message'
+            assert response.contentAsString.contains("Parsing error occurred while converting JSON content to Json Node")
+    }
 }
index 1545487..911fbc2 100644 (file)
@@ -19,6 +19,8 @@ tags:
   name: cps-admin
 - description: cps Data
   name: cps-data
+- description: CPS Delta
+  name: cps-delta
 paths:
   /v1/dataspaces:
     post:
@@ -2185,7 +2187,7 @@ paths:
           description: Internal Server Error
       summary: Get delta between anchors in the same dataspace
       tags:
-      - cps-data
+      - cps-delta
       x-codegen-request-body-name: xpath
     post:
       description: Get delta between an anchor in a dataspace and JSON payload
@@ -2275,7 +2277,7 @@ paths:
           description: Internal Server Error
       summary: Get delta between an anchor and JSON payload
       tags:
-      - cps-data
+      - cps-delta
   /v1/dataspaces/{dataspace-name}/anchors/{anchor-name}/nodes/query:
     get:
       deprecated: true
@@ -3180,21 +3182,16 @@ components:
     NotificationSubscriptionsDataSample: {}
     getDeltaByDataspaceAnchorAndPayload_request:
       properties:
-        json:
-          example:
-            test:bookstore:
-              bookstore-name: Chapters
-              categories:
-              - code: 1
-                name: SciFi
-              - code: 2
-                name: kids
-          type: object
-        file:
+        targetDataAsJsonFile:
+          example: "{$ref=components.yml#/components/schemas/TargetDataAsJsonFile}"
+          format: binary
+          type: string
+        yangResourceFile:
+          example: "{$ref=components.yml#/components/schemas/MultipartFile}"
           format: binary
           type: string
       required:
-      - json
+      - targetDataAsJsonFile
       type: object
   securitySchemes:
     basicAuth:
index ec9b4fb..1bc7083 100644 (file)
@@ -32,11 +32,11 @@ paths:
       - description: |
           The `resourceIdentifier` parameter specifies the target resource in the GNBDUFunctionConfig model.
              For ONAP DMI Plugin, the format will follow RESTConf paths. Examples:
-               - All GNBDUFunctions: `'/ManagedElement=NRNode1/GNBDUFunction=1'`
+               - All GNBDUFunctions: `/ManagedElement=node1/GNBDUFunction=1`
         examples:
           sample 1:
             value:
-              resourceIdentifier: '/ManagedElement=NRNode1/GNBDUFunction=1'
+              resourceIdentifier: /ManagedElement=node1/GNBDUFunction=1
         in: query
         name: resourceIdentifier
         required: true
@@ -138,11 +138,11 @@ paths:
       - description: |
           The `resourceIdentifier` parameter specifies the target resource in the GNBDUFunctionConfig model.
              For ONAP DMI Plugin, the format will follow RESTConf paths. Examples:
-               - All GNBDUFunctions: `/ManagedElement=NRNode1/GNBDUFunction=1`
+               - All GNBDUFunctions: `/ManagedElement=node1/GNBDUFunction=1`
         examples:
           sample 1:
             value:
-              resourceIdentifier: '/ManagedElement=NRNode1/GNBDUFunction=1'
+              resourceIdentifier: /ManagedElement=node1/GNBDUFunction=1
         in: query
         name: resourceIdentifier
         required: true
@@ -152,18 +152,18 @@ paths:
           The `options` parameter specifies additional query options. It is mandatory to wrap key(s)=value(s) in parentheses `()`.
           Examples for GNBDUFunctionConfig queries:
             - Limit depth of returned sub-tree: `(depth=2)`
-            - Select specific fields: `(fields=id,gNBDUName)`
-            - Combine options: `(depth=3,fields=id,gNBDUName)`
+            - Select specific fields: `(fields=attributes(gNBId;gNBDUName))`
+            - Combine options: `(depth=3,fields=attributes(gNBId;gNBDUName))`
         examples:
           Limit Depth:
             value:
               options: (depth=2)
           Select Specific Fields:
             value:
-              options: "(fields=id,gNBDUName)"
+              options: (fields=attributes(gNBId;gNBDUName))
           Combine Depth and Fields:
             value:
-              options: "(depth=3,fields=id,gNBDUName)"
+              options: "(depth=3,fields=attributes(gNBId;gNBDUName))"
         in: query
         name: options
         required: false
@@ -271,11 +271,11 @@ paths:
       - description: |
           The `resourceIdentifier` parameter specifies the target resource in the GNBDUFunctionConfig model.
              For ONAP DMI Plugin, the format will follow RESTConf paths. Examples:
-               - All GNBDUFunctions: `/ManagedElement=NRNode1/GNBDUFunction=1`
+               - All GNBDUFunctions: `/ManagedElement=node1/GNBDUFunction=1`
         examples:
           sample 1:
             value:
-              resourceIdentifier: '/ManagedElement=NRNode1/GNBDUFunction=1'
+              resourceIdentifier: /ManagedElement=node1/GNBDUFunction=1
         in: query
         name: resourceIdentifier
         required: true
@@ -380,11 +380,11 @@ paths:
       - description: |
           The `resourceIdentifier` parameter specifies the target resource in the GNBDUFunctionConfig model.
              For ONAP DMI Plugin, the format will follow RESTConf paths. Examples:
-               - All GNBDUFunctions: `/ManagedElement=NRNode1/GNBDUFunction=1`
+               - All GNBDUFunctions: `/ManagedElement=node1/GNBDUFunction=1`
         examples:
           sample 1:
             value:
-              resourceIdentifier: '/ManagedElement=NRNode1/GNBDUFunction=1'
+              resourceIdentifier: /ManagedElement=node1/GNBDUFunction=1
         in: query
         name: resourceIdentifier
         required: true
@@ -494,11 +494,11 @@ paths:
       - description: |
           The `resourceIdentifier` parameter specifies the target resource in the GNBDUFunctionConfig model.
              For ONAP DMI Plugin, the format will follow RESTConf paths. Examples:
-               - All GNBDUFunctions: `/ManagedElement=NRNode1/GNBDUFunction=1`
+               - All GNBDUFunctions: `/ManagedElement=node1/GNBDUFunction=1`
         examples:
           sample 1:
             value:
-              resourceIdentifier: '/ManagedElement=NRNode1/GNBDUFunction=1'
+              resourceIdentifier: /ManagedElement=node1/GNBDUFunction=1
         in: query
         name: resourceIdentifier
         required: true
@@ -699,10 +699,10 @@ paths:
         schema:
           example: my-cm-handle
           type: string
-      - description: For more details on cps path, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html
+      - description: "For more details on cps path, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html"
         examples:
           container cps path:
-            value: '/GNBDUFunction'
+            value: //GNBDUFunction
           list attributes cps path:
             value: "//GNBDUFunction[@id='1001']"
         in: query
@@ -723,7 +723,7 @@ paths:
               options: (depth=2)
           Select Specific Fields:
             value:
-              options: "(fields=attributes(gNBId;gNBDUName))"
+              options: (fields=attributes(gNBId;gNBDUName))
           Combine Depth and Fields:
             value:
               options: "(depth=3,fields=attributes(gNBId;gNBDUName))"
@@ -1478,11 +1478,11 @@ components:
       description: |
         The `resourceIdentifier` parameter specifies the target resource in the GNBDUFunctionConfig model.
            For ONAP DMI Plugin, the format will follow RESTConf paths. Examples:
-             - All GNBDUFunctions: `/ManagedElement=NRNode1/GNBDUFunction=1`
+             - All GNBDUFunctions: `/ManagedElement=node1/GNBDUFunction=1`
       examples:
         sample 1:
           value:
-            resourceIdentifier: '/ManagedElement=NRNode1/GNBDUFunction=1'
+            resourceIdentifier: /ManagedElement=node1/GNBDUFunction=1
       in: query
       name: resourceIdentifier
       required: true
@@ -1501,7 +1501,7 @@ components:
             options: (depth=2)
         Select Specific Fields:
           value:
-            options: "(fields=attributes(gNBId;gNBDUName))"
+            options: (fields=attributes(gNBId;gNBDUName))
         Combine Depth and Fields:
           value:
             options: "(depth=3,fields=attributes(gNBId;gNBDUName))"
@@ -1567,21 +1567,12 @@ components:
         example: my-cm-handle
         type: string
     cpsPathInQuery:
-      description: |
-        The `cps-path` parameter allows referencing elements in the GNBDUFunctionConfig data model.
-            For more details on cps path, please refer to:
-            [CPS Path Documentation](https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html).
-            Example paths:
-              - Root GNBDUFunction: `/GNBDUFunction`
-              - Specific gNB ID: `//GNBDUFunction[@id='1001']`
-              - RIM-RS Reporting Config: `//GNBDUFunction[@id='1001']/rimRSReportConf`
+      description: "For more details on cps path, please refer https://docs.onap.org/projects/onap-cps/en/latest/cps-path.html"
       examples:
-        GNBDUFunction Root:
-          value: /GNBDUFunction
-        Specific gNB ID:
+        container cps path:
+          value: //GNBDUFunction
+        list attributes cps path:
           value: "//GNBDUFunction[@id='1001']"
-        RIM-RS Reporting Config:
-          value: "//GNBDUFunction[@id='1001']/rimRSReportConf"
       in: query
       name: cps-path
       required: false
@@ -1719,7 +1710,7 @@ components:
     DataOperationRequest:
       example:
         operations:
-        - resourceIdentifier: '/ManagedElement=NRNode1/GNBDUFunction=1'
+        - resourceIdentifier: /ManagedElement=NRNode1/GNBDUFunction=1
           targetIds:
           - "[\"da310eecdb8d44c2acc0ddaae01174b1\",\"c748c58f8e0b438f9fd1f28370b17d47\"\
             ]"
@@ -1729,7 +1720,7 @@ components:
           options: (fields=NRCellDU/attributes/cellLocalId)
           operationId: "12"
           operation: read
-        - resourceIdentifier: '/ManagedElement=NRNode1/GNBDUFunction=1'
+        - resourceIdentifier: /ManagedElement=NRNode1/GNBDUFunction=1
           targetIds:
           - "[\"da310eecdb8d44c2acc0ddaae01174b1\",\"c748c58f8e0b438f9fd1f28370b17d47\"\
             ]"
@@ -1749,7 +1740,7 @@ components:
       type: object
     DataOperationDefinition:
       example:
-        resourceIdentifier: '/ManagedElement=NRNode1/GNBDUFunction=1'
+        resourceIdentifier: /ManagedElement=NRNode1/GNBDUFunction=1
         targetIds:
         - "[\"da310eecdb8d44c2acc0ddaae01174b1\",\"c748c58f8e0b438f9fd1f28370b17d47\"\
           ]"
@@ -1773,7 +1764,7 @@ components:
           example: (fields=NRCellDU/attributes/cellLocalId)
           type: string
         resourceIdentifier:
-          example: '/ManagedElement=NRNode1/GNBDUFunction=1'
+          example: /ManagedElement=NRNode1/GNBDUFunction=1
           type: string
         targetIds:
           items: