-
Notifications
You must be signed in to change notification settings - Fork 4
Description
Issue: Service Mashup Deep Read Fails on Extended CatalogService
-
I am attempting to implement a Service Mashup following the principle of extending an external service's entity (bookshop.CatalogService.Books) with an association to a data source from another service (reviews.ReviewService).
-
The core issue is that the OData parser is rejecting the request with an Invalid resource path error, indicating that the extension logic defined in my local service is not being loaded or recognized by the service endpoint handling the request.
Context and Goal
The setup is based on the capire/samples structure, running the bookshop, reviews, and bookstore (where the mashup logic resides) packages in a monorepo structure, likely using cds run from the root.
Goal: Enable deep reads on the CatalogService.Books entity, allowing queries like GET /Books(ID)/reviews.
Reproduction Steps
Define the necessary services in the monorepo structure (bookshop, reviews, and bookstore).
In the bookstore package, define the extension model (srv/mashup.cds) and the handler logic (srv/mashup.js).
bookstore/srv/mashup.cds (Current implementation, including the necessary Association fix earlier reviews was a simple Integer property which gave invalid navigation property error):
using {sap.capire.bookshop} from 'bookshop';
using {sap.capire.reviews.api.ReviewService as reviews} from 'reviews';
using {sap.capire.reviews.app.ReviewService as reviewOrg} from 'reviews';
extend bookshop.Books with {
test_prop : Integer default 2;
ratings : type of reviews.AverageRatings : rating;
// CRITICAL: Defining the Association for valid navigation
reviews : Association to many reviewOrg.Reviews
on reviews.subject = $self.ID;
}
bookstore/srv/mashup.js (Handler logic using prepend):
cds.once("served", async () => {
const CatalogService = await cds.connect.to("CatalogService");
const ReviewService = await cds.connect.to("ReviewService");
const db = await cds.connect.to("db");
const { Books } = cds.entities("sap.capire.bookshop");
CatalogService.prepend((srv) =>
// Intercepts the READ event on the new navigation path
srv.on("READ", "Books/reviews", (req) => {
const [id] = req.params,
{ columns, limit } = req.query.SELECT;
// Delegate the read to the ReviewService
return ReviewService.read("Reviews", columns)
.limit(limit)
.where({ subject: String(id) });
})
);
})
;
Run the application (e.g., cds run from the monorepo root).
Execute the deep read request:
### Request to CatalogService endpoint (e.g., port 4004)
GET {{bookshop}}/odata/v4/catalog/Books/201/reviews?
&$select=rating,date,title
&$top=3
Observed Behavior (Error)
The request is not intercepted by the prepend handler in mashup.js. Instead, the bookshop service terminal throws an OData model validation error:
[odata] - GET /odata/v4/catalog/Books/201/reviews { '$select': 'rating,date,title', '$top': '3' }
[cds] - Error: Invalid resource path "CatalogService.Books:reviews"
at _processSegments (...)
... (full stack trace)
{ code: '404', statusCode: 404 }
[error] - 404 > {
code: '404',
message: 'Invalid resource path "CatalogService.Books:reviews"'
}
Conceptual Question
Even after correcting the model by adding the Association to many, the error persists. This suggests a runtime loading/scoping issue rather than a model syntax issue.
How can I ensure that the CatalogService instance that is serving the OData endpoint (which lives in the bookshop package) correctly loads and applies the model extensions from the bookstore package's mashup.cds and the event handler from mashup.js?
Is there a specific configuration (e.g., in package.json or package-lock.json dependency linking) required for the prepend logic to successfully inject itself into the host service's runtime when running a monorepo setup?
What is the recommended approach to debug why the CatalogService serving the request is running the unextended model?
bookstore/package.json
"dependencies": {
"@sap/cds": "^8",
"express": "^4",
"bookshop": "*",
"reviews": "*",
"orders": "*",
"common-db": "*",
"@sap-cloud-sdk/connectivity": "^4",
"@sap-cloud-sdk/http-client": "^4",
"@sap-cloud-sdk/resilience": "^4"
},
"cds": {
"requires": {
"ReviewService": {
"kind": "odata",
"model": "reviews",
"service": "sap.capire.reviews.api.ReviewService"
},
"OrderService": {
"kind": "odata",
"model": "orders",
"service": "sap.capire.orders.api.OrderService"
}
}
}
cds version
@sap/cds: 9.4.4
@sap/cds-dk: 9.4.3
@sap/cds-compiler: 6.4.6
@sap/cds-dk (global): 9.4.3
@sap/cds-fiori: 2.1.1
@sap/cds-mtxs: 3.4.3
@cap-js/asyncapi: 1.0.3
@cap-js/openapi: 1.2.3
Node.js: v22.12.0