meakgoz
meakgoz

Reputation: 588

DateTime field causes error after CAP v8 upgrade

I am using SAP Cloud SDK together with SAP CAP. Recently I upgraded from CAP v7 to v8, regenerate the odata clients and started getting errors on creating entity that has DateTime field.

Reproduce the error

I have reproduce the error using CAP sample bookshop.

Get the CAP sample app

  1. Get the CAP Cloud Samples from here
  2. Update the CAP version of the Bookshop app by replacing package.json#L16 with "@sap/cds": ">=8",
  3. Add a DateTime field (e.g., testField : DateTime;) to the Books entity after image field, so here:
  4. run npm ci and cds watch bookshop to start the CAP server.

Create a typescript express app

  1. Create a very simple typescript exress application and install the SDK dependencies.
  2. Get the bookshop admin service edmx: cds ../cloud-cap-samples/bookshop/srv/admin-service.cds -2 edmx > ./resources/bookshop.edmx (NOTE: for this to work, you need to have ypur express app in the same root folder as the cloud-cap-samples, or you need to change the relative path).
  3. Generate the OData client: generate-odata-client --input resources/ --outputDir src/odata-clients/ --overwrite --clearOutputDir --optionsPerService resources/service-mapping.json (Need to install the generator package globally: npm install -g @sap-cloud-sdk/generator)
  4. Write this Get request (for the sake of simplicity) to your index.ts:
import { bookshop } from "./odata-clients/bookshop";
const { booksApi } = bookshop();

app.get("/post-books", async (req: Request, res: Response) => {
 const bookEntityToPost = booksApi
   .entityBuilder()
   .title("Test Book")
   .authorId(101)
   .descr("Test Description")
   .price(new BigNumber(100.0))
   .stock(10)
   .testField(moment.utc("2022-12-15 18:00:31.139000000")) // an example time field I get from S/4HANA
   .build();

 const craeteBookRequest = booksApi
   .requestBuilder()
   .create(bookEntityToPost)
   .skipCsrfTokenFetching();

 const result = await craeteBookRequest.execute({
   url: "http://localhost:4004",
   username: "alice",
   password: "",
   authentication: "BasicAuthentication",
 });

 console.log(result);

 res.send("Book posted");
});

Run the app

  1. Run the app (e.g., ts-node src/main.ts and make the get request to http://localhost:8000/post-books (I used the browser simply.)

Output

Node app crashes with the following error:

[nodemon] starting `ts-node src/main.ts`
Server is Fire at http://localhost:8000
[2024-11-21T15:05:26.665Z] ERROR    ErrorWithCause: Create request failed!
    at /Users/path/to/project/node_modules/@sap-cloud-sdk/odata-common/src/request-builder/create-request-builder-base.ts:113:15
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
Caused by:
ErrorWithCause: post request to http://localhost:4004/admin failed! 
{"message":"Value 2022-12-15T18:00:31.139Z is not a valid DateTime","target":"testField","code":"400","@Common.numericSeverity":4}
    at constructError (/Users/path/to/project/node_modules/@sap-cloud-sdk/odata-common/src/request/odata-request.ts:291:12)
    at /Users/path/to/project/node_modules/@sap-cloud-sdk/odata-common/src/request/odata-request.ts:237:13
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
Caused by:
HTTP Response: Request failed with status code 400 - [object Object]
[nodemon] app crashed - waiting for file changes before starting...

and the CAP server logs:

[odata] - POST /admin/Books 
[cds] - [Value 2022-12-15T18:00:31.139Z is not a valid DateTime] {
  target: 'testField',
  args: [ '2022-12-15T18:00:31.139Z', DateTime { type: 'cds.DateTime' } ]
}
[error] - 400 > {
  message: 'Value 2022-12-15T18:00:31.139Z is not a valid DateTime',
  target: 'testField',
  code: '400',
  '@Common.numericSeverity': 4
}

EDIT: Adding a repository with bookshop and small sample for SDK. Readme should provide necessary information to replicate the problem.

Upvotes: 0

Views: 144

Answers (2)

Daniel
Daniel

Reputation: 1

We double-checked and analysed the situation from CAP side, with these outcomes ....

Long story short:

  • The behavior in cds8 is correct; the former one was wrong.
  • We should keep the correct one → please fix your clients.
  • ( Note: Fiori clients always behaved correctly, apparently ).

Long story long...

  1. The relevant CDS types are specified as follows (from the very beginning of CDS):

    CDS Type Remarks
    DateTime sec precision → i.e. 0 fractional digits
    Timestamp µs precision, with up to 7 fractional digits
  2. The cds compiler maps these to OData as follows (always did so):

    CDS Type OData v4
    DateTime Edm.DateTimeOffset
    Timestamp Edm.DateTimeOffset with Precision="7"
  3. The OData standard specifies for Edm.DateTimeOffset attribute Precision:

    If not specified for a temporal property, the temporal property has a precision of zero.
    ( "temporal" in there means date/time related data )

  4. With the New OData Adapter (NOA) comes improved input validation which corrects quite some glitches of the external OData lib used before. One of which is checking on value ranges and precisions of numbers and datetime values to protect applications from late data loss surprises due to unexpected truncation → was requested by many stakeholders/customers.


Does that help?

Upvotes: 0

bananabräd
bananabräd

Reputation: 21

Good find! We in the SAP Cloud SDK were also testing the v8 integration and noticed the same issue. There is already an issue raised with CAP here, for now you will have to wait.

Upvotes: 1

Related Questions