Product Information
Announcing the SAP Cloud SDK for JavaScript
TypeScript and JavaScript developers, this is for you: the SAP Cloud SDK (fka SAP S/4HANA Cloud SDK) is now available for JavaScript. Today, we are proud to release version 1.0.0 of the SAP Cloud SDK for JavaScript. This is the first generally available, productive version of the libraries for JavaScript, after the beta that started in October last year.
Similar to the SDK for Java, the SAP Cloud SDK for JavaScript makes it easy and delightful to develop extensions to SAP S/4HANA as applications on SAP Cloud Platform. The SAP Cloud SDK for JavaScript helps you to integrate SAP S/4HANA into your Cloud-native applications written in TypeScript or JavaScript, running in Node.js. You can execute those applications locally or deploy them to SAP Cloud Platform, Cloud Foundry.
Continue reading below if you want to get the high level picture on the most helpful features of the initial release and on how to access the JavaScript libraries of the SDK. If you want to get started quickly, head over to our tutorial series and begin using the SDK for JavaScript today. Like the SDK for Java, the SAP Cloud SDK for JavaScript is available free-of-charge under SAP Developer License.
Capabilities of the SDK for JavaScript
The following describes on a high-level the most important features. For more details, refer to the release notes and the API documentation in JSDoc.
Easy access to SAP S/4HANA Cloud APIs
Accessing SAP S/4HANA Cloud can be as easy as follows – no boilerplate, low-level code, just business logic:
import { BusinessPartner } from '@sap/cloud-sdk-vdm-business-partner-service';
BusinessPartner.requestBuilder()
.getAll()
.select(BusinessPartner.LAST_NAME)
.filter(BusinessPartner.FIRST_NAME.equals("John"))
.execute({destinationName: "S4HANACloud"})
.then(businessPartners => {
// process result of type BusinessPartner[]
}).catch(reason => {
// handle error
});
This is made possible by the OData Virtual Data Model (VDM, also known from the SDK for Java). The OData VDM of the SDK for JavaScript provides a TypeScript/JavaScript representation of the OData API of SAP S/4HANA Cloud, including all services, operations and entity types listed on the SAP API Business Hub. In a similar manner as the code snippet above, you can access not only reading, but also writing operations (function imports are not yet supported).
Straightforward integration of SAP Cloud Platform
The code snippet above also illustrates the out-of-the-box integration with the destination service on SAP Cloud Platform for managing the target system, or destination, and authentication credentials. Don’t worry if you missed it at first glance – it’s easy to miss thanks to the straightforward integration: when calling execute on an OData VDM request, you pass the name of a destination, in this case, S4HANACloud
. That’s it, the SDK will take care of resolving the destination defined in the destination service on SAP Cloud Platform and perform the required authentication.
If you prefer, you can also define the destination manually. In addition, it’s easy to substitute the destination service with simple environment variables when running locally or during tests.
TypeScript or JavaScript?
The above example uses TypeScript, a typed superset of JavaScript. If you are only familiar with JavaScript, you may not even have noticed, though. In fact, the above code is also perfectly valid JavaScript. The SAP Cloud SDK for JavaScript has been implemented in TypeScript, and can be used in JavaScript and TypeScript project alike. Both JavaScript and TypeScript developers can use the same libraries and get the same features, and both will benefit from the code completion capabilities enabled by TypeScript, given an editor with corresponding support. TypeScript projects of course will benefit from additional type-safety.
We can only encourage everyone to check if TypeScript suits his needs. If you don’t want to use TypeScript, it is still perfectly fine to stick to plain JavaScript and use the SDK in JavaScript.
Continuous delivery pipeline
The continuous delivery toolkit is a core component of the SAP Cloud SDK, because it enables projects to continuously deliver their application without additional effort for setting up a continuous delivery pipeline. We are happy that we are able from the very beginning to provide this out-of-the-box continuous delivery pipeline also for JavaScript projects.
To this end, we provide two project scaffolds, one for TypeScript and one for JavaScript projects. They out-of-the-box include everything needed to run the continuous delivery pipeline on a Jenkins server. You do not have to write a single line of pipeline code to benefit from the best practices codified in the pipeline, only configure it to your project environment. For more details on what is supported, take a look at the release announcement for version v17 of the continuous delivery toolkit.
How to Access the JavaScript Libraries
The JavaScript libraries of the SAP Cloud SDK are freely accessible from SAP’s npm registry. SAP’s registry works like the standard npmjs registry for resolving JavaScript modules. It hosts packages of the scope @sap
. All you need to do to be able to retrieve the SDK modules, which are all provided with scope @sap
, is executing the following command:
npm config set "@sap:registry" "https://npm.sap.com"
Afterwards, pick any module of the SDK listed on the module overview in the documentation and install it as a dependency into your Node.js project, for example:
npm install @sap/cloud-sdk-vdm-business-partner-service
Thank You!
Thanks a lot to the whole development team for the effort and dedication to make the release possible. We would also like to thank the many partners and customers that participated in the beta. Their feedback helped shape the version 1.0.0 of the SAP Cloud SDK for JavaScript.
Here’s what two SAP partners participating in the beta had to say:
- Lars Schubert, managing director of graphomate GmbH, said about the SDK: “Our first tests of the SDK were very promising and we are excited to implement productive applications with it.” Jonas Vogler, Head of Software Development at graphomate GmbH, summarized the experience of the development team with the SDK as “easy to use, nice, reliable. That’s the future.”
- Scott Stefanich, solution architect at pmc America, Inc., enjoyed working with the beta of the SAP Cloud SDK for JavaScript specifically because of the OData virtual data model: “The virtual data model is excellent. The combination of type-safety and auto-completion really improves your productivity and allows to focus on the task at hand.”
Now, we would like to invite everyone to experience this for themselves, use the SDK, ask questions on Stack Overflow, and give open feedback.
Thanks for such a nice blog, Really Helpful !!!
I tried to use
"https://sandbox.api.sap.com/s4hanacloud/sap/opu/odata/sap/API_BUSINESS_PARTNER" instead of MockServer however , it needs APIKey along with credentials which seems to be not supported in destination.
Can you please help me out how i can send it during fetch call ? I tried below but it gives error -
function getAllBusinessPartners(): Promise<BusinessPartner[]> {
return BusinessPartner.requestBuilder()
.getAll()
.execute({
url: 'https://sandbox.api.sap.com/s4hanacloud',
username: 'MyUserName',
password: 'MyPass',
APIKey: 'MyAPIKey'
});
}
Error ->
src/business-partner-route.ts:16:3 - error TS2345: Argument of type '{ url: string; username: string; password: string; APIKey: string; }' is not assignable to parameter of type 'Destination | DestinationNameAndJwt'.
Object literal may only specify known properties, and 'APIKey' does not exist in type 'Destination | DestinationNameAndJwt'.
Thanks ,
Mahesh Z.
Hi Mahesh,
you can set the APIKey using the withCustomHeaders method on the request builder like this:
(Plus I think you can skip username and password when providing an API key).
Let me know if this works for you! If not, don't hesitate to reach out to us for further questions.
Best regards
Dennis
Hi Dennis,
Thanks for sharing the solution, That worked for me.
Just couple of more things to clarify –
Thanks ,
Mahesh Z.
Hi Mahesh,
for all the OData operations there are corresponding functions on the request builder. Consider the following example:
This code example should give you a pretty good idea of what you can do. For more, check the documentation here: https://help.sap.com/viewer/product/SAP_S4HANA_CLOUD_SDK/1.0/en-US
Regarding VDM on S/4HANA on-premise: While the VDM we ship in the SAP Cloud SDK is for S/4HANA Cloud, it should also work for on-premise as long as the APIs themselves are compatible between the two versions.
Thanks Dennis. That worked for me. I am now trying my luck with onPremise systems.
Also , i tried to implement the same thing in plain JS but not getting the expected output - My Route Code is as follows -
const express = require("express");
const BusinessPartners = require("@sap/cloud-sdk-vdm-business-partner-service");
exports.businessPartners = function(req, res) {
res.status(200).send(getAllBusinessPartners());
}
function getAllBusinessPartners() {
return BusinessPartners.requestBuilder()
.getAll()
.top(1)
.skip(0)
.execute({
destinationName: 'MyDest'
});
}
Is there any correction required here ?
Thanks ,
Mahesh.
Your function getAllBusinessPartners returns a Promise<BusinessPartner[]>, so you will either have to await it:
or call the function and then handle the response with then() (which I recommend because you can properly handle errors):
Hi Dennis,
I am getting Internal Server Error as response.
Can you please advice if below method declaration is correct ?
function getAllMaterials() {
return Materials.requestBuilder()
.getAll()
.withCustomHeaders({
'APIKey': 'mcJX5Yp6iMh3jXlGbDt17vNzyWgARQ1E'
}).top(1)
.skip(0)
.execute({
destinationName: 'Destination'
});
}
Thanks ,
Mahesh.
Without more information about the error it's impossible to tell the cause. The code itself looks fine, though you can omit skip(0).
Hi Dennis,
Thanks for your solutions.I tried using "select" it worked for me and i am trying to "filter" but its throwing error ,can you please help me with that.
My code as follows,
Here i am attaching errors....
HIRE_DATE sounds very much like a date object. In the VDM, dates are represented by moment objects, but you passed a string. Editors like VSCode should highlight such errors. May I ask what editor you are using?
Hi Dennis,
Thanks for your replay..
I am also using VScode and it is not highlighting any error there.
My data for HIRE_DATE is in this format
Strange, usually VSCode should warn you. Try using:
You might need to require/import moment explicitly.
Hi Dennis,
I have imported the moment package and have used the below code.
And i am getting error as below....
This is an error returned by the backend.
As the error suggests, you're trying to filter on a field that is marked as non-filterable by the service. To be fair, the code does not reflect this currently. Short-term, you will either need to filter client-side or think of a different filter condition, if possible. Long-term, you might want to address this to the author of the service to see if filtering on the hireDate can be implemented.
Hi Henning,
Thanks for the great blog!!!
Our new requirement is to consume sandbox Successfactor Onboarding API using Javascript SDK.
Can you please suggest how to generate VDM for this sandbox Successfactor Onboarding API/ any other custom odata services using this approach?
Since VDM for Successfactor Onboarding API is not available in Javascript Documentation https://help.sap.com/doc/9dbcab0600b346c2b359a8c8978a45ba/1.0/en-US/index.html
Thanks in Advance,
Meenakshi
Hi Meenakshi,
you can generate your own client code for OData services using our generator. You can find out how to do that here: https://help.sap.com/doc/9dbcab0600b346c2b359a8c8978a45ba/1.0/en-US/modules/_sap_cloud_sdk_generator.html
If you have further questions, don't hesitate to reach out to us!
Best regards
Dennis
Hi Dennis,
Thanks for your inputs and sorry for the delayed reply.Followed the link you suggested.I got only vdm for ts files but I need vdm files in js too.However my code is in js format.
C:\Project>npm run start:local
> cloud-sdk-starter-app@1.0.0 start:local C:\Project
> npx node src/
internal/modules/cjs/loader.js:638
throw err;
^
Error: Cannot find module ‘@sap/sfo-data-service’
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:636:15)
at Function.Module._load (internal/modules/cjs/loader.js:562:25)
at Module.require (internal/modules/cjs/loader.js:690:17)
at require (internal/modules/cjs/helpers.js:25:18)
at Object.<anonymous> (C:\Project\src\hello-world-route.js:4:16)
at Module._compile (internal/modules/cjs/loader.js:776:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:787:10)
at Module.load (internal/modules/cjs/loader.js:653:32)
at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
at Function.Module._load (internal/modules/cjs/loader.js:585:3)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! cloud-sdk-starter-app@1.0.0 start:local: `npx node src/`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the cloud-sdk-starter-app@1.0.0 start:local script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
Currently, you need to go into the folder you generated in your terminal and call "npx tsc" (tsc is the typescript compiler) to transpile from typescript to javascript.
Up from version 1.6.1 of the generator, which will be available on Thursday, the generate will be default also generate JavaScript files.
Hi Dennis,
Thanks a lot! VDM generated successfully.
Sandbox s/4 hana cloud business partner api has been successfully consumed.Similarly I tried sandbox successfactor api.
Tried the the below three urls.
Getting the below errors.
Error: get request failed!
at Object.errorWithCause (C:\Project\node_modules\@sap\cloud-sdk-util\dist\error.js:14:20)
at specializeError (C:\Project\node_modules\@sap\cloud-sdk-core\dist\request-builder\request\odata-request.js:175:32)
at C:\Project\node_modules\@sap\cloud-sdk-core\dist\request-builder\request\odata-request.js:162:58
at process._tickCallback (internal/process/next_tick.js:68:7)
Caused by:
Error: Request failed with status code 404
at createError (C:\Project\node_modules\axios\lib\core\createError.js:16:15)
at settle (C:\Project\node_modules\axios\lib\core\settle.js:17:12)
at IncomingMessage.handleStreamEnd (C:\Project\node_modules\axios\lib\adapters\http.js:237:11)
at IncomingMessage.emit (events.js:203:15)
at endReadableNT (_stream_readable.js:1129:12)
at process._tickCallback (internal/process/next_tick.js:63:19)
Kindly refer the below code.
Please suggest me some inputs.
Can you please take a look at the service-mapping.json that the generator outputs? there might be something like
servicePath: "VALUE_IS_UNDEFINED"
If this is the case, you will need to enter the service path there (I think for SFSF it's /odata/v2) and then regenerate the code with the --serviceMapping flag pointing to the service-mapping.json.
Hi Dennis,
Thanks a lot!!! Able to retrieve the SF data :))
Just wanted to know that cant we migrate this code to web ide instead of using Command line interface.
I mean complete CLoud SDK Java Script development using Web IDE.
Thanks Again
Meenakshi A N
Glad to hear it worked!
Hi Dennis,
Similarly while generating vdm file for User SF api i am getting the below errors.
SF API:User Management
Link:https://sandbox.api.sap.com/successfactors/odata/v2/User
I have provided edmx file which is taken from Sap api business hub only.
Suggest me how to modify edmx file to solve this error.
TypeError: Cannot read property ‘typeName’ of undefined
at parseReturnType (C:\Project\node_modules\@sap\cloud-sdk-generator\dist\parser\service-parser.js:158:37)
at C:\Project\node_modules\@sap\cloud-sdk-generator\dist\parser\service-parser.js:175:25
at Array.map (<anonymous>)
at transformFunctionImports (C:\Project\node_modules\@sap\cloud-sdk-generator\dist\parser\service-parser.js:169:32)
at transformServiceMetadata (C:\Project\node_modules\@sap\cloud-sdk-generator\dist\parser\service-parser.js:65:27)
at parseService (C:\Project\node_modules\@sap\cloud-sdk-generator\dist\parser\service-parser.js:35:12)
at C:\Project\node_modules\@sap\cloud-sdk-generator\dist\parser\service-parser.js:29:109
at Array.map (<anonymous>)
at Object.parseAllServices (C:\Project\node_modules\@sap\cloud-sdk-generator\dist\parser\service-parser.js:29:83)
at Generator.readServices (C:\Project\node_modules\@sap\cloud-sdk-generator\dist\generator.js:56:33)
Which version of the generator are you using?
Hi Dennis,
Version is 1.5.0
I just tested it, this is a bug in version 1.5.0, but it has already been fixed in version 1.6.1, which will most likely be available on Thursday.
If you really need to proceed now, there is a workaround that may or may not help you. The bug is caused by function imports whose return type is native to OData (e.g. Edm.String vs a self-defined complex type). So if you don't need these specific function imports, you could remove them from the metadata and the generator shouldn't fail anymore.
Hi Dennis,
I tried removing those two functions.VDM got generated.However I am getting the 502 status error while running the application.
Express server listening on port 8080
Error: get request failed!
at Object.errorWithCause (C:\Project\node_modules\@sap\cloud-sdk-util\dist\error.js:14:20)
at specializeError (C:\Project\node_modules\@sap\cloud-sdk-core\dist\request-builder\request\odata-request.js:175:32)
at C:\Project\node_modules\@sap\cloud-sdk-core\dist\request-builder\request\odata-request.js:162:58
at process._tickCallback (internal/process/next_tick.js:68:7)
Caused by:
Error: Request failed with status code 502
at createError (C:\Project\node_modules\axios\lib\core\createError.js:16:15)
at settle (C:\Project\node_modules\axios\lib\core\settle.js:17:12)
at IncomingMessage.handleStreamEnd (C:\Project\node_modules\axios\lib\adapters\http.js:237:11)
at IncomingMessage.emit (events.js:203:15)
at endReadableNT (_stream_readable.js:1129:12)
at process._tickCallback (internal/process/next_tick.js:63:19)
Without any code samples I can only guess, but if you execute a request against the API Hub, try adding something like .top(10) to your request. The API Hub does stupid things if there are too many entities in the response...
Hi Dennis,
You are absolutely right!! After giving top() got the output.:))
Just wanted to one more thing.
How can I add service path to the metadata file.Where can I find service-mapping.json
Glad to hear it worked!
The service-mapping.json is generated into the inputDirectory that you specified for the given run of the generator.
Hi Dennis,
Want to use two SF aPI's.But i am not able to get user related classes when two services are imported at a time.
In the service-mapping.json, there is a key called "directoryName" for each generated service. If you change this and regenerate you're code, it will create folders with the names you specified there, which should solve your import problem.
Side-note: I don't think you'll be able to import anything from "New" in your current approach right now because even thought the folder (read: module) inside of "New", i.e. the one produced by the generator, exports things, the folder (read: module) "New" itself does not export anything.
Hi Dennis,
I am about to deploy my node.js application in to cloud foundry.
But the deployment is unsuccessfull.
Below is the manifest.yml
I have attached error logs too.
Kindly help.Let me know if more information is required.
We generate a package.json for each service (metadata file), and we also put a package name in there. However, you cannot use this name to import from this as long as you don't publish it (which is probably not what you want). I'm guessing somewhere in your code will be line like one of these:
This will not work, since this assumes the code to be present in the node_modules. What you want to do instead is using a relative path in the import that points to whereever your code is generated to, e.g.:
Hi Dennis,
I have changed the line to the folder path where the vdm file is generated.
You're missing the '.' in the beginning. It should be require(“./Project/sfo-data-service”). Path's that start with '/' are interpreted as root of the file system.
Please find my project path:
C:\Project\sfo-data-service
Project->My project name.
sfo-data-service->Name of the vdm folder
Let me put it like this: you do not want to use absolute paths when when importing modules. If you use absolute paths, it will work on your machine and only there, nowhere else. Relative paths make it portable.
In your example, judging from your stack trace you're trying to import from the generated code in hello-world-route.js, which is in src/. Your require call should therefore look like this: require('../sfo-data-service').
For more background on JavaScript modules, this is a good read. But at the end of the day, there's really no magic behind it. If you import code from you're file system, use relative paths.
Thanks :)) It worked..
To find out more about SAP Cloud SDK for Java and JS you can check out our documentation portal.