CPS-2310: Refactoring of CPS Delta APIs

Issues/Decisions/Open Questions


SloganNotesDecision
1Which alternativechanged target anchor name to a query parameter Alternative 2 of having one endpoint capable of performing 2 operations
2


Introduction

Currently CPS Delta Feature provides 2 endpoints as follows:

  • GET-/v2/dataspaces/{dataspace-name}/anchors/{anchor-name}/deltaAnchors
  • POST- /v2/dataspaces/{dataspace-name}/anchors/{anchor-name}/deltaByPayload

Objective

The objective of this proposal is to have a new singular delta endpoint which can provide the functionality of the above-mentioned endpoints. This new endpoint will be a POST operation and will accept the source anchor name as the path parameter, xpath as the query parameter and a request body which will serve 2 functions:

  • first it can be used to provide the target anchor name as a replacement for query parameter of first API
  • second it can be used to provide the JSON payload as defined in proposal of 2nd API

After determining whether an anchor name or JSON payload is provided in the request the respective underlying controller will be called. So only the endpoints will be merged to a singular endpoint, and the underlying logic will remain same.

Alternative 1: Single Endpoint

#Sub interfaceMethodScenarioHTTP response codeNotes
1Data
  • POST- /v2/dataspaces/{dataspace-name}/anchors/{anchor-name}/delta?xpath={xpath}
Generate a delta report between a source anchor and target anchor or JSON payload
  • 200 (OK)
    • success
  • 400
    • dataspace not found
      DataspaceNotFoundException
    • anchor not found
      AnchorNotFoundException
    • Data node not found
      DataNodeNotFoundException
    • invalid xpath
      CpsPathException
  • 500
    • unexpected error

Request parameters:

Parameter name

In

Required

Description

dataspace-namePathYesDataspace name
anchorPathYesSource Anchor Name
xpathQueryYesxpath of the node
descendantsQueryNoLevel of descendants for delta comparison. Set to INCLUDE_ALL_DESCENDANTS by default.

Request body:

Content-Type: multipart/form-data

Type

Format

Description

FileYang file/Zip filefile containing the schema details.
Text/StringTarget anchor name or JSON payload as plain text
  • Case 1: target anchor name to fetch the data stored under the specified anchor, which is then compared to source anchor
  • Case 2: json data to be compared to source anchor

Alternative 2:  One Endpoint with Two Operations

In RESTful interface we can have same endpoint for multiple APIs, given they are performing different operations, for example POST and GET.

So, we can have the following endpoints in CPS for the Delta feature:

  • GET /v2/dataspaces/{dataspace-name}/anchors/{anchor-name}/delta
  • POST /v2/dataspaces/{dataspace-name}/anchors/{anchor-name}/delta

Sample endpoints after change


After the update only the names of the endpoint will be updated, the path and query parameters will remain as it is. So, the updated APIs would be as follows:

#Existing EndpointUpdated EndpointPath/Query ParametersResponse Codes
1

GET-/v2/dataspaces/{dataspace-name}/anchors/{anchor-name}/deltaAnchors

GET-/v2/dataspaces/{dataspace-name}/anchors/{source-anchor-name}/delta?target-anchor-name={target-anchor-name}&descendants={descendants}&xpath={xpath}

Parameter NameInRequiredDescription
dataspace-namePathYesDataspace name
source-anchor-namePathYesFirst Anchor Name/Reference Anchor
target-anchor-nameQueryYesSecond Anchor Name/Comparand Anchor
descendantsQueryNoLevel of descendants for delta comparison. 
xpathQueryYesxpath of the node
  • 200 (OK)
    • success
  • 400
    • dataspace not found
      DataspaceNotFoundException
    • anchor not found
      AnchorNotFoundException
    • Data node not found
      DataNodeNotFoundException
    • invalid xpath
      CpsPathException
  • 500
    • unexpected error
2

POST- /v2/dataspaces/{dataspace-name}/anchors/{anchor-name}/deltaPayload

POST- /v2/dataspaces/{dataspace-name}/anchors/{source-anchor-name}/delta?xpath={xpath}

Body

file- yang/zip schema (Optional)

json - JSON payload as String (Mandatory)

Parameter NameInRequiredDescription
dataspace-namePathYesDataspace name
source-anchor-namePathYesFirst Anchor Name/Reference Anchor
xpathQueryYesxpath of the node
FileBody (multipart/form-data)OptionalYang file/Zip file containing the schema details.
Text/StringBody (multipart/form-data)YesJSON payload as plain text

Changes and Justification for going with second approach

The second proposed approach is best suited for the scenario, but there are a few minor changes to it:

Changes

  •  It was proposed to have "target-anchor-name" as a path parameter of the endpoint, resulting in a new endpoint as follows: GET-/v2/dataspaces/{dataspace-name}/anchors/{source-anchor-name}/delta/{target-anchor-name}
  • but it is suggested to set it as a query parameter due to limitations and reasons listed below.

Limitations

An attempt to set "target-anchor-name" as path parameter was made and following limitations were found out:

  • The base endpoint was set to /v2/dataspaces/{dataspace-name}/anchors/{source-anchor-name}/delta and when "target-anchor-name" is set as path parameter and appended towards the end of the base endpoint, it lead to a failure when executing the request because according to REST standards a path parameter should be part of the path and are always included in the base URI. So appending then towards the end of an URI is technically incorrect and throws the following error 

    Error message
    {
      "status": "500 INTERNAL_SERVER_ERROR",
      "message": "Required URI template variable 'target-anchor-name' for method parameter type String is not present",
      "details": "Check logs for details."
    }

    Apart from this after setting "target-anchor-name" as path parameter the URI generated was "/v2/dataspaces/{dataspace-name}/anchors/{source-anchor-name}/delta" instead of "/v2/dataspaces/{dataspace-name}/anchors/{source-anchor-name}/delta/target-anchor-name/{target-anchor-name} because REST ignores any path parameter set after the base URI..

  • So, alternatively an attempt to set "target-anchor-name" as part of base URI was made and this resulted in the following:
    /v2/dataspaces/{dataspace-name}/anchors/{source-anchor-name}/target-anchor-name/{target-anchor-name}/delta
    But this approach brings us back to the original problem that is to have a singular endpoint for delta feature. And the above URI is clearly a different endpoint compared to the second operation, i.e. delta between an anchor and a payload having an endpoint as follows /v2/dataspaces/{dataspace-name}/anchors/{source-anchor-name}/delta

Most viable approach

The best viable alternative is to set "target-anchor-name" as a query parameter. This resolves most of the problems mentioned above while solving the main issue, that is to have a singular endpoint for delta operation.

Justifications:

  • since the operation is always same, i.e. delta, having a single endpoint makes more sense. So finalized endpoint is as follows /v2/dataspaces/{dataspace-name}/anchors/{source-anchor-name}/delta
  • this will also make the openapi doc more manageable

Decisions leading to above mentioned endpoint:

  • we have two different ways to generate delta, so we can say the final operation is common that is "delta". So, the idea is to have the common components between the operations as path parameters, i.e. dataspace name and first anchor name
  • remaining components should be in query, that is target anchor name, and fetch descendants' option in first operation and JSON payload and schema in second operation.
  • this approach is also consistent with existing CPS API's such as list-node APIs where a singular endpoint performs different operations while having similar parameters