cap-js-community / odata-v2-adapter

OData V2 adapter for CDS. Exposes a full-fledged OData V2 service, converting OData V2 requests to CDS OData V4 service calls and responses back.
https://www.npmjs.com/package/@cap-js-community/odata-v2-adapter
Apache License 2.0
23 stars 8 forks source link

Odata v2 response's navigation uri appending v4 path along with v2 #45

Closed pranavnag18 closed 4 months ago

pranavnag18 commented 4 months ago

A simple CAP application that needs to serve both OData v4 and v2. To achieve this, I'm using the cov2ap plugin. In the plugin configuration, I've specified path and targetPath to route requests for v2 to the corresponding v4 endpoint.

However, I've encountered an issue where the OData v2 API response incorrectly appends the v4 path to the v2 target URI. For example, my setup is as follows:

OData v4 endpoint: /api/v4/businesspartner

OData v2 endpoint: /api/v2/businesspartner

Yet, the OData v2 response for business partners navigation to orders uri includes URLs that combine paths from both v2 and v4, like this below,

"__deferred": {
            "uri": "https://<host>/api/v2/businesspartner/api/v4/businesspartner('05c0436a-a2ff-41db-9261-f52c22d9accf')/ORDERS"
          }

          note: **/api/v4/businesspartner** appended in the target uri

Here is the relevant part of my package.json:

"cov2ap": {
   "plugin": true,   
   "path": "api/v2/businesspartner",
   "targetPath": "api/v4/businesspartner" 
}   

And the service.cds:

service partner@(path: '/api/v4/businesspartner') {          
           entity businesspartner{                   
                       key ID : string(40),                 
                        .....                   
                      ORDERS: Association to many Order                                     
                                       on Order.order_id= $self.ID;        
             }
}

odata v2 request and response


GET https://<host>/api/v2/businesspartner

{
  "d": {
    "results": [
      {
        "ID": "05c0436a-a2ff-41db-9261-f52c22d9accf",
        "ORDERS": {
          "__deferred": {
            "uri": "https://<host>/api/v2/businesspartner/api/v4/businesspartner('05c0436a-a2ff-41db-9261-f52c22d9accf')/ORDERS"
          }
        }
      }
    ]
  }
}

Please see the uri in the response, it appends "/api/v4/businesspartner" in the navigation uri.

oklemenz2 commented 4 months ago

Yes, your use-case is supported, but not like you configured it.

Explanation why you experience the current behavior

How you can solve this requirement

Preparation: Remove the cov2ap.path and cov2ap.targetPath configuration

Option 1 - Globally

"cds": {
  "protocols": {
    "odata": {
      "path": "/api/v4"
    },
    "odata-v2": {
      "path": "/api/v2"
    }
  }
}

Then the service path is just defined as a relative path (does not start with a slash /) appended to the protocol path: @(path: 'businesspartner')

The resulting routes are then:

OData v4: /api/v4/businesspartner OData v2: /api/v2/businesspartner

Option 2 - Service local

@protocol: [{
    kind: 'odata-v4', path: '/api/v4/businesspartner'
}, {
    kind: 'odata-v2', path: '/api/v2/businesspartner'
}]
service partner {
  // ...
}

You remove the @path annotation, and instead use the @protocol annotation. Then you start your path with a slash (/) to indicate absolute paths. This will prevent, that the paths are prefixed with the global protocol path, as you don't want to get e.g. /odata/v4/api/v4/businesspartner...

When you configure it like this, the resulting routes are then again:

OData v4: /api/v4/businesspartner OData v2: /api/v2/businesspartner

The request URLs and the URLs in the response are then correct as you expected it.