https://raw.githubusercontent.com/ajmaradiaga/feeds/main/scmt/topics/SAP-Cloud-SDK-blog-posts.xml SAP Community - SAP Cloud SDK 2024-05-20T11:12:30.924411+00:00 python-feedgen SAP Cloud SDK blog posts in SAP Community https://community.sap.com/t5/enterprise-resource-planning-blogs-by-members/customized-project-budgeting-in-sap-business-bydesign/ba-p/13570236 Customized Project Budgeting in SAP Business ByDesign 2023-04-05T15:35:49+02:00 former_member39718 https://community.sap.com/t5/user/viewprofilepage/user-id/39718 <H2 id="toc-hId-963834889"><STRONG><U>Requirement:</U></STRONG></H2><BR /> Customers needs the ability to specify a budget amount at the project level.<BR /> <BR /> When expenses are posted to a project, the system should validate this expense against the project budget amount<BR /> <BR /> If this expense will cause the total incurred expense for the project to exceed the budgeted amount, the system should stop the transaction from being posted and issue an error message or trigger a mail.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/Project-Budgeting-1.png" /></P><BR /> <P class="image_caption" style="text-align:center;font-style:italic;, Arial, sans-serif">Project Budgeting</P><BR /> <BR /> <H2 id="toc-hId-767321384"><STRONG><U>Solution:</U></STRONG></H2><BR /> Build the capability to specify a budget amount at the project level as well as the ability to upload this data from MS Excel. Only an overall budget amount can be specified at the project level<BR /> <H2 id="toc-hId-570807879"><STRONG><U>Design:</U></STRONG></H2><BR /> Budget validation will be provided for the following transactions<BR /> <UL><BR /> <LI><BR /> <H5 id="toc-hId-761542531">Purchase Order</H5><BR /> </LI><BR /> <LI><BR /> <H5 id="toc-hId-565029026">Supplier Invoice</H5><BR /> </LI><BR /> <LI><BR /> <H5 id="toc-hId-368515521">Expense Report</H5><BR /> </LI><BR /> <LI><BR /> <H5 id="toc-hId-172002016">Journal Entry Voucher</H5><BR /> </LI><BR /> </UL><BR /> <H2 id="toc-hId--411759646"><SPAN style="text-decoration: underline"><STRONG>Business</STRONG> <STRONG>Benefits:</STRONG></SPAN></H2><BR /> <UL><BR /> <LI>Hassle free Cloud Solution.</LI><BR /> <LI><SPAN style="font-size: 1rem">Custom reports to track every Project based on Budget.</SPAN></LI><BR /> </UL><BR /> <H2 id="toc-hId--608273151"><STRONG><U>Conclusion:</U></STRONG></H2><BR /> The Solution which describes the Budgeting at Project Level in SAP Business ByDesign<BR /> <H4 id="toc-hId--546621218">Kindly post your questions in&nbsp;<A href="https://answers.sap.com/tags/01200615320800000691" target="_blank" rel="noopener noreferrer">ask a question section</A>&nbsp;and feedback in the below comments section.</H4> 2023-04-05T15:35:49+02:00 https://community.sap.com/t5/technology-blogs-by-members/how-to-calculate-the-difference-between-two-datetime-fields-in-sap-c4c/ba-p/13561604 How to Calculate the Difference Between Two DateTime Fields in SAP C4C 2023-04-06T00:06:39+02:00 former_member625898 https://community.sap.com/t5/user/viewprofilepage/user-id/625898 <DIV><BR /> <BR /> Hello everyone,<BR /> <BR /> In the course of implementing a business requirement, I recently had to calculate the difference between two DateTime fields in SAP C4C for reporting which calculates ticket assignment time from the creation. However, I couldn't find any straightforward blog that provided a simple solution to this problem.<BR /> <BR /> Fortunately, SAP provides a function called Delta() that can be used to calculate the difference between two DateTime fields. The only catch is that Delta() is only accessible for the GlobalDateTime data type.<BR /> <BR /> So, how can you use Delta() for DateTime fields? It's simple - just use the ConvertToGlobalDateTime() function after your DateTime field. This will convert your DateTime field to GlobalDateTime format, allowing you to use Delta().<BR /> <BR /> The result of Delta() is returned in a "Duration" format, which was not convenient for my purposes. To convert the result into minutes or hours, I simply used the ConvertToMinutes() / ConvertToHour() functions, respectively.<BR /> <BR /> Here's a code snippet that demonstrates how to use Delta() to calculate the difference between two DateTime fields:<BR /> <PRE class="language-abap"><CODE>// Creation time in Datetime format.<BR /> var ZV_CreationDateTime = this.RequestInitialReceiptTimePoint.TimePoint.DateTime; <BR /> <BR /> <BR /> //Converting local datetime to global datetime to use standard Delta function.<BR /> var ZV_CreationDateTimeGlobal = Library::DateTime.ConvertToGlobalDateTime(ZV_CreationDateTime);<BR /> <BR /> <BR /> //Ticket reassigned datetime.<BR /> var ZV_AssignedDateTime = Context.GetCurrentGlobalDateTime(); <BR /> <BR /> <BR /> //Calculating the difference between two dates.<BR /> var ZV_DeltaDifference = ZV_AssignedDateTime.Delta(ZV_CreationDateTimeGlobal).ConvertToMinutes();</CODE></PRE><BR /> </DIV><BR /> <DIV></DIV><BR /> <DIV>I hope this solution helps you as much as it helped me. If you have any feedback or questions, please don't hesitate to leave a comment.</DIV><BR /> <DIV></DIV><BR /> <DIV>Links for ref.:<A href="https://help.sap.com/docs/SAP_CLOUD_APPLICATIONS_STUDIO/cbcebe3cfb1647a8b0322c18dbb0b481/729b136f73e21014ae6afa4ef4b79d75.html?q=duration" target="_blank" rel="noopener noreferrer">Duration (Reuse Library)</A></DIV><BR /> <DIV></DIV><BR /> Best regards,<BR /> <BR /> Pratik Shekokar<BR /> <BR /> SAP C4C Technical Consultant 2023-04-06T00:06:39+02:00 https://community.sap.com/t5/technology-blogs-by-members/sap-private-linky-swear-with-azure-enabling-sap-cap-with-azure-services/ba-p/13560179 SAP private linky swear with Azure – enabling SAP CAP with Azure services without OData APIs using SAP Private Link 2023-04-24T13:07:20+02:00 Martin-Pankraz https://community.sap.com/t5/user/viewprofilepage/user-id/143781 <TABLE style="width: 100%;border-collapse: collapse;border-style: solid;background-color: #82b4ff" border="1"><BR /> <TBODY><BR /> <TR><BR /> <TD style="width: 100%"><BR /> <BR /> <SPAN style="color: #ffffff">This post is part of a series sharing service implementation experience and possible applications of SAP Private Link Service on Azure.</SPAN><BR /> <BR /> <SPAN style="color: #ffffff">Find the table of contents and my curated news regarding series updates <A href="https://blogs.sap.com/2021/12/29/getting-started-with-btp-private-link-service-for-azure/" target="_blank" rel="noopener noreferrer">here</A>.</SPAN><BR /> <BR /> <SPAN style="color: #ffffff">Find the associated </SPAN><SPAN style="color: #ffffff">GitHub repos</SPAN>&nbsp;<A href="https://github.com/MartinPankraz/AzCosmosDB-OData-Shim" target="_blank" rel="noopener nofollow noreferrer">here</A> <SPAN style="color: #ffffff">and <A href="https://github.com/MartinPankraz/sap-cap-cosmos-app" target="_blank" rel="nofollow noopener noreferrer">here</A>.</SPAN></TD><BR /> </TR><BR /> </TBODY><BR /> </TABLE><BR /> <SPAN style="font-size: 1rem">Dear community,</SPAN><BR /> <BR /> Continuing with the implementation journey of <A href="https://help.sap.com/docs/PRIVATE_LINK/42acd88cb4134ba2a7d3e0e62c9fe6cf/af86a457ffd84324a6691c6ea1649dd6.html" target="_blank" rel="noopener noreferrer">SAP Private Link Service</A> (PLS) for Azure we will have a closer look at connecting <A href="https://learn.microsoft.com/azure/application-gateway/private-link" target="_blank" rel="nofollow noopener noreferrer">privately</A> to Azure services that don’t have an OData interface today from apps implemented with <A href="https://cap.cloud.sap/docs/" target="_blank" rel="nofollow noopener noreferrer">SAP Cloud Application Programming Model</A> (CAP). You might say that SAP CAP can connect to non-BTP sources via the <A href="https://sap.github.io/cloud-sdk/docs/js/getting-started" target="_blank" rel="nofollow noopener noreferrer">SAP Cloud SDK</A> or custom coding. However, if an OData API is available, it works out of the box and allows for separation of concerns. Multiple BTP apps may use the same interface without the need for each of them to take a dependency on the Azure SDK.<BR /> <BR /> So, why not meet CAP halfway?<BR /> <BR /> We will do so using a <A href="https://github.com/MartinPankraz/AzCosmosDB-OData-Shim" target="_blank" rel="nofollow noopener noreferrer"><STRONG>translator app</STRONG></A> running on <A href="https://learn.microsoft.com/azure/app-service/overview" target="_blank" rel="nofollow noopener noreferrer">Azure App Service</A> in a private virtual network on Azure exposed via SAP Private Link.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/app-service-pls-pinky.png" /></P><BR /> <BR /> <H2 id="toc-hId-962910534">The provided translator app is pre-configured to work with Azure Cosmos DB and Azure Blob storage. Its structure is modular and open for you to add any service you desire.</H2><BR /> Any scenario top of mind already? Reach out via GitHub or <STRONG>leave a note down below</STRONG> under this post.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/app-service-pls-overview-2.png" /></P><BR /> <P style="text-align: center">Fig.1 Architecture overview depicting the protocol translation and the SAP Private Link exposure.</P><BR /> <BR /> <H1 id="toc-hId-637314310">Let’s take a look under the hood</H1><BR /> To replicate the scenario, create a basic private Azure VNet, provision a serverless Azure Cosmos DB for NoSQL instance and windows-based Azure App Service into it. Make sure all resources are in the same region. You may do this via CLI, the Azure portal, bicep, or terraform for instance. See below guidance for the portal-based approach.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/app-service-pls-vnet.png" /></P><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/app-service-pls-cosmos.png" /></P><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/app-service-pls-app.png" /></P><BR /> <P style="text-align: center">Fig.2 Detailed Azure deployment view from the Azure portal</P><BR /> <BR /> <H1 id="toc-hId-440800805">Data setup and integration test</H1><BR /> Before we make everything private and troubleshooting becomes harder (would require private VNet access via <A href="https://learn.microsoft.com/azure/bastion/bastion-overview" target="_blank" rel="nofollow noopener noreferrer">Azure Bastion service</A> for instance or VPN), let’s verify initial integration.<BR /> <BR /> I am using the famous SAP SFlight demo data set on Cosmos as a sample. It is stored in database “saps4” in container “sflight”.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/app-service-pls-database.png" /></P><BR /> <P style="text-align: center">Fig.3 Screenshot of Sflight data set in Data Explorer of Cosmos DB</P><BR /> You may <A href="https://blogs.sap.com/2021/12/09/hey-sap-where-is-my-xbox-an-insight-into-capitalizing-on-event-driven-architectures/" target="_blank" rel="noopener noreferrer">synch the data from SAP</A> or for the sake of quicker getting started generating it using the Cosmos DB Data Explorer with below steps:<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/app-service-pls-chatgpt.png" /></P><BR /> <P style="text-align: center">Fig.4 ChatGPT generated guidance to create SFlight data set in Cosmos DB</P><BR /> <BR /> <PRE class="language-javascript"><CODE>{<BR /> "id": "006",<BR /> "carrid": "AA",<BR /> "connid": "64",<BR /> "fldate": "2016-06-17",<BR /> "planetype": "A310-300",<BR /> "seatsmax": 280,<BR /> "seatsocc": 10<BR /> }</CODE></PRE><BR /> Deploy the code for the translator app via the provided script for convenience:<BR /> <PRE class="language-perl"><CODE>az login<BR /> .\publish.bat [your resource group] [name of above created app service]</CODE></PRE><BR /> <H2 id="toc-hId-373370019">Once finished call the APIs to verify proper setup with public endpoints still.</H2><BR /> Local execution (or from <A href="https://github.com/codespaces/new?hide_repo_select=true&amp;ref=main&amp;repo=364871140" target="_blank" rel="nofollow noopener noreferrer">GitHub Codespaces</A>) is also possible at this point:<BR /> <PRE class="language-perl"><CODE>cd .\GenericODataWebAPI\<BR /> dotnet run</CODE></PRE><BR /> Find a sample call library on the repos <A href="https://github.com/MartinPankraz/AzCosmosDB-OData-Shim/blob/main/sample-http-requests/sflight-requests.http" target="_blank" rel="nofollow noopener noreferrer">here</A>.<BR /> <BR /> Call <A href="http://localhost:52056/api/odata/Sflight" target="_blank" rel="nofollow noopener noreferrer">http://localhost:52056/api/odata/Sflight</A> for the integration test. It should look something like this:<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/app-service-pls-data-test.png" /></P><BR /> <P style="text-align: center">Fig.5 Sflight output from local OData request via translator app</P><BR /> <BR /> <H2 id="toc-hId-176856514">So far so good. Now we will inject all services into our private VNet and prepare the SAP Private Link.</H2><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/app-service-pls-cosmos-private-1.png" /></P><BR /> <P style="text-align: center">Fig.6 Screenshot of Cosmos DB private network setup</P><BR /> Note the associated VNet in above screen and the marked <STRONG>checkbox to retain access</STRONG> to the database via the portal. Believe me been there, done that <span class="lia-unicode-emoji" title=":winking_face:">😉</span><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/app-service-pls-app-private.png" /></P><BR /> <P style="text-align: center">Fig.7 Screenshot of App Service private network setup</P><BR /> Inject the Azure App Service into the same VNet as your Cosmos instance. See above for a reference.<BR /> <H2 id="toc-hId--19656991">Swoosh <span class="lia-unicode-emoji" title=":tornado:">🌪</span>️ At this point you can reach the database only via the App Service! Don’t believe me? Go on and check. Trust is good but verification is better as they say🧐</H2><BR /> Now onwards to the private link. Collect the resource id of your app service either from the properties pane or my favourite option: From the JSON view of the Overview pane.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/app-service-pls-app-id.png" /></P><BR /> <P style="text-align: center">Fig.8 Screenshot of App Service resource id retrieval</P><BR /> Login into your BTP subaccount and create a new instance of SAP Private Link called “<STRONG>odata-proxy-pls</STRONG>” providing the required properties for Azure App Service. See the <A href="https://help.sap.com/docs/PRIVATE_LINK/42acd88cb4134ba2a7d3e0e62c9fe6cf/d5f96f99a9034ce290cf4384b4166255.html" target="_blank" rel="noopener noreferrer">SAP docs</A> for further details.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/app-service-pls-btp-create.png" /></P><BR /> <P style="text-align: center">Fig.9 Screenshot of SAP Private Link create view for Azure App Service</P><BR /> This triggers the connection request on the Azure App Service from your BTP account. Go on hit approve. I will wait <span class="lia-unicode-emoji" title=":hourglass_not_done:">⏳</span><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/app-service-pls-approve.png" /></P><BR /> <P style="text-align: center">Fig.10 Screenshot of SAP Private Link approval in Azure</P><BR /> Done? Ok, great. Now we are ready to deploy our CAP app to “seal” the private link and create the Cloud Foundry service binding.<BR /> <BR /> I provided a <A href="https://github.com/MartinPankraz/sap-cap-cosmos-app" target="_blank" rel="nofollow noopener noreferrer">repos</A> for this purpose. Find more details on how to deploy via Business Application Studio (BAS) or the likes there too. I ran “cf deploy”.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/app-service-pls-mta.png" /></P><BR /> <P style="text-align: center">Fig.11 Screenshot of CAP app config with emphasis on SAP Private Link config</P><BR /> See above the reference on the CAP app binding itself to the SAP Private Link pointing to the Azure App Service.<BR /> <TABLE style="border-collapse: collapse;width: 100%" border="1"><BR /> <TBODY><BR /> <TR><BR /> <TD style="width: 100%;background-color: #ffc978"><EM><STRONG>Be aware</STRONG> that you require an SSH tunnel on BAS for local testing reaching through the private link to Azure. Otherwise only deployed apps have access due to the Cloud Foundry security groups. Find more details </EM><A href="https://blogs.sap.com/2021/10/05/btp-private-linky-swear-with-azure-how-do-i-debug-and-test-with-live-data/" target="_blank" rel="noopener noreferrer"><EM>here</EM></A><EM>.</EM></TD><BR /> </TR><BR /> </TBODY><BR /> </TABLE><BR /> With that we can retrieve the hostname to reach the private link and maintain our destination on BTP.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/app-service-pls-host.png" /></P><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/app-service-pls-dest.png" /></P><BR /> <P style="text-align: center">Fig.12 Screenshot of SAP BTP Destination setup using Private Link</P><BR /> For now, I didn’t put authentication on the App Service but is pre-configured to use Azure AD. Have a look <A href="https://github.com/MartinPankraz/AzCosmosDB-OData-Shim/blob/main/documentation/WHATS-NEXT.md" target="_blank" rel="nofollow noopener noreferrer">here</A>. Once you decided what authentication flow to use adjust the destination above accordingly.<BR /> <BR /> Broke a sweat yet? 🥵<BR /> <H2 id="toc-hId--216170496">Either way you may be glad to hear we are done <span class="lia-unicode-emoji" title=":flexed_biceps:">💪</span>Yes, go on call the CAP app URL and marvel and the privately served data from Cosmos DB as OData stream:</H2><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/app-service-pls-cap.png" /></P><BR /> <P style="text-align: center">Fig.13 Screenshot of SAP CAP app OData output requested from Cosmos DB</P><BR /> Thanks to the translator app we are serving OData from Azure Cosmos DB tapping into the dotnet NoSQL API even though Cosmos DB doesn't have an OData interface for the NoSQL API. And all of that privately!<BR /> <TABLE style="border-collapse: collapse;width: 100%" border="1"><BR /> <TBODY><BR /> <TR><BR /> <TD style="width: 100%;background-color: #ffc978"><BR /> <BR /> Focus of this blog was on advocating for the private link approach and deeper understanding of the setup rather than enterprise scale. However, all <STRONG>steps taken can be accomplished via infrastructure-as-Code</STRONG>. I can highly recommend the <A href="https://learn.microsoft.com/azure/developer/azure-developer-cli/overview" target="_blank" rel="nofollow noopener noreferrer">Azure Developer CLI</A> (AZD). For BTP components consider the <A href="https://github.com/SAP-samples/btp-setup-automator" target="_blank" rel="nofollow noopener noreferrer">BTP Setup Automator</A>.<BR /> <BR /> In addition to that I am considering adding the AZD configuration to the <A href="https://github.com/MartinPankraz/AzCosmosDB-OData-Shim/issues/5" target="_blank" rel="nofollow noopener noreferrer">repos</A> at later point in time. Would appreciate any help from the community!</TD><BR /> </TR><BR /> </TBODY><BR /> </TABLE><BR /> <H1 id="toc-hId--541766720">Thoughts on production readiness</H1><BR /> SAP Private Link is generally available and therefore completely ready for prime time (quoting <SPAN class="mention-scrubbed">gowrisankar.m2</SPAN> from the SAP engineering team <span class="lia-unicode-emoji" title=":smiling_face_with_smiling_eyes:">😊</span>).<BR /> <BR /> Cosmos DB powers critical globally available solutions like <A href="https://customers.microsoft.com/story/821099-next-games-gaming-azure" target="_blank" rel="nofollow noopener noreferrer">NEXT GAMES apps</A> with real-time leader board requirements or the <A href="https://customers.microsoft.com/story/1481264036149964884-deutsche-borse-ag-banking-capital-markets" target="_blank" rel="nofollow noopener noreferrer">data hub</A> of Deutsche Börse AG for instance. For additional stories, have a look at the official <A href="https://customers.microsoft.com/home" target="_blank" rel="nofollow noopener noreferrer">portal</A> or the nice community offering <A href="https://azurecharts.com/stories" target="_blank" rel="nofollow noopener noreferrer">Azure Charts</A>.<BR /> <BR /> Cosmos DB&nbsp;<A href="https://learn.microsoft.com/azure/cosmos-db/nosql/how-to-provision-autoscale-throughput?tabs=api-async" target="_blank" rel="nofollow noopener noreferrer">scales on its own</A>, match that setup for your CF app on BTP where required with the&nbsp;<A href="https://discovery-center.cloud.sap/serviceCatalog/application-autoscaler?service_plan=standard&amp;region=all&amp;commercialModel=cpea&amp;tab=service_plan&amp;provider=azure" target="_blank" rel="nofollow noopener noreferrer">Application Autoscaler</A>.<BR /> <BR /> Azure App Service is a full-blown PaaS offering to run apps, APIs in all major programming languages, with native integration with Azure AD (no need for custom code), Log Analytics, Application Insights, and Key Vault etc. Have a look <A href="https://github.com/Azure-Samples/app-service-javascript-sap-cloud-sdk-quickstart" target="_blank" rel="nofollow noopener noreferrer">here</A> for more goodies. You may even <A href="https://github.com/Azure-Samples/app-service-javascript-sap-cloud-sdk-quickstart" target="_blank" rel="nofollow noopener noreferrer">run the SAP Cloud SDK on App Service</A>.<BR /> <H1 id="toc-hId--738280225">Final Words</H1><BR /> Alrighty, folks! Today we continued our SAP Private Link with Azure journey to the Azure App Service - a <STRONG>match made in tech-heaven</STRONG>! We took a closer look at how to <STRONG>connect privately to Azure services</STRONG> that don’t offer an <STRONG>OData</STRONG> interface today, using a <STRONG>translator app</STRONG> running on the App Service.<BR /> <BR /> The provided <A href="https://github.com/MartinPankraz/AzCosmosDB-OData-Shim" target="_blank" rel="nofollow noopener noreferrer">repos</A> is <STRONG>fully operational to translate to OData for Azure Cosmos DB</STRONG> and has the <STRONG>foundation pre-configured for Azure Blob Storage</STRONG>. You need a different service or prefer to private-link directly sacrificing OData? Let me know in the comments or open an Issue on GitHub or go all-in with a Pull-Request <span class="lia-unicode-emoji" title=":smiling_face_with_smiling_eyes:">😊</span><BR /> <BR /> Till then: sit back, relax, and let's get private linking!<BR /> <BR /> Any comments regarding your individual integration journey with SAP Private Link SAP @Developers and @Architects?<BR /> <BR /> Find the related GitHub repos <A href="https://github.com/MartinPankraz/AzCosmosDB-OData-Shim" target="_blank" rel="nofollow noopener noreferrer">here</A> and <A href="https://github.com/MartinPankraz/sap-cap-cosmos-app" target="_blank" rel="nofollow noopener noreferrer">here</A>.<BR /> <BR /> Find your way back to the aggregator blog post <A href="https://blogs.sap.com/2021/12/29/getting-started-with-btp-private-link-service-for-azure/" target="_blank" rel="noopener noreferrer">here</A>.<BR /> <BR /> As always feel free to ask lots of follow-up questions.<BR /> <BR /> &nbsp;<BR /> <BR /> Best Regards<BR /> <BR /> Martin 2023-04-24T13:07:20+02:00 https://community.sap.com/t5/technology-blogs-by-members/sap-btp-destinations-in-a-nutshell-part-1-motivation-noauthentication/ba-p/13561006 SAP BTP Destinations in a Nutshell Part 1 - Motivation & NoAuthentication Destinations 2023-05-23T22:08:10+02:00 JakobFra https://community.sap.com/t5/user/viewprofilepage/user-id/178619 <H1 id="toc-hId-833856425">Motivation</H1><BR /> <P class="reader-text-block__paragraph">We are in the midst of the age of cloud computing and the change in IT system landscapes and software development projects is both noticeable and irreversible. Large, heavyweight monoliths are no longer in vogue, IT systems are becoming smaller and more distributed, technology stacks more heterogeneous, a development that also no longer stops at the SAP world. In future, the core systems are to be kept clean; instead of Z-tables, the migration-plagued IT professional now prefers to use side-by-side extensions. If the standard functionality of a system does not sufficiently reflect the process reality of a company, additional functionality is provided as independent, small and lean Fiori apps. So far, so good. But of course these extensions do not exist on their own in a vacuum, but should be loosely coupled with other extensions and of course also with the underlying back-end systems in order to achieve a noticeable business benefit across the entire process chain. This sounds simple at first, but is quickly accompanied by hard nuts to crack:</P><BR /> <BR /> <UL><BR /> <LI>As a rule, and ideally, the interfaces of individual systems are not located on the internet with the gates wide open, but only grant entry if the corresponding authentication protocols are meticulously followed and adhered to.</LI><BR /> <LI>Not all systems are operated in the cloud; the older generation of business standard software still prefers to cavort on the company's internal on-premise infrastructure, into which one first has to laboriously dig connection tunnels before even being allowed through to the entry control.</LI><BR /> <LI>In the simpler case, a technical user is sufficient to gain access to an interface, but this is not always sufficient. Sometimes it is necessary for system A to pass the identity of the user initiating an operation to system B so that the operation can continue there for that user. In complex and evolved IT landscapes, the identities of users are often distributed among different identity providers for different systems, which does not necessarily facilitate the transfer of identity information.</LI><BR /> <LI>Communication with another system via an interface usually runs via HTTP, which nevertheless leaves enough leeway for the design of the data transfer, depending on whether it is based on classic REST, OData, GraphQL or gRPC. If you are very lucky (as I was a few months ago in one of my projects), you will still occasionally come across rare examples of the SOAP interface, a protocol from long ago, when XML was still considered the solution to all present and future problems.</LI><BR /> </UL><BR /> <P class="reader-text-block__paragraph">To master at least part of this challenge, SAP Business Technology Platform offers so-called destinations. Destinations are used to configure connection information and to simplify the handling of individual communication steps and outsource them to a destination service. The main focus here is on the respective mechanisms for authentication. There is already a lot of official documentation on Destinations on the Internet, as well as many great blog articles and other community contributions that help to familiarise oneself with the cosmos of SAP BTP Destinations. Nevertheless, in my day-to-day work with developers and architects, I notice that there is often a lack of clarity about how destinations are to be used and which destination type is suitable for the respective integration scenarios. What I personally have often lacked in my research over the past years were tangible and touchable examples. This motivated me to create a GitHub repository in which I gradually provide examples for the different destination types, supplementing them with text contributions in which I describe the use cases for which the respective destination type is suitable. I also provide some background information on what goes on behind the scenes of such a destination.</P><BR /> <BR /> <H1 id="toc-hId-637342920">Prerequisites</H1><BR /> <P class="reader-text-block__paragraph">In order to try out the examples in the repository, you should have some basic experience in working with the SAP BTP Cloud Foundry environment. Knowledge of node / npm / JavaScript is also definitely an advantage. All examples are built with SAP CAP with Node.js and use Multi Target Applications (MTA) for deployment. To build and deploy the examples you will need in any case:</P><BR /> <BR /> <UL><BR /> <LI>Access to an SAP Business Technology Platform subscription with an activated Cloud Foundry environment and a corresponding Cloud Foundry space, e.g. with a&nbsp;<A href="https://developers.sap.com/tutorials/hcp-create-trial-account.html" target="_blank" rel="noopener noreferrer">SAP BTP Trial account</A></LI><BR /> <LI><A href="https://docs.npmjs.com/downloading-and-installing-node-js-and-npm#using-a-node-version-manager-to-install-nodejs-and-npm" target="_blank" rel="nofollow noopener noreferrer">node and npm</A></LI><BR /> <LI><A href="https://docs.cloudfoundry.org/cf-cli/install-go-cli.html" target="_blank" rel="nofollow noopener noreferrer">Cloud Foundry CLI</A></LI><BR /> <LI><A href="https://help.sap.com/docs/HANA_CLOUD_DATABASE/c2b99f19e9264c4d9ae9221b22f6f589/1412120094534a23b1a894bc498c2767.html#download-and-install-the-mta-build-tool" target="_blank" rel="noopener noreferrer">MTA Build Tool (MBT) CLI</A></LI><BR /> </UL><BR /> <P class="reader-text-block__paragraph">For each destination type there is a separate branch with a README file describing how to deploy client and server on Cloud Foundry and how to test the connection between client and server.</P><BR /> <BR /> <H1 id="toc-hId-440829415">Cloud 2 Cloud - NoAuthentication</H1><BR /> <A href="https://github.com/jfranken/sap-btp-destinations/tree/cloud-2-cloud-no-authentication" target="_blank" rel="nofollow noopener noreferrer">https://github.com/jfranken/sap-btp-destinations/tree/cloud-2-cloud-no-authentication</A><BR /> <BR /> To make the introduction pleasant, I start at a very low level with the simplest conceivable integration scenario: System A (client) communicates with System B (server) via HTTP over the internet, the interface of System B is openly available and does not require any authentication. A classic use case for this is the consumption of a public API.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/05/Bildschirmfoto-2023-05-21-um-12.14.45-1.png" /></P><BR /> The repo contains two SAP CAP applications,&nbsp;<EM>client</EM>&nbsp;and&nbsp;<EM>server</EM>. The magic here takes place in the&nbsp;<EM>client-service.js</EM>&nbsp;file. Two service endpoints are defined in the&nbsp;<EM>client-service.cds</EM>&nbsp;file, both of which call a Hello Word endpoint of the server app, one using the Cloud SDK, one using step-by-step direct communication with the destination service, to better illustrate what happens behind the scenes in the Cloud SDK.<BR /> <H2 id="toc-hId-373398629">Cloud SDK</H2><BR /> <PRE class="language-javascript"><CODE>srv.on('helloWorldClientCloudSDK', async () =&gt; <BR /> return executeHttpRequest({ destinationName: 'Server' })<BR /> .then((response) =&gt; response.data)<BR /> })</CODE></PRE><BR /> <H2 id="toc-hId-176885124">Plain</H2><BR /> <PRE class="language-javascript"><CODE>const { executeHttpRequest } = require('@sap-cloud-sdk/http-client'<BR /> const axios = require('axios')<BR /> <BR /> <BR /> module.exports = async (srv) =&gt; {<BR /> srv.on('helloWorldClientPlain', async () =&gt; {<BR /> // get all the necessary destination service parameters <BR /> // from the service binding in the VCAP_SERVICES env variable<BR /> const vcapServices = JSON.parse(process.env.VCAP_SERVICES)<BR /> const destinationServiceUrl =<BR /> vcapServices.destination[0].credentials.uri +<BR /> '/destination-configuration/v1/destinations/'<BR /> const destinationServiceClientId =<BR /> vcapServices.destination[0].credentials.clientid<BR /> const destinationServiceClientSecret =<BR /> vcapServices.destination[0].credentials.clientsecret<BR /> const destinationServiceTokenUrl =<BR /> vcapServices.destination[0].credentials.url +<BR /> '/oauth/token?grant_type=client_credentials'<BR /> <BR /> <BR /> // before we can fetch the destination from the <BR /> // destination service, we need to retrieve an auth token<BR /> const token = await axios.post(destinationServiceTokenUrl, null, {<BR /> headers: {<BR /> authorization:<BR /> 'Basic ' +<BR /> Buffer.from(<BR /> `${destinationServiceClientId}:${destinationServiceClientSecret}`<BR /> ).toString('base64'),<BR /> },<BR /> })<BR /> const destinationServiceToken = token.data.access_token<BR /> <BR /> <BR /> // with this token, we can now request the <BR /> // "Server" destination from the destination service<BR /> const headers = {<BR /> authorization: 'Bearer ' + destinationServiceToken,<BR /> }<BR /> const destinationResult = await axios.get(<BR /> destinationServiceUrl + 'Server',<BR /> {<BR /> headers,<BR /> }<BR /> )<BR /> const destination = destinationResult.data<BR /> <BR /> <BR /> // now, we use the retrieved the destination <BR /> // information to send a HTTP request to the server endpoint<BR /> const destinationResponse = await axios.get(<BR /> destination.destinationConfiguration.URL<BR /> )<BR /> return destinationResponse.data<BR /> })<BR /> srv.on('helloWorldClientCloudSDK', async () =&gt; {<BR /> return executeHttpRequest({ destinationName: 'Server' })<BR /> .then((response) =&gt; response.data)<BR /> })<BR /> })</CODE></PRE><BR /> The result is expected to be the same for both endpoints:<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/05/Bildschirmfoto-2023-05-21-um-10.55.19.png" /></P><BR /> <P class="reader-text-block__paragraph">This example is far from passing for rocket science. But don't worry - in terms of complexity, it is guaranteed to increase in the coming parts of this series!</P><BR /> <P class="reader-text-block__paragraph">What are your experiences with destinations in SAP BTP so far? Which integration scenarios have you already had to deal with? What were the biggest challenges? If you have any suggestions or improvement requests, or if something doesn't work as you hoped, please let me know. It is my wish and goal to continuously expand and improve this repository, and for that I depend on your feedback from the SAP BTP community! <span class="lia-unicode-emoji" title=":slightly_smiling_face:">🙂</span></P><BR /> <BR /> <H1 id="toc-hId--148711100">Disclaimer</H1><BR /> The code examples provided are&nbsp;<STRONG>not suitable</STRONG>&nbsp;to be transferred 1:1 into productive implementations, but they only serve to illustrate the functioning of destinations and Destination Service. In some cases, the interaction with the Destination Service is deliberately implemented in a "cumbersome" manner in order to illustrate the communication processes as explicitly and in detail as possible. SAP CAP and the SAP Cloud SDK provide various functionality to simplify and abstract the use of destinations. However, this would be more of a hindrance than a benefit to the purpose of the illustration. 2023-05-23T22:08:10+02:00 https://community.sap.com/t5/technology-blogs-by-members/sap-btp-destinations-in-a-nutshell-part-2-basic-authentication/ba-p/13569516 SAP BTP Destinations in a Nutshell Part 2 – Basic Authentication 2023-06-01T13:14:42+02:00 JakobFra https://community.sap.com/t5/user/viewprofilepage/user-id/178619 <H1 id="toc-hId-834099589">Introduction</H1><BR /> This series is about taking a closer look at the different destination types of the SAP BTP Cloud Foundry environment and making them more tangible with executable code examples. In the <A href="https://blogs.sap.com/2023/05/23/sap-btp-destinations-in-a-nutshell-part-1-motivation-noauthentication-destinations/" target="_blank" rel="noopener noreferrer">first part</A>, we addressed the underlying motivation and started with the easiest scenario for an easy-to-digest introduction: two SAP CAP applications deployed in the Cloud Foundry environment in the same space communicate with each other via Internet / HTTP without requiring authentication in any way. Such scenarios are of course very pleasant and thankful from a developer's point of view, however, they are only practical in the rarest of cases. Sensitive and confidential data is almost always involved, and then it must be ensured that only trusted parties can access corresponding interfaces. We will therefore take the first step in this direction in the second part of this series, which deals with destinations for what is probably the simplest type of authentication: System A (client) communicates with System B (server) via the Internet / HTTP and sends an Basic Authentication header with each request, since the server would otherwise reject the request in a friendly but firm manner.<BR /> <H1 id="toc-hId-637586084">Basic Authentication</H1><BR /> Before we look into the actual code example, let's briefly review the theory behind Basic Authentication. Basic Authentication is a method by which a client sends username and password to a server with an HTTP request for authentication purposes. The server uses this information to verify whether or not the client is authorized to make this request based on correctly supplied authentication information. Basic Authentication is stateless, i.e. the Basic Authentication header needs to be send again with every request.<BR /> <BR /> The user data is sent as an HTTP request header with the Authorization header key. The value here is a Base64 encoded string with the format <EM>username:password</EM>, together with the prefix <EM>Basic</EM>. Example:<BR /> <BR /> <EM>Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ</EM><BR /> <BR /> Important: even if the cryptic appearance may suggest it, Base64 is only suitable for encoding, not for encryption! <span class="lia-unicode-emoji" title=":winking_face:">😉</span><BR /> <BR /> Basic Authentication is particularly suitable for server-side authentication for a service using a technical user. Basic authentication via an application that runs on the client side, e.g., in the web browser, should be avoided. Since this requires the unencrypted password, there is a high risk that attackers will succeed in stealing the data and thus gaining unauthorized access to the service. Since credentials are transmitted unencrypted using this method, it should be ensured in any case that communication takes place encrypted via HTTPS to prevent data loss through man-in-the-middle attacks. If a generic technical user is not sufficient for authentication, but a real personal user is required, Basic Authentication is also not the means of choice, because then the disadvantage is that the server side receives not only the username but also the password in plain text and the user has no control over how this sensitive information is further processed. In this case, a token-based protocol such as OAuth2 should be used. We will look at this in detail in later parts of this series.<BR /> <H1 id="toc-hId-441072579">Cloud 2 Cloud – Basic Authentication</H1><BR /> <A href="https://github.com/jfranken/sap-btp-destinations/tree/cloud-2-cloud-basic-authentication" target="_blank" rel="nofollow noopener noreferrer">https://github.com/jfranken/sap-btp-destinations/tree/cloud-2-cloud-basic-authentication</A><BR /> <BR /> The underlying architecture of the Basic Authentication Destinations example is almost identical to the architecture of the No Authentication example. Two SAP CAP applications, client and server, are deployed in the same Cloud Foundry space. A destination to the server is stored in the destination service, the client application reads the detailed information about this destination via HTTP request to the destination service. In order to be able to execute this request successfully, an access token must first be requested via the platform UAA, and this token must then be sent to the destination service in the request. To obtain a token, the client ID and client secret of the destination service are sent to the platform UAA; basic authentication is also used here.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/05/Bildschirmfoto-2023-05-29-um-17.34.07.png" /></P><BR /> The complete communication flow is shown in the diagram below:<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/05/Bildschirmfoto-2023-05-30-um-14.05.15.png" height="396" width="722" /></P><BR /> For a better illustration, the complete response of the Destination Service is also shown here. As you can see, it not only contains the destination configuration, but also a kitchen-ready AuthToken that contains the Base64-encoded username-password pair:<BR /> <PRE class="language-javascript"><CODE>{<BR /> "owner": {<BR /> "SubaccountId": "00000000-0000-0000-0000-000000000000",<BR /> "InstanceId": "00000000-0000-0000-0000-000000000000"<BR /> },<BR /> "destinationConfiguration": {<BR /> "Name": "Server",<BR /> "Type": "HTTP",<BR /> "URL": "https://00000000trial-dev-server.cfapps.0000-000.hana.ondemand.com/server/helloWorldServer()",<BR /> "Authentication": "BasicAuthentication",<BR /> "ProxyType": "Internet",<BR /> "User": "myUsername",<BR /> "Password": "superStrongPassword"<BR /> },<BR /> "authTokens": [<BR /> {<BR /> "type": "Basic",<BR /> "value": "bXlVc2VybmFtZTpzdXBlclN0cm9uZ1Bhc3N3b3Jk",<BR /> "http_header": {<BR /> "key": "Authorization",<BR /> "value": "Basic bXlVc2VybmFtZTpzdXBlclN0cm9uZ1Bhc3N3b3Jk"<BR /> }<BR /> }<BR /> ]<BR /> }</CODE></PRE><BR /> <H2 id="toc-hId-373641793">Client Implementation</H2><BR /> As in the first part of the series, the client includes two alternative implementations. On the one hand, the server call via Cloud SDK, and on the other hand, a plain variant that illustrates the communication processes step by step.<BR /> <H3 id="toc-hId-306211007">Cloud SDK</H3><BR /> <PRE class="language-javascript"><CODE>srv.on('helloWorldClientCloudSDK', async () =&gt; {<BR /> return executeHttpRequest({ destinationName: 'Server' })<BR /> .then((response) =&gt; response.data)<BR /> })</CODE></PRE><BR /> <H3 id="toc-hId-109697502">Plain</H3><BR /> <PRE class="language-javascript"><CODE>srv.on('helloWorldClientPlain', async () =&gt; {<BR /> // ...<BR /> // fetching token for destination service and reading<BR /> // destination from destination service is handled<BR /> // in the same way as in part 1 of this series<BR /> // ...<BR /> const destinationResponse = await axios.get(<BR /> destination.destinationConfiguration.URL, {<BR /> headers: {<BR /> // alternatively, you can also read the already<BR /> // encoded value from destination.authTokens[0].value<BR /> Authorization: 'Basic ' + <BR /> btoa(<BR /> destination.destinationConfiguration.User + <BR /> ':' + <BR /> destination.destinationConfiguration.Password<BR /> ),<BR /> },<BR /> }<BR /> )<BR /> return destinationResponse.data<BR /> }</CODE></PRE><BR /> <H2 id="toc-hId--215898722">Server Implementation</H2><BR /> The server implementation is kept relatively simple, and despite the disclaimer at the end of this chapter, I explicitly point out once again: this implementation presented here is <STRONG>not suitable</STRONG> for productive use!<BR /> <BR /> When the request arrives, the server reads the authorization header, decodes username and password and checks if they match the expected values. If yes, the already known response "Hello World from Server" is returned. Otherwise, the string "Unauthorized" is used to indicate that the credentials are not correct.<BR /> <PRE class="language-javascript"><CODE>module.exports = async (srv) =&gt; {<BR /> srv.on('helloWorldServer', async (req) =&gt; {<BR /> const authHeader = req.headers.authorization<BR /> if (authHeader.indexOf('Basic ') === 0) {<BR /> const username = atob(authHeader.split(' ')[1]).split(':')[0]<BR /> const password = atob(authHeader.split(' ')[1]).split(':')[1]<BR /> if (username === 'myUsername' &amp;&amp; password === 'superStrongPassword') {<BR /> return 'Hello World from Server'<BR /> }<BR /> }<BR /> return 'Unauthorized'<BR /> })<BR /> }<BR /> </CODE></PRE><BR /> <H2 id="toc-hId--412412227">Execution</H2><BR /> Once the client and server are deployed and the destination is configured correctly, calls to both client endpoints should return the following result:<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/05/Bildschirmfoto-2023-05-21-um-10.55.19-1.png" /></P><BR /> The moment has come for us to give ourselves a quick appreciative pat on the back. We have implemented a server that is secured by a technical user and that our client can access with an appropriately configured destination. This is still quite "basic", but admittedly the name of this authentication type doesn't promise more. In the next part of the series we will deal with the OAuth2 client credential flow (OAuth2ClientCredentials). While we are still on the level of technical users, the following parts will then deal with the question of how the identity of a real end user can be passed on from the client to the server, where we will distinguish between two different scenarios:<BR /> <OL><BR /> <LI>Client and server are deployed within the same subaccount (OAuth2UserTokenExchange).</LI><BR /> <LI>Client and server are deployed in different subaccounts (or even different global accounts) (OAuth2SAMLBearerAssertion)</LI><BR /> </OL><BR /> Until then, have fun trying it out and as always, I'm looking forward to your feedback! <span class="lia-unicode-emoji" title=":slightly_smiling_face:">🙂</span><BR /> <H1 id="toc-hId--738008451">Disclaimer</H1><BR /> The code examples provided are not suitable to be transferred 1:1 into productive implementations, but they only serve to illustrate the functioning of destinations and Destination Service. In some cases, the interaction with the Destination Service is deliberately implemented in a “cumbersome” manner in order to illustrate the communication processes as explicitly and in detail as possible. SAP CAP and the SAP Cloud SDK provide various functionality to simplify and abstract the use of destinations. However, this would be more of a hindrance than a benefit to the purpose of the illustration. 2023-06-01T13:14:42+02:00 https://community.sap.com/t5/technology-blogs-by-members/why-the-typescript-sheriff-has-come-to-clean-up-your-javascript-part-1-of-3/ba-p/13550500 Why the TypeScript Sheriff has come to clean up your JavaScript (Part 1 of 3) 2023-07-05T18:26:31+02:00 MikeDoyle https://community.sap.com/t5/user/viewprofilepage/user-id/13892 <STRONG>TLDR</STRONG>: TypeScript simply adds types to JavaScript.&nbsp; We can reduce run-time errors by catching more bugs at design-time. It doesn't ruin the flexibility and expressiveness of JavaScript and it's easy to start using TypeScript in your SAP development today.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/07/cactus2.png" height="100" width="70" /></P><BR /> JavaScript is one of the most important programming languages. In the 2023 Stack Overflow developer survey it was listed as&nbsp;<EM>the&nbsp;</EM><A href="https://survey.stackoverflow.co/2023/#most-popular-technologies-language-prof" target="_blank" rel="nofollow noopener noreferrer">most commonly used language amongst professional developers</A>.&nbsp; &nbsp;I enjoy using JavaScript because I find it's flexibility is conducive to good '<A href="https://www.bbc.com/worklife/article/20190204-how-to-find-your-flow-state-to-be-peak-creative" target="_blank" rel="nofollow noopener noreferrer">flow</A>'. It's easy for me to 'express myself' as I write.<BR /> <BR /> It's also pervasive because it runs almost everywhere. Every modern browser has a JavaScript runtime, but of course it can <A href="https://nodejs.org/" target="_blank" rel="nofollow noopener noreferrer">run on servers</A> too.<BR /> <BR /> A downside of the <EM>dynamic</EM> typing inherent in JavaScript (as opposed to the <EM>static</EM> typing of Java, for example) is that it's easy for type-related bugs to slip through the net and materialise as run-time errors.<BR /> <BR /> What if there was a way to catch these bugs at design-time, without spoiling the expressiveness and flexibility of JavaScript? Such a tool would have a big potential to change the world, because of the near-ubiquity of JavaScript . Happily there is such a tool, and it goes by the name of <A href="https://www.typescriptlang.org/" target="_blank" rel="nofollow noopener noreferrer"><STRONG>TypeScript</STRONG></A>.<BR /> <BR /> In this short series I would like to introduce you to TypeScript and explain how it can improve your JavaScript development.&nbsp; I will focus on the SAP ecosystem and I hope to share the perspective of a new convert, not an expert (because I am not a TypeScript expert).<BR /> <BR /> To learn more we must head to the 'old west' where we will meet the TypeScript Sheriff.&nbsp; He's tough on type errors but don't worry for your safety.&nbsp; As long as you aren't a cowboy coder you have nothing to fear...<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/07/Scene4.jpeg" height="275" width="460" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">The TypeScript Sheriff</P><BR /> <BR /> <H3 id="toc-hId-1091073350">Why TypeScript?</H3><BR /> The easiest way to explain&nbsp;<EM>why&nbsp;</EM>TypeScript exists is to consider a simple example. Here we scaffold a function to book a ticket on a stagecoach, then we call the function to book a seat from San Francisco to Boulder City<BR /> <PRE class="language-javascript"><CODE>function stagecoachBook(startPoint, endPoint, date) {<BR /> //logic here<BR /> }<BR /> <BR /> stagecoachBook(new Date("1860-06-17T00:00:00"), "San Francisco", "Boulder City");<BR /> </CODE></PRE><BR /> This JavaScript code looks good, but when we run it what will happen? A run-time error!&nbsp; Whilst we have the correct number of parameters, they aren't in the right order.&nbsp; Many <A href="https://www.freecodecamp.org/news/what-is-an-ide-in-programming-an-ide-definition-for-developers/" target="_blank" rel="nofollow noopener noreferrer">IDEs</A> (&amp; <A href="https://www.freecodecamp.org/news/what-is-linting-and-how-can-it-save-you-time/" target="_blank" rel="nofollow noopener noreferrer">linters</A>) won't pick this up.&nbsp; It might be easy enough to find the bug (depending on our test coverage) but what if the mistake is in a obscure piece of code that only runs in exceptional circumstances?<BR /> <BR /> Far better to introduce static types, as in this TypeScript example below.&nbsp; Now we specify the types of the function parameters<BR /> <PRE class="language-javascript"><CODE>function stagecoachBook(startPoint: string, endpoint: string, date: Date) {<BR /> //logic here<BR /> }<BR /> <BR /> stagecoachBook(new Date("1860-06-17T00:00:00"), "San Francisco", "Boulder City");<BR /> </CODE></PRE><BR /> The IDE will give us an error like this:<BR /> <BLOCKQUOTE><SPAN style="color: #ff0000"><B>Argument of type 'Date' is not assignable to parameter of type 'string'.</B></SPAN></BLOCKQUOTE><BR /> So much better to find our error at design-time! Other common type errors prevented are typos in function names and assignments to constants (using <EM>const</EM> when you should have used <EM>let</EM>).<BR /> <BR /> Zooming up from the desert weeds to a wider vista it should be obvious that the advantages are more than just avoiding the errors shown in these simple examples.&nbsp; Explicitly declaring types makes code easier to read. In larger codebases it makes life much easier if consumers of library functions can see exactly what parameters they should pass.<BR /> <BR /> Another big advantage is that including types enables the IDE to support code completion, which makes us more productive. Imagine if you have an entity with a large number of properties. How great to have code completion on those property names.<BR /> <BR /> Do you think TypeScript might assist you in your JavaScript programming?&nbsp; Would you like to reduce the number of runtime errors you have to remediate?&nbsp; If so <STRONG>move on to <A href="https://blogs.sap.com/2023/07/05/typescript-sheriff-how-can-i-use-typescript-in-the-sap-ecosystem/" target="_blank" rel="noopener noreferrer">Part 2</A> in the series</STRONG>, in which we will discuss how to use TypeScript in the SAP ecosystem. <STRONG><A href="https://blogs.sap.com/2023/07/05/typescript-sheriff-tips-for-newbies-part-3-of-3/" target="_blank" rel="noopener noreferrer">Part 3</A> will cover some tips</STRONG> to help you get started.<BR /> <BR /> &nbsp;<BR /> <BR /> &nbsp;<BR /> <BR /> &nbsp;<BR /> <BR /> &nbsp;<BR /> <BR /> &nbsp; 2023-07-05T18:26:31+02:00 https://community.sap.com/t5/technology-blogs-by-members/typescript-sheriff-how-can-i-use-typescript-in-the-sap-ecosystem-part-2-of/ba-p/13550830 TypeScript Sheriff: How can I use TypeScript in the SAP ecosystem? (Part 2 of 3) 2023-07-05T18:30:19+02:00 MikeDoyle https://community.sap.com/t5/user/viewprofilepage/user-id/13892 <STRONG>TLDR</STRONG>: TypeScript is nothing more than JavaScript plus types. TypeScript files with a .ts extension are transpiled to plain JavaScript files with a .js extension, so that they will be understood by a JavaScript runtime. We can use TypeScript wherever we can use JavaScript, and it's well supported in the SAP ecosystem.<BR /> <BR /> Now that we have covered <EM>why</EM> we use TypeScript (<STRONG>see <A href="https://blogs.sap.com/2023/07/05/why-the-typescript-sheriff-has-come-to-clean-up-your-javascript-part-1-of-3/" target="_blank" rel="noopener noreferrer">Part 1</A></STRONG>), lets move on to explaining what it is and how we can use it.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/07/TS-Badge-2.png" height="100" width="110" /></P><BR /> <BR /> <H3 id="toc-hId-1091076326">What is TypeScript?</H3><BR /> As explained in the <A href="https://www.typescriptlang.org/" target="_blank" rel="nofollow noopener noreferrer">documentation</A>, TypeScript is simply JavaScript plus types.&nbsp; All of JavaScript is in TypeScript.&nbsp; If you are familiar with JavaScript then you will be instantly familiar with TypeScript.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/07/Screenshot-2023-07-02-at-7.59.36-am.png" height="226" width="436" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">TypeScript is JavaScript plus types</P><BR /> <BR /> <H3 id="toc-hId-894562821">How does TypeScript work?</H3><BR /> If you have built front-end apps using JavaScript (e.g. SAP UI5) you will be familiar with <A href="https://developer.mozilla.org/en-US/docs/Glossary/Minification" target="_blank" rel="nofollow noopener noreferrer">minifying</A> your code. The code we write gets transformed before it runs in the browser. This is just for performance reasons (to speed download). Variable names are shortened, whitespace is removed and files are combined.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/07/Screenshot-2023-07-03-at-6.02.31-am.png" height="164" width="271" /></P><BR /> With TypeScript we just add a predecessor step. The code we write gets <A href="https://dev.to/kealanparr/compiling-vs-transpiling-3h9i" target="_blank" rel="nofollow noopener noreferrer">transpiled</A> by the TypeScript compiler before minification. The types, which the runtime doesn’t understand, are removed.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/07/Screenshot-2023-07-03-at-6.10.13-am.png" height="284" width="504" /></P><BR /> In the example above we've added types to the function signature.&nbsp; We've made it clear that the arguments passed in must be of type string/string/Date (see inside parenthesis) and that a string will be returned (see immediately following parenthesis).<BR /> <BR /> As you can see from the diagram, TypeScript files are distinguished by the extension .<EM>ts</EM> (rather than <EM>.js</EM>).&nbsp; If you open these files they will look just like JavaScript, apart from the types you find here and there.&nbsp; The transpilation step transforms .ts files to .js files, removing the types.&nbsp; It is the .js files which can be interpreted by the JavaScript runtime.<BR /> <BR /> Happily, when testing we can still debug the original TypeScript source code (.ts), because these files are still available (to the client browser) for download when in debug mode.<BR /> <BR /> NB this example is for front-end code. With back-end code (e.g. with Node.js running on the server) we don’t need the minification step because the code doesn't need to be downloaded to a client.<BR /> <H3 id="toc-hId-698049316">Where can we use TypeScript in an SAP context?</H3><BR /> Consider the following scenario.&nbsp; We are extending the standard functionality of our S/4HANA system.&nbsp; We are using <A href="https://community.sap.com/topics/business-technology-platform" target="_blank">SAP BTP</A> to build a side-by-side extension because we want to keep our 'core clean' and enable easy upgrades of S/4HANA.<BR /> <BR /> Where can we use TypeScript in this scenario? Everywhere of course!&nbsp; Out of the box we get TypeScript support from<BR /> <UL><BR /> <LI>The <A href="https://cap.cloud.sap/docs/" target="_blank" rel="nofollow noopener noreferrer">SAP Cloud Application Programming Model</A> (a.k.a. CAP) which we can use to provision OData services for the back-end of our application</LI><BR /> <LI><A href="https://sapui5.hana.ondemand.com/" target="_blank" rel="nofollow noopener noreferrer">SAP UI5</A>, which we can use to build the user interface for the front-end of our application (consuming the CAP services)</LI><BR /> <LI>The <A href="https://sap.github.io/cloud-sdk/docs/js/overview" target="_blank" rel="nofollow noopener noreferrer">SAP Cloud SDK</A> which makes it easy for us to consume external services (APIs), such as those provided by S/4HANA</LI><BR /> </UL><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/07/Screenshot-2023-07-03-at-6.42.01-am.png" /></P><BR /> At the time of writing these frameworks differ slightly in the level of support they provide for TypeScript. The Cloud SDK, for example, already generates OData Clients in TypeScript form (.ts files) by default. UI5 provides types for controls and modules and the tooling supports TypeScript too.<BR /> <BR /> CAP does provide standard types (e.g. for <EM>Request</EM>) and generating types for the OData services you create is a new feature (see <A href="https://www.npmjs.com/package/@cap-js/cds-typer" target="_blank" rel="nofollow noopener noreferrer">@cap-js/cds-typer</A>). It's aimed at those using JavaScript (not TypeScript) and in its current form there are some compatibility issues with TypeScript (running cds-ts commands can overwrite the files generated by <EM>cds-typer)</EM>. I would prefer that <EM>cds-typer&nbsp;</EM>would support TypeScript so that we can simply say 'the SAP BTP stack has full TypeScript support' without need of caveats.<BR /> <BR /> NB I have shown an SAP-only stack here, but of course I could use non-SAP tools and frameworks too.&nbsp; For example I could build the front-end with <A href="https://react.dev/" target="_blank" rel="nofollow noopener noreferrer">React</A> <A href="https://www.typescriptlang.org/docs/handbook/react.html" target="_blank" rel="nofollow noopener noreferrer">and use TypeScript</A> with that.<BR /> <H3 id="toc-hId-501535811">Where can I find all the information I need to get started?</H3><BR /> The <A href="http://www.typescriptlang.org" target="_blank" rel="nofollow noopener noreferrer">official TypeScript documentation</A> is a great place to begin your learning. It's comprehensive, gives a good introduction and can serve as a reference once you get going.<BR /> <BR /> For UI5 there is a central <A href="http://sap.github.io/ui5-typescript/" target="_blank" rel="nofollow noopener noreferrer">UI5 vs. TypeScript</A> page. I also recommend Peter Muessig's blog <A href="https://blogs.sap.com/2021/07/01/getting-started-with-typescript-for-ui5-application-development/" target="_blank" rel="noopener noreferrer">Getting Started with TypeScript for UI5 Application Development</A> as an introduction.<BR /> <BR /> <SPAN class="mention-scrubbed">andreas.kunz</SPAN> has put together a comprehensive <A href="https://github.com/SAP-samples/ui5-typescript-tutorial" target="_blank" rel="nofollow noopener noreferrer">UI5 TypeScript Tutorial</A> based on a recent workshop at UI5Con.&nbsp; See also the <A href="https://t.co/8DDxUnORIh" target="_blank" rel="nofollow noopener noreferrer">video presentation.</A><BR /> <BR /> See <A href="https://cap.cloud.sap/docs/node.js/typescript#using-typescript" target="_blank" rel="nofollow noopener noreferrer">Using TypeScript</A> for the lowdown on using TypeScript with CAP.<BR /> <BR /> There isn't a specific page in the SAP Cloud SDK on using TypeScript (that I can find), however support is good and TypeScript is referenced across the documentation.<BR /> <BR /> SAP have created a <A href="http://github.com/SAP-samples/btp-full-stack-typescript-app" target="_blank" rel="nofollow noopener noreferrer">full-stack reference app</A> that uses TypeScript.&nbsp; I found it very useful to see what a working TypeScript app looks like.<BR /> <BR /> Andreas Kunz has investigated the easiest ways to generate types from OData metadata in his blog post <A href="https://blogs.sap.com/2023/04/13/ui5-and-typescript-how-to-generate-types-for-odata-services/" target="_blank" rel="noopener noreferrer">UI5 and TypeScript: how to generate types for OData services</A>. If you have entities in your services with a non-trivial number of properties then you might want to generate <A href="https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#interfaces" target="_blank" rel="nofollow noopener noreferrer">interfaces</A> to use in your code (rather than just creating them manually), and CAP doesn't currently do this for you.<BR /> <BR /> <STRONG>Now read <A href="https://blogs.sap.com/2023/07/05/typescript-sheriff-tips-for-newbies-part-3-of-3/" target="_blank" rel="noopener noreferrer">Part 3</A> of this series, to get some tips to help you get started with TypeScript.</STRONG><BR /> <BR /> So, be a good citizen and use types with your JavaScript. That way you can stay on side with the TypeScript Sheriff...<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/07/Scene4-1.jpeg" height="236" width="395" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic;font-family: 'SAPRegular', 'Helvetica Neue', Arial, sans-serif">The TypeScript Sheriff</P> 2023-07-05T18:30:19+02:00 https://community.sap.com/t5/technology-blogs-by-members/typescript-sheriff-tips-for-newbies-part-3-of-3/ba-p/13552828 TypeScript Sheriff: Tips for newbies (Part 3 of 3) 2023-07-05T18:31:48+02:00 MikeDoyle https://community.sap.com/t5/user/viewprofilepage/user-id/13892 <STRONG>TLDR:&nbsp;</STRONG>We <EM>can</EM> use TypeScript types in every line of our code, but that doesn't mean that we <EM>have</EM> to use them in every line.&nbsp; You can configure the TypeScript compiler as well as clearing its cache, if you need to. Let the IDE handle those imports.<BR /> <BR /> If you need a recap on why we use TypeScript and how we use it <STRONG>check out <A href="https://blogs.sap.com/2023/07/05/why-the-typescript-sheriff-has-come-to-clean-up-your-javascript-part-1-of-3/" target="_blank" rel="noopener noreferrer">Part 1</A> and <A href="https://blogs.sap.com/2023/07/05/typescript-sheriff-how-can-i-use-typescript-in-the-sap-ecosystem/" target="_blank" rel="noopener noreferrer">Part 2</A> of this series.</STRONG><BR /> <BR /> &nbsp;<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/07/cactus2-1.png" height="201" width="140" /></P><BR /> In this final post of the series I will share some tips on how to use TypeScript in your SAP-ecosystem development.&nbsp; I'm a recent convert (or 'reformed character' if you prefer) rather than a TypeScript expert, but I hope this perspective will be useful for others.<BR /> <H3 id="toc-hId-1091135885">Use the import prompt</H3><BR /> We use import statements to reference the types provided by the various frameworks that I discussed in the previous post. This is particularly important in UI5 development where we need to need to use the types that correspond to the UI controls on our views. The good news is that our IDE can add the import statements for us.<BR /> <BR /> In this example, from SAP Business Application Studio,&nbsp; we can click on the Quick Fix prompt.....<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/07/Import1.jpg" height="109" width="568" /></P><BR /> ...and then choose from the list of matching types<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/07/Import2.png" height="136" width="310" /></P><BR /> The import statement will be added for us.&nbsp; In this case there is ambiguity (which 'Button' class are we referencing?) but if the module name is unique the import will be added automatically.<BR /> <H3 id="toc-hId-894622380">Watch your case</H3><BR /> In TypeScript, as in JavaScript, primitives are written all lower case: e.g. <EM><STRONG>s</STRONG>tring, <STRONG>n</STRONG>umber, <STRONG>b</STRONG>oolean</EM>.&nbsp; Object types have title case: e.g. <EM>Date</EM>. With <EM>string</EM> in particular you need to be careful to <A href="https://www.geeksforgeeks.org/what-is-the-difference-between-string-and-string-in-typescript/" target="_blank" rel="nofollow noopener noreferrer">use the correct case</A>.&nbsp; As we are usually referring the primitive type we should almost always be using <STRONG>s</STRONG>tring rather than <STRONG>S</STRONG>tring in our types.<BR /> <H3 id="toc-hId-698108875">Less is more</H3><BR /> Once I was up and running with TypeScript I loved using types and declared an explicit type everywhere I could.&nbsp; The downside to this is that the code becomes a little 'busy'.<BR /> <BR /> TypeScript is smart enough to distinguish between situations in which an explicit type is needed and when there is no ambiguity and the type can be inferred, so in my opinion it's best to leave out the explicit types unless they add value. Consider the following example. The calculateAgeAtDeath function accepts a Sheriff object as a parameter and returns the age of the that sheriff (a number).&nbsp; The return type of the function is explicitly declared as is the type of the variable we assigned to it.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/07/Screenshot-2023-07-05-at-11.34.00-am.png" height="284" width="469" /></P><BR /> Both of these declarations are redundant and can be removed.&nbsp; The return type of the function will always be number, because are returning the difference between two numbers.&nbsp; If so, the variable to which we assign that return value will also be a number.&nbsp; We can dispense with the types altogether.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/07/Screenshot-2023-07-05-at-3.02.34-pm.png" height="317" width="482" /></P><BR /> <BR /> <H3 id="toc-hId-501595370">Clearing the cache</H3><BR /> Very occasionally your IDE may report spurious errors.&nbsp; This can be resolved by clearing the cache of the TypeScript compiler.&nbsp; In Business Application Studio (or Visual Studio Code) this can be done with the&nbsp;<EM>Restart TS Server</EM> command.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/07/Screenshot-2023-07-05-at-3.03.40-pm.png" height="196" width="488" /></P><BR /> Use the menu path <EM>View-&gt;Command Palette</EM> then type to filter the commands until <EM>Restart TS Server</EM> appears. NB You must have a .ts file open in the editor when you launch the Command Palette, otherwise this command won't appear.<BR /> <H3 id="toc-hId-305081865">Taking a break from types</H3><BR /> Of course when using TypeScript we want to declare types wherever they resolve ambiguity and add value (see above).&nbsp; There may occasionally be times however when you feel that including types is too difficult or impedes your 'flow' too much.<BR /> <BR /> One simple approach in this scenario is to <A href="https://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.html#any" target="_blank" rel="nofollow noopener noreferrer">use the generic&nbsp;<EM>any&nbsp;</EM>type</A>.&nbsp; This is a way to acknowledge that a type is appropriate but still leave the exact type to be inferred at run-time.<BR /> <PRE class="language-javascript"><CODE>let something: any = …<BR /> </CODE></PRE><BR /> If you're doing this then your code may have a .ts suffix but it isn't really superior to the plain JavaScript we are replacing! For this reason you are risking a knock at the door from the TypeScript Sheriff<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/07/Scene4-2.jpeg" height="208" width="349" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">The TypeScript Sheriff</P><BR /> There are also <A href="https://timmousk.com/blog/typescript-ignore-next-line/#:~:text=To%20ignore%20all%20TypeScript%20compiler%20errors%20of%20a%20file%2C%20add,the%20top%20of%20the%20file.&amp;text=This%20comment%20will%20silence%20all,outputted%20by%20the%20TypeScript%20compiler." target="_blank" rel="nofollow noopener noreferrer">annotations</A> which give the TypeScript compiler instructions. With these you can use proper types for the vast majority of your code, but allow for the odd exception case.<BR /> <PRE class="language-javascript"><CODE>@ts-ignore //no checks for the next line<BR /> @ts-nocheck //no checks for the whole file<BR /> @ts-expect-error //expecting an error, only highlight if there isn't one<BR /> </CODE></PRE><BR /> <H3 id="toc-hId-108568360">Confgure the TypeScript Compiler</H3><BR /> The <EM>tsconfig.json</EM> file sits in the root of your project. It contains various options for the TypeScript compiler, controlling for example the destination folder and language version (e.g. es6) for the .js files generated.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/07/Screenshot-2023-07-05-at-3.55.23-pm.png" height="472" width="435" /></P><BR /> <BR /> <H3 id="toc-hId--87945145">Don't be a cowboy coder....</H3><BR /> Don't be a 'cowboy coder', use TypeScript to stay on the right side of the law and hopefully these tips will assist you on your journey to more reliable and readable code<BR /> <BR /> &nbsp; 2023-07-05T18:31:48+02:00 https://community.sap.com/t5/technology-blogs-by-members/lets-deep-dive-into-capm-and-hana-cloud-gt-hanacap/ba-p/13560227 Lets Deep dive into CAPM and HANA Cloud --> HANACap 2023-07-16T22:03:44+02:00 shivamshukla12 https://community.sap.com/t5/user/viewprofilepage/user-id/16613 Hello everyone!<BR /> <BR /> &nbsp;<BR /> <BR /> I hope you're coding and having a great time!!!<BR /> <BR /> Currently, I am engaged in working on various BTP (Business Technology Platform) services, and designing and development constitute my everyday tasks. As expected, we encounter some challenges along the way, which is quite normal <span class="lia-unicode-emoji" title=":slightly_smiling_face:">🙂</span> Therefore, I've decided to document these challenges along with their corresponding solutions in my GitHub repository. This compilation is expected to grow into a substantial list over time, but for now, I have already included two challenges and their respective solutions.<BR /> <BR /> &nbsp;<BR /> <H2 id="toc-hId-962911338"><STRONG>Pre-requisite:</STRONG></H2><BR /> <UL><BR /> <LI>Get your BTP Trial Account setup before you jump into Coding <span class="lia-unicode-emoji" title=":slightly_smiling_face:">🙂</span> + VSCode or BAS</LI><BR /> </UL><BR /> &nbsp;<BR /> <H3 id="toc-hId-895480552"><STRONG>Here you go GitHub Repo - <A href="https://github.com/shivamshukla12/SAP-CAP/tree/main" target="_blank" rel="nofollow noopener noreferrer">https://github.com/shivamshukla12/SAP-CAP/tree/main</A>&nbsp;</STRONG></H3><BR /> &nbsp;<BR /> <UL><BR /> <LI><BR /> <H4 id="toc-hId-828049766">Write your first CAP Application -&nbsp; Its a simple one Hello World</H4><BR /> </LI><BR /> <LI><BR /> <H4 id="toc-hId-631536261">Create one entity in your CAP App and Insert&nbsp; / Retrieve some Hard coded Values</H4><BR /> </LI><BR /> <LI><BR /> <H4 id="toc-hId-435022756">Add some CSV Data in your CAP Application</H4><BR /> </LI><BR /> <LI><BR /> <H4 id="toc-hId-238509251">Run and retrieve your CSV Data</H4><BR /> </LI><BR /> <LI><BR /> <H4 id="toc-hId-41995746">Connect your CAP Application to BTP Space</H4><BR /> </LI><BR /> <LI><BR /> <H4 id="toc-hId--154517759">Provision Services for your CAP Application</H4><BR /> </LI><BR /> <LI><BR /> <H4 id="toc-hId--351031264">Enable HANA Cloud Instance and Add HDI Containers</H4><BR /> </LI><BR /> <LI><BR /> <H4 id="toc-hId--547544769">Build and Deploy your CAP Application on CF ( Cloud Foundry )</H4><BR /> </LI><BR /> <LI><BR /> <H4 id="toc-hId--1241775369">Run and Debug your CAP Application</H4><BR /> </LI><BR /> </UL><BR /> &nbsp;<BR /> <H3 id="toc-hId--1144885867"><STRONG>Tutorial Highlights:</STRONG></H3><BR /> &nbsp;<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/07/15-6.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">Say Hello to SAP CAP</P><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/07/16-5.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">Supplier Entity for Projection</P><BR /> &nbsp;<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/07/17-5.png" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">Supplier JS File For logic and data export</P><BR /> <BR /> <H3 id="toc-hId--1341399372"></H3><BR /> <H3 id="toc-hId--1537912877">GET Request :</H3><BR /> Using CDS in CAP -&nbsp; you can simply write select statement and Wrap it in NodeJS and run the query to get data back from the database<BR /> <BR /> <STRONG>POST Request :</STRONG><BR /> <BR /> Using CDS in CAP - you can make POST Calls directly on Entity exposed which will Create New entry in Database<BR /> <BR /> <STRONG>Delete Request :</STRONG><BR /> <BR /> Using CDS in CAP - You can use custom handler function to delete records from the database - A Custom logic or i would say simply wrap your delete statement in Nodejs and run it on CDS.<BR /> <H3 id="toc-hId--1734426382"></H3><BR /> <H1 id="toc-hId--1344133873">Highlights</H1><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/07/18-6.png" /></P><BR /> <P class="image_caption" style="text-align:center;font-style:italic;, Arial, sans-serif">CRUD Operations in CAP Entity</P><BR /> <BR /> <H3 id="toc-hId--2127453392"></H3><BR /> <H3 id="toc-hId-1971000399"></H3><BR /> <H2 id="toc-hId-2067889901"><STRONG>Coming up Next...</STRONG></H2><BR /> <UL><BR /> <LI><BR /> <PRE><CODE>&nbsp;How SQL is giving the real value to your cloud Application Programming -- SQL is the magic</CODE></PRE><BR /> </LI><BR /> <LI><BR /> <PRE><CODE>&nbsp;Working with multiple entities and Association</CODE></PRE><BR /> </LI><BR /> <LI><BR /> <PRE><CODE>&nbsp;Projection , Aggregate functions and Joins</CODE></PRE><BR /> </LI><BR /> <LI><BR /> <PRE><CODE>&nbsp;Function Import in CAP</CODE></PRE><BR /> </LI><BR /> </UL><BR /> &nbsp;<BR /> <BR /> Keep Learning and Keep Sharing <span class="lia-unicode-emoji" title=":slightly_smiling_face:">🙂</span><BR /> <BR /> &nbsp;<BR /> <BR /> PS: I will Keep posting Updates in my this blog and Updating&nbsp; the repo for promised exercises<BR /> <BR /> &nbsp;<BR /> <BR /> Thanks Shivam<BR /> <BR /> &nbsp; 2023-07-16T22:03:44+02:00 https://community.sap.com/t5/technology-blogs-by-members/up-level-your-sap-odata-apis-with-azure-api-management/ba-p/13563562 Up-level your SAP OData APIs with Azure API Management 2023-07-21T08:20:38+02:00 Martin-Pankraz https://community.sap.com/t5/user/viewprofilepage/user-id/143781 <TABLE style="border-collapse: collapse;width: 100%" border="1"><BR /> <TBODY><BR /> <TR><BR /> <TD style="width: 100%;background-color: #ffcc73"><BR /> <BR /> <span class="lia-unicode-emoji" title=":unicorn_face:">🦄</span>Featured <A href="https://github.com/Azure-Samples/app-service-javascript-sap-cloud-sdk-quickstart" target="_blank" rel="nofollow noopener noreferrer">GitHub repos</A> <STRONG>SAP Cloud SDK on Azure</STRONG> App Service Quickstart<BR /> <BR /> <span class="lia-unicode-emoji" title=":backhand_index_pointing_right:">👉🏿</span><A href="https://techcommunity.microsoft.com/t5/azure-integration-services-blog/publish-protect-and-validate-odata-apis-in-api-management/ba-p/3879522" target="_blank" rel="nofollow noopener noreferrer">Annoucement post</A> on the Microsoft TechCommunity by my Engineering colleagues<BR /> <BR /> <span class="lia-unicode-emoji" title=":magnifying_glass_tilted_left:">🔍</span>Find the Preview note <A href="https://azure.microsoft.com/en-us/updates/public-preview-odata-api-type-in-azure-api-management-2/" target="_blank" rel="nofollow noopener noreferrer">here</A>.<BR /> <BR /> <EM><SPAN style="color: #ff00ff">*</SPAN>Beforehand an API definition </EM><A href="https://aka.ms/ODataOpenAPI" target="_blank" rel="nofollow noopener noreferrer"><EM>conversion to OpenAPI</EM></A><EM> had been necessary. See </EM><A href="https://blogs.sap.com/2022/03/17/open-your-sap-odata-apis-for-some-swagger-or-how-to-make-friends-with-the-other-kids-from-the-api-block/" target="_blank" rel="noopener noreferrer"><EM>this blog</EM></A><EM> for more info.</EM></TD><BR /> </TR><BR /> </TBODY><BR /> </TABLE><BR /> Dear community,<BR /> <BR /> As of <A href="https://learn.microsoft.com/azure/api-management/import-api-from-odata" target="_blank" rel="nofollow noopener noreferrer">yesterday</A>, you may <STRONG>directly consume</STRONG><SPAN style="color: #ff00ff">*</SPAN><STRONG> SAP OData APIs </STRONG>via <A href="https://learn.microsoft.com/azure/api-management/api-management-key-concepts" target="_blank" rel="nofollow noopener noreferrer">Azure API Management</A> <STRONG>from any-premise</STRONG> no matter where they live from all Azure regions<span class="lia-unicode-emoji" title=":party_popper:">🎉</span>: SAP Gateway, BTP ABAP environment, S/4HANA Cloud private or public edition in <A href="https://learn.microsoft.com/azure/sap/workloads/rise-integration#integration-with-azure-services" target="_blank" rel="nofollow noopener noreferrer">RISE</A> or GROW, SuccessFactors, Ariba, Concur, Commerce Cloud, or SAP Business Technology Platform (BTP) etc.🤩<BR /> <BR /> <STRONG>Azure API Management</STRONG> <STRONG>secures and simplifies </STRONG>the <STRONG>SAP API integration</STRONG> with popular Microsoft services like Power Platform, Azure Functions, Microsoft Entra ID (formerly Azure AD) and Microsoft Sentinel to name a few.<BR /> <BR /> And of course, you get standard API Management features like fully <A href="https://learn.microsoft.com/azure/api-management/api-management-using-with-internal-vnet?tabs=stv2" target="_blank" rel="nofollow noopener noreferrer">private virtual network integration</A>, <A href="https://learn.microsoft.com/azure/api-management/api-management-howto-deploy-multi-region" target="_blank" rel="nofollow noopener noreferrer">multi-location deployment</A>, <A href="https://learn.microsoft.com/azure/api-management/self-hosted-gateway-overview" target="_blank" rel="nofollow noopener noreferrer">hybrid and multi-cloud gateways</A>, <A href="https://azure.microsoft.com/explore/global-infrastructure/products-by-region/?products=api-management&amp;regions=all" target="_blank" rel="nofollow noopener noreferrer">global presence</A> (more regions that any other cloud provider), throttling, quota handling, request validation before it even hits SAP, and <A href="https://learn.microsoft.com/azure/api-management/authorizations-overview" target="_blank" rel="nofollow noopener noreferrer">cloud native authentication flows</A> in one central place<span class="lia-unicode-emoji" title=":sign_of_the_horns:">🤘</span>.<BR /> <BR /> In case you favor SAP API Management on Azure, find your way to SAP Integration Suite on Azure <A href="https://discovery-center.cloud.sap/serviceCatalog/integration-suite?region=all&amp;tab=service_plan&amp;provider=azure&amp;commercialModel=cpea" target="_blank" rel="nofollow noopener noreferrer">here</A>. See <A href="https://blogs.sap.com/2023/01/30/sap-integration-suite-enhanced-for-todays-digital-processes-sap-teched-2022-edition/" target="_blank" rel="noopener noreferrer">SAP Edge Integration Cell</A> to run your iFlows on any-premise including any Azure region or Edge deployments.<BR /> <BR /> Find your way around the highlighted Azure API Management features, SDKs, quickstart repos, deep-dive blog posts, and more from below.<BR /> <H1 id="toc-hId-833920994">API Creation, Design &amp; blueprints</H1><BR /> <H3 id="toc-hId-895572927">Enable modern GraphQL for your OData APIs.</H3><BR /> See <A href="https://blogs.sap.com/2023/07/20/sap-btp-abap-environment-integration-journey-with-microsoft-part-3/" target="_blank" rel="noopener noreferrer">this</A> ABAP Cloud scenario from my BTP ABAP environment (steampunk) <A href="https://blogs.sap.com/2023/06/06/kick-start-your-sap-abap-platform-integration-journey-with-microsoft/" target="_blank" rel="noopener noreferrer">blog series</A>.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/07/steampunk-graphql-overview-1.png" /></P><BR /> <BR /> <H3 id="toc-hId-699059422">Spin up your SAP app extension powered by the <A href="https://github.com/Azure-Samples/app-service-javascript-sap-cloud-sdk-quickstart" target="_blank" rel="nofollow noopener noreferrer">SAP Cloud SDK on Azure</A> with API Management with one command</H3><BR /> The <A href="https://learn.microsoft.com/azure/developer/azure-developer-cli/overview" target="_blank" rel="nofollow noopener noreferrer">Azure Developer CLI</A> handles the whole app lifecycle including the API create from schema and attaching policies.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/07/project-overview-azd-style.png" /></P><BR /> <BR /> <H3 id="toc-hId-502545917">Speed up your Azure API Management Policy design with <A href="https://github.com/features/preview/copilot-x" target="_blank" rel="nofollow noopener noreferrer">GitHub Copilot</A> and <A href="https://chat.openai.com/" target="_blank" rel="nofollow noopener noreferrer">ChatGPT</A></H3><BR /> Since there are many policies published out there the <STRONG>Large-Language-Model is quite good at creating APIM policies</STRONG>.<BR /> <BR /> Try below prompt either in <A href="https://marketplace.visualstudio.com/items?itemName=GitHub.copilot-chat" target="_blank" rel="nofollow noopener noreferrer">GitHub Copilot chat</A> or <A href="https://chat.openai.com/" target="_blank" rel="nofollow noopener noreferrer">ChatGPT</A> to get started:<BR /> <PRE class="language-swift"><CODE>Create an azure apim policy handling csrf tokens with sap odata apis</CODE></PRE><BR /> <H3 id="toc-hId-306032412">Reason about and debug complex policies on Azure API Management using breakpoints from <A href="https://learn.microsoft.com/azure/api-management/api-management-debug-policies" target="_blank" rel="nofollow noopener noreferrer">Visual Studio Code</A></H3><BR /> Don’t forget to turn on tracing on APIM! Otherwise, there is no process attach <span class="lia-unicode-emoji" title=":winking_face:">😉</span><BR /> <H3 id="toc-hId-109518907">Create an <A href="https://learn.microsoft.com/azure/api-management/quickstart-terraform?tabs=azure-cli" target="_blank" rel="nofollow noopener noreferrer">Azure API Management service including APIs using Terraform</A></H3><BR /> Check out our <A href="https://github.com/Azure-Samples/app-service-javascript-sap-cloud-sdk-quickstart" target="_blank" rel="nofollow noopener noreferrer">SAP Cloud SDK quickstart repos</A> for more details on injecting APIs into existing API Management instances.<BR /> <H1 id="toc-hId--345160036">Authentication &amp; Security</H1><BR /> <H3 id="toc-hId--283508103"><A href="https://learn.microsoft.com/azure/defender-for-cloud/defender-for-apis-introduction" target="_blank" rel="nofollow noopener noreferrer">Activate Defender for APIs in Azure API Management to automatically detect threats</A> in your SAP APIs</H3><BR /> Unused days, authentication type, classification of sensitive data in response, and detection of suspicious API traffic patterns, already go a long way in securing your API estate.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/07/endpoint-details.png" /></P><BR /> <BR /> <H3 id="toc-hId--480021608">Apply our <A href="https://github.com/Azure/api-management-policy-snippets/blob/master/examples/Request%20OAuth2%20access%20token%20from%20SAP%20using%20AAD%20JWT%20token.xml" target="_blank" rel="nofollow noopener noreferrer">standard policy for SAP Principal Propagation</A> to map Microsoft authenticated users to SAP backend users</H3><BR /> Learn more from this <A href="https://blogs.sap.com/2021/08/12/.net-speaks-odata-too-how-to-implement-azure-app-service-with-sap-odata-gateway/" target="_blank" rel="noopener noreferrer">blog post</A>.<BR /> <BR /> Take a deep dive on the involved SAP OAuth server from <A href="https://github.com/MartinPankraz/SAP-MSTeams-Hero/blob/main/Towel-Bearer/103a-sap-principal-propagation-basics.md" target="_blank" rel="nofollow noopener noreferrer">here</A>:<BR /> <BR /> <IFRAME width="560" height="315" src="https://www.youtube.com/embed/JGvJJnMSEHM" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen=""></IFRAME><BR /> <H3 id="toc-hId--676535113">Apply Azure API Management to lift the burden of <A href="https://blogs.sap.com/2023/07/14/sap-btp-abap-environment-integration-journey-with-microsoft-part-2-using-api-management/" target="_blank" rel="noopener noreferrer">X.509 client certificate handling</A> for consumers apps integrating with BTP ABAP environment</H3><BR /> &nbsp;<BR /> <H3 id="toc-hId--948279987">Utilize Azure API Management <A href="https://learn.microsoft.com/azure/api-management/authorizations-overview" target="_blank" rel="nofollow noopener noreferrer">Authorization Provider</A> to streamline your auth setup and ease policy design</H3><BR /> Use <A href="https://www.youtube.com/watch?v=bHh9_WVzXzI" target="_blank" rel="nofollow noopener noreferrer">Azure API Management Authorizations</A><span class="lia-unicode-emoji" title=":movie_camera:">🎥</span> with apps like Power Platform or SAP Build Process Automation to integrate with SAP faster.<BR /> <BR /> Stay tuned for further simplifications in this space for SAP workloads specifically.<BR /> <H1 id="toc-hId--557987478"><A href="https://azure.github.io/apiops/" target="_blank" rel="nofollow noopener noreferrer">APIOps</A></H1><BR /> UI-based API creation, modification, and deletion is doable for smaller API estates. However, enterprise scale requires API-as-Code and pipelining approaches with CD/CD.<BR /> <H3 id="toc-hId--1341306997">Use <A href="https://learn.microsoft.com/azure/developer/azure-developer-cli/overview" target="_blank" rel="nofollow noopener noreferrer">Azure Developer CLI</A> to handle the complete lifecycle of your SAP extension app, including the SAP OData API in Azure API Management</H3><BR /> You may choose from Bicep or Terraform. See <A href="https://github.com/Azure-Samples/app-service-javascript-sap-cloud-sdk-quickstart" target="_blank" rel="nofollow noopener noreferrer">this repo</A> for more details.<BR /> <BR /> Apply the <A href="https://github.com/Azure/azure-api-management-devops-resource-kit" target="_blank" rel="nofollow noopener noreferrer">Azure API Management DevOps kit</A> including GitHub Actions. Automate API deployments with <A href="https://learn.microsoft.com/azure/architecture/example-scenario/devops/automated-api-deployments-apiops" target="_blank" rel="nofollow noopener noreferrer">APIOps</A> and Azure DevOps<BR /> <H3 id="toc-hId--1537820502">For the ABAP RAP part of the house have a look at combining the git-based flows via Git-enabled Change and Transport System (<A href="https://open.sap.com/courses/gcts1" target="_blank" rel="noopener noreferrer">gCTS</A>)</H3><BR /> Either have Azure Developer CLI (AZD) trigger the gCTS workflow or receive the trigger from gCTS using <A href="https://learn.microsoft.com/azure/developer/azure-developer-cli/azd-extensibility" target="_blank" rel="nofollow noopener noreferrer">AZD hooks</A>.<BR /> <H1 id="toc-hId--1147527993">Connectivity</H1><BR /> <H3 id="toc-hId--1930847512">Connect SAP BTP based apps like SAP CAP, Cloud Integration, Build Workzone Standard Edition, or SAP Build Apps with your APIs via <A href="https://help.sap.com/docs/private-link/private-link1/consume-azure-services-in-sap-btp" target="_blank" rel="noopener noreferrer">SAP Private Link</A></H3><BR /> Reach your private Azure API Management instance securely via the private link traversing the Azure Application Gateway and the its <A href="https://learn.microsoft.com/azure/architecture/web-apps/api-management/architectures/protect-apis" target="_blank" rel="nofollow noopener noreferrer">web application firewall</A>. Learn more from <A href="https://blogs.sap.com/2022/11/30/sap-private-linky-swear-with-azure-to-waf-or-not-to-waf%f0%9f%90%b6-with-sap-private-link/" target="_blank" rel="noopener noreferrer">this blog post</A>.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/07/private-linky-appgw-overview-1.png" /></P><BR /> <BR /> <H3 id="toc-hId--2127361017">Keep your SAP OData APIs fully private by <A href="https://learn.microsoft.com/azure/api-management/api-management-using-with-internal-vnet?tabs=stv2" target="_blank" rel="nofollow noopener noreferrer">injecting an internal Azure API Management instance</A> into the private Azure virtual network</H3><BR /> You may customize this approach to securely expose the private SAP APIs via Azure API Management to the Internet using the <A href="https://learn.microsoft.com/azure/api-management/api-management-using-with-vnet?tabs=stv2" target="_blank" rel="nofollow noopener noreferrer">external mode</A>.<BR /> <H3 id="toc-hId-1971092774">Use the <A href="https://learn.microsoft.com/azure/api-management/self-hosted-gateway-overview" target="_blank" rel="nofollow noopener noreferrer">Self-hosted Gateway of Azure API Management</A> for hybrid deployments</H3><BR /> The use cases span from multi-cloud, any-premise (your local data center etc.) to the Edge (think factories, oil-rigs, etc.).<BR /> <H3 id="toc-hId-1774579269">Export APIs from <A href="https://learn.microsoft.com/azure/api-management/export-api-power-platform" target="_blank" rel="nofollow noopener noreferrer">Azure API Management to the Power Platform</A></H3><BR /> <H1 id="toc-hId--2130095518">Final Words</H1><BR /> Only thing left to say: happy integrating everyone <span class="lia-unicode-emoji" title=":smiling_face_with_sunglasses:">😎</span><BR /> <BR /> Start your Azure Journey regarding your SAP integration <A href="https://azure.microsoft.com/free" target="_blank" rel="nofollow noopener noreferrer">here</A> for free. See the Azure API Management <A href="https://azure.microsoft.com/pricing/details/api-management/" target="_blank" rel="nofollow noopener noreferrer">serverless and developer tier</A> for cloud credit effective use. For SAP API Management on Azure see <A href="https://discovery-center.cloud.sap/serviceCatalog/integration-suite?region=all&amp;tab=service_plan&amp;commercialModel=free&amp;provider=azure" target="_blank" rel="nofollow noopener noreferrer">FREE tier and trial plans</A>.<BR /> <BR /> Find the announcement blog post by my Azure APIM colleagues on the <A href="https://techcommunity.microsoft.com/t5/azure-integration-services-blog/publish-protect-and-validate-odata-apis-in-api-management/ba-p/3879522" target="_blank" rel="nofollow noopener noreferrer">Microsoft TechCommunity here</A>.<BR /> <BR /> Discover additional Microsoft integration scenarios from our <A href="https://learn.microsoft.com/azure/sap/workloads/integration-get-started" target="_blank" rel="nofollow noopener noreferrer">aggregator article</A>.<BR /> <BR /> &nbsp;<BR /> <BR /> Reach out to me for a deep dive into SAP integration with APIs <span class="lia-unicode-emoji" title=":handshake:">🤝</span><BR /> <BR /> &nbsp;<BR /> <BR /> Cheers<BR /> <BR /> Martin 2023-07-21T08:20:38+02:00 https://community.sap.com/t5/technology-blogs-by-sap/sap-configure-price-quote-cpq-apis-with-resilience-with-sap-btp-kyma/ba-p/13561449 SAP Configure,Price,Quote (CPQ) APIs with resilience with SAP BTP, Kyma runtime 2023-07-28T08:44:58+02:00 quovadis https://community.sap.com/t5/user/viewprofilepage/user-id/743 <TABLE style="width: 100%;border-collapse: collapse;background-color: #f5f5f5" border="1"><BR /> <TBODY><BR /> <TR style="height: 112px"><BR /> <TD style="width: 100%;height: 62px"><A href="https://www.sap.com/uk/products/financial-management/cpq.html" target="_blank" rel="noopener noreferrer"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/06/SAP_CustomerExperience_R.png" /></A><STRONG style="font-family: inherit;font-size: inherit">SAP Configure, Price and Quote APIs with OAuth2SAMLBearerAssertion</STRONG></TD><BR /> </TR><BR /> </TBODY><BR /> </TABLE><BR /> <TABLE style="width: 100%;border-collapse: collapse;background-color: #ebf8ff" border="1"><BR /> <TBODY><BR /> <TR><BR /> <TD style="width: 43.28%"><BR /> <P style="overflow: hidden;margin-bottom: 0px"><A href="https://help.sap.com/docs/btp/sap-business-technology-platform/getting-started-in-kyma-environment" target="_blank" rel="noopener noreferrer"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/07/extension-factory-kyma-runtime.png" height="75" width="75" /></A><A style="font-family: inherit;font-size: inherit" href="https://sap.github.io/cloud-sdk/docs/js/getting-started" target="_blank" rel="nofollow noopener noreferrer"><IMG src="https://sap.github.io/cloud-sdk/img/logo.svg" alt="SAP Cloud SDK" width="75" height="75" /></A><A href="https://help.sap.com/doc/92c0b171cceb4db2a93518b34b84febd/Cloud/en-US/connectivity_service.pdf" target="_blank" rel="noopener noreferrer"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2021/06/destservice-5.png" height="75" width="75" /></A></P><BR /> &nbsp;<BR /> <BR /> <A href="https://learning.sap-press.com/sap-customer-experience" target="_blank" rel="nofollow noopener noreferrer"><IMG src="https://learning.sap-press.com/hs-fs/hubfs/01_003_CX.jpg?width=738&amp;name=01_003_CX.jpg" alt="SAP Customer Experience Overview" /></A></TD><BR /> <TD style="width: 56.72%"><BR /> <BR /> SAP CPQ configure, price, and quote <A href="https://www.sap.com/uk/assetdetail/2021/05/38c77905-e07d-0010-bca6-c68f7e60039b.html" target="_blank" rel="noopener noreferrer">solution</A> is part of the <A href="https://learning.sap-press.com/sap-customer-experience" target="_blank" rel="nofollow noopener noreferrer">SAP Customer Experience solutions portfolio</A>.<BR /> <BR /> Furthermore, SAP CPQ offers a reach palette of <A href="https://help.sap.com/docs/SAP_CPQ/f80fbcd4f1c74232839c30ce26886f07/c1d80a83d8134e91b2c527c17a8301b7.html" target="_blank" rel="noopener noreferrer">integration</A> capabilities with other SAP Solutions, for instance, with <A href="https://help.sap.com/docs/SAP_CPQ/f80fbcd4f1c74232839c30ce26886f07/e28bbb5e433d4e8fbda475fcadab5f4b.html" target="_blank" rel="noopener noreferrer">SAP Commerce Cloud</A><BR /> <BR /> So how does <A href="https://help.sap.com/docs/SAP_CPQ" target="_blank" rel="noopener noreferrer">SAP Configure, Price and Quote</A> relate to <A href="https://www.sap.com/documents/2022/10/4cd2433b-487e-0010-bca6-c68f7e60039b.html" target="_blank" rel="noopener noreferrer">SAP Kyma</A> and <A href="https://sap.github.io/cloud-sdk/docs/js/getting-started" target="_blank" rel="nofollow noopener noreferrer">SAP Cloud SDK</A>?<BR /> <BR /> Surprise, surprise...</TD><BR /> </TR><BR /> </TBODY><BR /> </TABLE><BR /> <H1 id="toc-hId-833860396">Putting it all together</H1><BR /> <!-- TABLE OF CONTENTS --><BR /> <BR /> <DETAILS open="open"><SUMMARY>Table of Contents</SUMMARY><BR /> <OL><BR /> <LI><A href="#per-aspera-ad-astra-who-am-i" target="_blank" rel="nofollow noopener noreferrer">About me</A></LI><BR /> <LI><A href="#prerequisites" target="_blank" rel="nofollow noopener noreferrer">SAP CPQ APIs</A></LI><BR /> <LI><A href="#per-aspera-ad-astra-solution-brief" target="_blank" rel="nofollow noopener noreferrer">Per aspera ad astra. Solution brief.</A><BR /> <OL><BR /> <LI><A href="#multi-tenant-application-architecture" target="_blank" rel="nofollow noopener noreferrer">SAP CPQ easy with kyma-powered multi-tenant application</A></LI><BR /> </OL><BR /> </LI><BR /> <LI><A href="#sapcpq-configuration-step-by-step" target="_blank" rel="nofollow noopener noreferrer">Setting up a SAP CPQ Trusted Application (OAuth2 client).</A></LI><BR /> <LI><A href="#sapcpq-destinations-definitions" target="_blank" rel="nofollow noopener noreferrer">SAP BTP sub-account and instance level destination definitions.</A><BR /> <OL><BR /> <LI><A href="#destinations-examples" target="_blank" rel="nofollow noopener noreferrer">Examples of SAP CPQ destination definitions</A></LI><BR /> </OL><BR /> </LI><BR /> <LI><A href="#sapcpq-implementation-notes" target="_blank" rel="nofollow noopener noreferrer">Implementation and troubleshooting notes.</A><BR /> <OL><BR /> <LI dir="auto"><A href="https://gist.github.com/ptesny/55d301039ae0fcb6bb5e684150bf4612#sap-cloud-sdk-with-built-in-resilience-middleware-with-kyma-runtime-to-the-rescue" target="_blank" rel="noopener nofollow noreferrer">SAP Cloud-SDK with built-in resilience middleware with Kyma runtime to the rescue</A></LI><BR /> <LI dir="auto"><A href="https://gist.github.com/ptesny/55d301039ae0fcb6bb5e684150bf4612#diy-saml-assertion-and-the-bearer-access-token" target="_blank" rel="noopener nofollow noreferrer">DIY: SAML Assertion and the bearer access token</A></LI><BR /> </OL><BR /> </LI><BR /> </OL><BR /> </DETAILS><BR /> <H2 id="prerequisites" id="toc-hId-766429610">SAP CPQ APIs</H2><BR /> From the <A href="https://help.sap.com/docs/SAP_CPQ/08a7929ad06d4680b4f18cb57bc1a1d3/7be8a894a6dd45f7806f11c86f5b7c11.html" target="_blank" rel="noopener noreferrer">documentation</A>...<BR /> <BLOCKQUOTE><BR /> <P class="p">With API you can update quotes, execute quote actions, create customers or business partners, update users and so on.</P><BR /> <P class="p">For example, if a company uses a separate application to process shipping information after an order has been placed,&nbsp;<SPAN class="ph pname">SAP CPQ</SPAN>&nbsp;API can be used to update a quote with shipping information, such as a tracking number, tracking URL, estimated shipping date, and so on.</P><BR /> </BLOCKQUOTE><BR /> <TABLE style="width: 100%;border-collapse: collapse;background-color: #ebf8ff" border="1"><BR /> <TBODY><BR /> <TR><BR /> <TD style="width: 50%"><BR /> <BR /> The focus of this brief is the SAP CPQ REST APIs with <STRONG>Token API Authentication&nbsp;</STRONG>as documented here:<BR /> <BR /> <A href="https://help.sap.com/docs/SAP_CPQ/08a7929ad06d4680b4f18cb57bc1a1d3/7be8a894a6dd45f7806f11c86f5b7c11.html" target="_blank" rel="noopener noreferrer">SAP CPQ API Documentation | SAP Help</A><BR /> <BR /> <A href="https://help.sap.com/doc/8aad4d38676643a9b56227b35c7c5f19/2305/en-US/1223eb24e83548a980c5aceb8de5b113.pdfhttps://help.sap.com/doc/8aad4d38676643a9b56227b35c7c5f19/2305/en-US/1223eb24e83548a980c5aceb8de5b113.pdf" target="_blank" rel="noopener noreferrer">SAP CPQ API Documentation | SAP PDF</A>.</TD><BR /> <TD style="width: 50%"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/06/cpq4.png" /></TD><BR /> </TR><BR /> </TBODY><BR /> </TABLE><BR /> <H2 id="per-aspera-ad-astra-solution-brief" id="toc-hId-569916105">Per aspera ad astra. Solution brief and architecture</H2><BR /> At the heart of the solution are:<BR /> <UL><BR /> <LI>SAP CPQ tenant, SAP BTP, Kyma runtime and SAP BTP services.</LI><BR /> <LI>SAP BTP multi-tenancy model - with a standalone multi-tenant<A href="https://www.npmjs.com/package/@sap/approuter" target="_blank" rel="nofollow noopener noreferrer"> @sap/<EM>approuter</EM></A> deployed to a <A href="https://help.sap.com/docs/btp/sap-business-technology-platform/create-kyma-environment-instance" target="_blank" rel="noopener noreferrer">kyma cluster</A>.</LI><BR /> <LI>SAP BTP <A href="https://help.sap.com/docs/connectivity/sap-btp-connectivity-cf/managing-destinations" target="_blank" rel="noopener noreferrer">destination service</A> - with a single instance-level <A href="https://help.sap.com/docs/connectivity/sap-btp-connectivity-cf/oauth-saml-bearer-assertion-authentication" target="_blank" rel="noopener noreferrer">OAuth2SAMLBearerAssertion</A> destination</LI><BR /> <LI>optionally one or more sub-account level S/4HANA Private and Public Cloud destinations</LI><BR /> <LI>standard SAP components and libraries/SDKs - meaning same application code is <EM>deployable</EM> to multiple runtime environments.</LI><BR /> </UL><BR /> <H3 id="multi-tenant-application-architecture" id="toc-hId-502485319">SAP CPQ easy with kyma-powered multi-tenant application</H3><BR /> <TABLE style="border-collapse: collapse;width: 100%" border="1"><BR /> <TBODY><BR /> <TR><BR /> <TD style="width: 100%"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/07/cpq04-2.png" /></TD><BR /> </TR><BR /> </TBODY><BR /> </TABLE><BR /> Good to know:<BR /> <UL><BR /> <LI>all destinations are consumed using&nbsp;<CODE>executeHttpRequest</CODE> SAP Cloud-SDK <A href="https://sap.github.io/cloud-sdk/docs/js/features/connectivity/http-client#executehttprequest" target="_blank" rel="nofollow noopener noreferrer">method</A> with a built-in <A href="https://sap.github.io/cloud-sdk/docs/js/guides/resilience#resilience-middleware" rel="nofollow noopener noreferrer" target="_blank">resilience</A>&nbsp;mechanism.</LI><BR /> <LI>communication between the SAP approuter's frontend and kyma backend service is <EM>intrinsic</EM> (local) via the in-cluster mesh.</LI><BR /> <LI>on premise destinations are accessible via a supported kyma connectivity proxy component</LI><BR /> </UL><BR /> <H2 id="sapcpq-configuration-step-by-step" id="toc-hId-176889095">Setting up a SAP CPQ Trusted Application (OAuth2 client)</H2><BR /> <H3 id="topic-title" id="toc-hId-109458309">Token API Authentication. OAuth 2.0 Assertion Profiles</H3><BR /> <BLOCKQUOTE>OAuth 2.0 Assertion Profiles authentication is implemented in&nbsp;<SPAN class="ph pname">SAP CPQ</SPAN>&nbsp;with the aim of standardizing server-to-server authentication. This type of authentication allows administrators to generate an access token without relying on the logged-in user (no need to store passwords).</BLOCKQUOTE><BR /> You will be asked to set up a <A href="https://help.sap.com/docs/SAP_CPQ/08a7929ad06d4680b4f18cb57bc1a1d3/ffa83300a8a041088824d842751044b6.html" target="_blank" rel="noopener noreferrer">Trusted Application</A> (an OAuth2 client) with your SAP CPQ tenant and required to enter there an issuer URL.<BR /> <BLOCKQUOTE><BR /> <P class="p"><SPAN class="ph uicontrol">Issuer</SPAN>&nbsp;- the URL of the system to which the access token needs to be issued. From that URL users will be accessing&nbsp;<SPAN class="ph pname">SAP CPQ</SPAN> .</P><BR /> </BLOCKQUOTE><BR /> With <STRONG>SAML bearer grant type</STRONG>, this <STRONG>must</STRONG> be the value of the SAML Assertion issuer.<BR /> <BR /> The <CODE>redirect_uri</CODE> is to be used only with the <EM>Authorization code grant type</EM> so best is to void it.<BR /> <BR /> You will also be provided with the<STRONG> client id, client secret and the token issuance endpoint</STRONG>. Please make a note of them as these values will no longer be available after you have saved the Trusted Application.<BR /> <BR /> Once the OAuth2 application has been created you can choose between JWT and SAML bearer grant types as documented here: <A href="https://help.sap.com/docs/SAP_CPQ/08a7929ad06d4680b4f18cb57bc1a1d3/ffa83300a8a041088824d842751044b6.html" target="_blank" rel="noopener noreferrer">OAuth 2.0 Assertion Profiles | SAP Help</A>.<BR /> <BR /> Lets' assume you want to use the <STRONG>SAML bearer grant type</STRONG> as documented here: <A href="https://help.sap.com/docs/SAP_CPQ/08a7929ad06d4680b4f18cb57bc1a1d3/4da87acd636243a585f36f4b205d0413.html" target="_blank" rel="noopener noreferrer">Generate SAML Bearer Grant Type | SAP Help</A><BR /> <BR /> In a nutshell, a SAML bearer grant type consists of exchanging a BTP user identity against a bearer access token coming from a SAP CPQ tenant.<BR /> <BR /> We shall be using an <A href="https://help.sap.com/docs/connectivity/sap-btp-connectivity-cf/oauth-saml-bearer-assertion-authentication" target="_blank" rel="noopener noreferrer">OAuth2SAMLBearerAssertion</A> destination to implement the above grant type.<BR /> <BR /> In a nutshell, a BTP user JWT token's user claim is used to create a SAML Assertion as to trigger an IDP-delegated authentication flow to eventually execute a remote (password-less and unmanned) login into SAP CPQ from a BTP application.<BR /> <BR /> Furthermore, a SAML Assertion must be digitally signed with a private key of a signing certificate. That's why you need to provide a public x509 certificate of the signing key in the Trusted Application definition, as follows:<BR /> <H3 id="toc-hId--87055196">SAP CPQ OAuth2 configuration</H3><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/07/sf-kyma.png" /></P><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/06/cpq2.png" /></P><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/06/cpq3.png" /></P><BR /> <STRONG>The second parameter is the value of the user claim.</STRONG><BR /> <BR /> &nbsp;<BR /> <TABLE style="border-collapse: collapse;width: 100%" border="1"><BR /> <TBODY><BR /> <TR><BR /> <TD style="width: 20.56%"><A href="https://help.sap.com/doc/92c0b171cceb4db2a93518b34b84febd/Cloud/en-US/connectivity_service.pdf" target="_blank" rel="noopener noreferrer"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2021/06/destservice-5.png" height="92" width="92" /></A></TD><BR /> <TD style="width: 79.44%"><BR /> <H2 id="sapcpq-destinations-definitions" id="toc-hId--412651420">SAP BTP sub-account and instance level destination definitions</H2><BR /> </TD><BR /> </TR><BR /> </TBODY><BR /> </TABLE><BR /> The very fact the issuer must be a valid URL with the <STRONG>https</STRONG> scheme has another very important ramification.<BR /> <BR /> Namely, that issuer URL requirement <EM>disqualifies</EM> the usage of a <STRONG>default destination service trust</STRONG> as explained below:<BR /> <BLOCKQUOTE>For the <STRONG>assertionIssuer</STRONG> property to work, one would need to have KeyStoreLocation and KeyStorePassword defined (a key pair) for a SAP CPQ destination.<BR /> Otherwise, as a fallback, the sub-account's trust key pair would be used, but these settings are configured to always use the issuer which doesn't have <A href="https://." target="test_blank" rel="nofollow noopener noreferrer">https://.</A><BR /> <BR /> The solution here is to generate or upload a keystore (for example in a p12 file) through the Certificates button, and point KeyStoreLocation to the name of such certificate, with KeyStorePassword as the appropriate password if applicable. Then the <STRONG>assertionIssuer</STRONG> property of a destination would work.</BLOCKQUOTE><BR /> In other words, you must use your own keystore with both private and public keys instead and declare the issuer URL via a destination <STRONG>assertionIssuer</STRONG> property. Please refer to this <A href="https://gist.github.com/ptesny/55d301039ae0fcb6bb5e684150bf4612#file-troubleshooting-01-md" target="_blank" rel="nofollow noopener noreferrer">gist</A> for further details.<BR /> <H3 id="destinations-examples" id="toc-hId--480082206">Examples of SAP CPQ destination definitions</H3><BR /> <UL><BR /> <LI><A href="https://gist.github.com/ptesny/55d301039ae0fcb6bb5e684150bf4612#sub-account-level-destination-definition" target="_blank" rel="nofollow noopener noreferrer">a sub-account level destination definition</A></LI><BR /> <LI><A href="https://gist.github.com/ptesny/55d301039ae0fcb6bb5e684150bf4612#instance-level-destination-definition" target="_blank" rel="nofollow noopener noreferrer">an instance level destination definition</A></LI><BR /> </UL><BR /> In order to test these definitions you will need to provide a BTP user JWT token that will have your SAP CPQ user's claim (for instance <CODE>user_name</CODE> if <CODE>NameId</CODE> selected in SAP CPQ OAuth2 client definition, as depicted above)<BR /> <BR /> Then, you could test the CPQ destinations leveraging <A href="https://gist.github.com/ptesny/55d301039ae0fcb6bb5e684150bf4612#sap-cloud-sdk-with-built-in-resilience-middleware-with-kyma-runtime-to-the-rescue" target="_blank" rel="nofollow noopener noreferrer">SAP Cloud-SDK</A>, for instance:<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/06/cpq5.png" /></P><BR /> <BR /> <PRE class="language-javascript"><CODE><A href="https://&lt;approuter" target="test_blank" rel="nofollow noopener noreferrer">https://&lt;approuter</A> host&gt;/srv/harmony?destination=cpq-anywhere&amp;path=/customapi/executescript?scriptname=GetOpportunityQuotes<BR /> <BR /> {<BR /> "data": [<BR /> {<BR /> "Quotes": [<BR /> {<BR /> "DateCreated": "&lt;DateCreated&gt;",<BR /> "Offer_Exp_Date": "&lt;Offer_Exp_Date&gt;",<BR /> "EditableforSAP": null,<BR /> "QuoteEngine": "Quote 1.0",<BR /> "TotalSummary": {<BR /> "TotalRevenue": 0,<BR /> "Service": 0,<BR /> "Cloud": 0,<BR /> "TotalContractValue": 0,<BR /> "OnPremise": 0<BR /> },<BR /> "OnPremiseRevenue": false,<BR /> "DealHealth": "High Risk",<BR /> "ContractStart": "&lt;ContractStart&gt;",<BR /> "ProcessTypeCode": null,<BR /> "IsECS": false,<BR /> "ServiceRevenue": false,<BR /> "QuoteNumber": "&lt;QuoteNumber&gt;",<BR /> "LinkedServicesContract": "New Contract",<BR /> "CMSID": "",<BR /> "CloudRevenue": true,<BR /> "Currency": "EUR",<BR /> "QuoteStatus": "Quote In Progress",<BR /> "Description": null,<BR /> "ValidUntilDate": "&lt;ValidUntilDate&gt;",<BR /> "Total": 0,<BR /> "ProcessType": "",<BR /> "WriteAccess": true,<BR /> "IsMain": true,<BR /> "QuoteStatusId": 45,<BR /> "RestructureType": null,<BR /> "PSBundleExtConfigFlag": false,<BR /> "ReadAccess": true,<BR /> "VisibletoChannelPartner": null,<BR /> "ContractEnd": "&lt;ContractEnd&gt;",<BR /> "WorkAtRisk": false<BR /> }<BR /> ],<BR /> "OpportunityId": "&lt;OpportunityId&gt;"<BR /> }<BR /> ]<BR /> }</CODE></PRE><BR /> or...simply using a <CODE>curl</CODE> command as explained <A href="https://gist.github.com/ptesny/55d301039ae0fcb6bb5e684150bf4612#lets-test-it-using-curl-as-depicted-below" target="_blank" rel="nofollow noopener noreferrer">here</A>.<BR /> <H2 id="sapcpq-implementation-notes" id="toc-hId--805678430">Implementation and troubleshooting notes</H2><BR /> During the implementation of the SAP CPQ APIs I have encountered a number of major road blocks. And, to a large extent, both kyma runtime and SAP Cloud-SDK have proven very helpful in overcoming them.<BR /> <BR /> I have gathered a number of implementation and troubleshooting <A href="https://gist.github.com/ptesny/55d301039ae0fcb6bb5e684150bf4612#file-troubleshooting-md" target="_blank" rel="nofollow noopener noreferrer">notes</A> to help explain what it was and how it was addressed, namely:<BR /> <UL><BR /> <LI dir="auto"><A href="https://gist.github.com/ptesny/55d301039ae0fcb6bb5e684150bf4612#sap-cloud-sdk-with-built-in-resilience-middleware-with-kyma-runtime-to-the-rescue" target="_blank" rel="nofollow noopener noreferrer">SAP Cloud-SDK with built-in resilience middleware with Kyma runtime to the rescue</A></LI><BR /> <LI dir="auto"><A href="https://gist.github.com/ptesny/55d301039ae0fcb6bb5e684150bf4612#diy-saml-assertion-and-the-bearer-access-token" target="_blank" rel="nofollow noopener noreferrer">DIY: SAML Assertion and the bearer access token</A></LI><BR /> <LI dir="auto"><A href="https://sap.github.io/cloud-sdk/docs/js/features/connectivity/destinations#destination-service" target="_blank" rel="nofollow noopener noreferrer">SAP Cloud SDK destinations | SAP Cloud SDK</A></LI><BR /> </UL><BR /> &nbsp;<BR /> <BR /> <HR /><BR /> <BR /> <H2 id="per-aspera-ad-astra-who-am-i" id="toc-hId--654937578">Per aspera ad astra. Who am I?</H2><BR /> <SPAN style="font-size: 1rem">You can follow me in SAP Community: </SPAN><SPAN class="mention-scrubbed">piotr.tesny</SPAN><BR /> <BR /> <A style="font-size: 1rem" href="https://community.sap.com/topics/kyma" target="_blank">SAP Kyma Community</A><SPAN style="font-size: 1rem"> and </SPAN><A style="font-size: 1rem" href="https://answers.sap.com/tags/73554900100800003012" target="_blank" rel="noopener noreferrer">SAP BTP, Kyma runtime Q&amp;A Tags</A><BR /> <BR /> <SPAN style="font-size: 1rem">Be </SPAN><A style="font-size: 1rem" href="https://balsamiq.com/learn/articles/tips-presenting-wireframes/" target="_blank" rel="nofollow noopener noreferrer">balsamiq</A><SPAN style="font-size: 1rem">; </SPAN><BR /> <DIV><BR /> <BR /> <IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2021/07/SAP_Best_scrn_R_blk_pos-1.png" width="100%" /><BR /> <BR /> </DIV> 2023-07-28T08:44:58+02:00 https://community.sap.com/t5/crm-and-cx-blogs-by-members/technical-user-date-time-format-settings-change-in-c4c/ba-p/13581365 Technical User Date & Time format Settings Change in C4C 2023-08-23T05:21:58+02:00 Ananthu_R_Biju https://community.sap.com/t5/user/viewprofilepage/user-id/749864 Hello Developers!!!<BR /> <BR /> I hope you’re doing well.<BR /> <BR /> The blog is about the Date and time format in the response while querying a C4C OData service with a technical user through Postman. Later, we will also discuss how to assign a fixed time zone for a Technical User as well.<BR /> <BR /> <STRONG>Issue:</STRONG><BR /> <BR /> We created a KUT field in the UI and wrote code to capture the date &amp; time on save based on conditions. Then these fields were extended to the OData services as well.<BR /> <BR /> When we began to test the OData service via Postman I noticed that the newly added Data Time fields in the response body are being populated like below.<BR /> <PRE class="language-markup"><CODE>{<BR /> "d": {<BR /> "results": [<BR /> {<BR /> "__metadata": {<BR /> "uri": "Removed due to security reasons",<BR /> "type": "sapbyd.RPZVVVVVVVVVVVAD3DQueryResult"<BR /> },<BR /> "CVDOC_CREATEDATE_LOCAL": "/Date(1690070400000)/",<BR /> "CVDOC_ID": "1XX55",<BR /> "CVYLD0005Y_D2E80000A9": "5XX4",<BR /> <BR /> "CVs1A000000000031DB8A": "08/01/2023 11:49:45 INDIA"",<BR /> "CVs100000000000047919": "08/01/2023 09:49:45 INDIA",<BR /> <BR /> "TDSC_ZSALPHASE_01": "In-Progress",<BR /> "TUSER_ZSTATUS_CODE_01": "Converted"<BR /> }<BR /> ]<BR /> }<BR /> }</CODE></PRE><BR /> <EM>(I have separated the two new fields in the middle of the above response.)</EM><BR /> <BR /> Here in the response, we are receiving the time zone as INDIA for both fields. <SPAN style="font-size: 1rem">When I checked the Technical user time format, it was empty.</SPAN><BR /> <BR /> In our case, we are using a third-party middleware so they require all the possible time zones to be configured to transform the data, else the data being displayed will be irrelevant in the destination system.<BR /> <BR /> <STRONG>Resolution:</STRONG><BR /> <BR /> Hence the time zone configuration will be a lengthy process in the middleware we have s<EM>et a</EM><EM><STRONG> Time Zone</STRONG></EM> for that specific <STRONG>Technical user</STRONG> so whenever you query, in the response you will have the <STRONG>fixed time zone.</STRONG><BR /> <BR /> You may follow the below steps to navigate to Technical User settings &amp; view the current time zone for the user.<BR /> <BR /> <STRONG>1)</STRONG>&nbsp;Go to <STRONG>Administrator</STRONG>&nbsp;<STRONG>&gt;</STRONG> <STRONG>General Settings</STRONG>&nbsp;&amp; from there open&nbsp; <STRONG>Support and Technical Users.</STRONG><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/08/1-33.jpg" /></P><BR /> <P class="image_caption" style="text-align:center;font-style:italic;, Arial, sans-serif">Support and Technical Users</P><BR /> <STRONG>2)</STRONG> <STRONG>Click &amp; Open</STRONG> the Technical user, to view the current time zone settings before change.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/08/2-11.jpg" /></P><BR /> <P class="image_caption" style="text-align:center;font-style:italic;, Arial, sans-serif">Choose User</P><BR /> &nbsp;<BR /> <BR /> <STRONG>3)</STRONG> Scroll down and navigate to the <STRONG>Regional Settings, </STRONG>where you can see the current <STRONG>Time zone.</STRONG><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/08/3-7.jpg" /></P><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/08/4-6.jpg" /></P><BR /> <P class="image_caption" style="text-align:center;font-style:italic;, Arial, sans-serif">Current Time Zone</P><BR /> &nbsp;<BR /> <BR /> <STRONG>Kindly follow the below steps to assign a constant Time Zone for the Technical User.</STRONG><BR /> <BR /> <STRONG>1) Login</STRONG> to C4C using <STRONG>Technical User.</STRONG><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/08/5-7.jpg" /></P><BR /> <P class="image_caption" style="text-align:center;font-style:italic;, Arial, sans-serif">Navigate to Settings</P><BR /> <STRONG>2)</STRONG> Go to<STRONG> My Settings &gt; Regional Settings</STRONG> &amp; Choose the preferred time zone.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/08/4-7.jpg" /></P><BR /> <P class="image_caption" style="text-align:center;font-style:italic;, Arial, sans-serif">Time Zone Changed</P><BR /> <STRONG>Result:</STRONG><BR /> <BR /> When we set a fixed time zone for the Interface/Technical User. Thereafter, the response had a constant Time Zone.<BR /> <BR /> The below sample response will give you the result of the change.<BR /> <PRE class="language-abap"><CODE>{<BR /> "d": {<BR /> "results": [<BR /> {<BR /> "__metadata": {<BR /> "uri": "Removed due to Privacy reasons",<BR /> "type": "sapbyd.RPZVVVVVVVVVVVAD3DQueryResult"<BR /> },<BR /> "CVDOC_CREATEDATE_LOCAL": "/Date(1690070400000)/",<BR /> "CVDOC_ID": "1XX55",<BR /> "CVYLD0005Y_D2E80000A9": "5XX4",<BR /> <BR /> "CVs1A000000000031DB8A": "08/01/2023 11:49:45 UTC+3"",<BR /> "CVs100000000000047919": "08/01/2023 09:49:45 UTC+3",<BR /> <BR /> "TDSC_ZSALPHASE_01": "In-Progress",<BR /> "TUSER_ZSTATUS_CODE_01": "Converted"<BR /> }<BR /> ]<BR /> }<BR /> }</CODE></PRE><BR /> &nbsp;<BR /> <BR /> Hope you enjoyed the blog. We have a lot more coming, so do like and follow for more such content.<BR /> <BR /> Bye bye!! <span class="lia-unicode-emoji" title=":slightly_smiling_face:">🙂</span><BR /> <BR /> <STRONG>Ananthu R Biju</STRONG><BR /> <BR /> <STRONG>Senior C4C Consultant</STRONG> 2023-08-23T05:21:58+02:00 https://community.sap.com/t5/technology-blogs-by-members/sap-btp-destinations-in-a-nutshell-part-3-oauth-2-0-client-credentials/ba-p/13577101 SAP BTP Destinations in a nutshell Part 3 - OAuth 2.0 Client Credentials 2023-10-08T09:15:07+02:00 JakobFra https://community.sap.com/t5/user/viewprofilepage/user-id/178619 <H1 id="toc-hId-834959648">Introduction</H1><BR /> The goal of this series is to introduce the different destination types of the SAP BTP, to show how they work and also to make them tangible with basic and easy to execute code examples. In parts one and two of this series, I looked at the basics, as well as the simplest destination types, NoAuthentication and BasicAuthentication. In this part, I'll dive into a more complex topic for the first time: I'll show you how to implement an OAuth 2.0 client credentials flow using Destination.<BR /> <H1 id="toc-hId-638446143">OAuth 2.0</H1><BR /> <P id="ember595" class="ember-view reader-content-blocks__paragraph">Before I turn to the concrete scenario and implementation, I will first take a closer look at the topic of OAuth. Most people in the IT environment have come across this term before, and a majority is still able to provide information when it comes to explaining at a high-level what it is and what it is used for. But as soon as it comes to the technical details, the exact workings of the protocols, the different authentication flows, etc., many (including me) quickly get tripped up. But fortunately I'm not alone in providing the most important information about OAuth, because there are also a large number of wonderful people who have a very deep understanding of the subject and are willing to document this knowledge and make it digitally available to their fellow world in an easy to understand way. One resource I came across a couple of years ago that has helped sharpen my understanding of this topic is this talk by Nate Barbettini:&nbsp;<A href="https://www.youtube.com/watch?v=996OiexHze0" target="_blank" rel="nofollow noopener noreferrer">https://www.youtube.com/watch?v=996OiexHze0</A>&nbsp;I can highly recommend this video to anyone who would like to learn more about OAuth 2.0 (and for good measure, OIDC) or is looking for a simple yet solid introduction to the topic. The investment of this one hour is definitely worth it.</P><BR /> <P id="ember596" class="ember-view reader-content-blocks__paragraph">For those who are in a hurry, here is the most important information in a nutshell:</P><BR /> <P id="ember597" class="ember-view reader-content-blocks__paragraph">OAuth 2.0 is an open protocol that allows standardized, secure API authorization for desktop, web and mobile applications. This also covers the scenario of access delegation, i.e. that an application gets access to certain data or functionalities of another application with the permission of the user. Classic example: an application is granted permission by a user to send posts on Facebook or read contact data on their behalf.</P><BR /> <BR /> <H2 id="toc-hId-571015357">4 Roles</H2><BR /> <P id="ember599" class="ember-view reader-content-blocks__paragraph"><STRONG>Resource Owner</STRONG>&nbsp;- The owner of a resource (data). As a rule, this is simply a user, i.e. the person sitting in front of the computer / smartphone / tablet / ...</P><BR /> <P id="ember600" class="ember-view reader-content-blocks__paragraph"><STRONG>Resource Server</STRONG>&nbsp;- This is the application that stores the resources (data) of the resource owner (user)</P><BR /> <P id="ember601" class="ember-view reader-content-blocks__paragraph"><STRONG>Client</STRONG>&nbsp;- The client is the third-party application that wants to access resources (data) of the resource server on behalf of the resource owner (user) and needs a token for authentication that contains the corresponding authorization grant (so to speak, the proof that the client has received permission from the resource owner to access the resource server)</P><BR /> <P id="ember602" class="ember-view reader-content-blocks__paragraph"><STRONG>Authorization Server</STRONG>&nbsp;- The Authorization Server is the instance that manages Authorization grants and issues the tokens (these are usually JWT (JSON Web Tokens), i.e. JSON objects that contain the relevant token information) that authorize the client to access the Resource Server on behalf of the Resource Owner. In some cases, Resource Server and Authorization Server are identical, but often they are separate instances</P><BR /> <BR /> <H2 id="ember603" class="ember-view" id="toc-hId-374501852">Client Credentials Flow</H2><BR /> Depending on the specific use case, there are different flows in the OAuth 2.0 standard. In this part of the series, we will look at the client credentials flow. In order for a client to access a resource server, it must be registered with the Authorization Server, for each registered client there are client credentials, these are ultimately username and password. In the client credentials flow, the client also acts as the resource owner, because it does not obtain delegated access to the resource server, but instead requests a token for itself from the authentication server (using basic authentication with the client credentials) in order to then authenticate itself to the resource server with its own (technical) identity outside of a user context.<BR /> <H1 id="ember605" class="ember-view" id="toc-hId-48905628">XSUAA</H1><BR /> <BLOCKQUOTE>The XSUAA service, inside of the SAP BTP, handles the authorization flow between users, identity providers, and the applications or services. The XSUAA service is an internal development from SAP dedicated for the SAP BTP. In the Cloud Foundry project, there is an open-source component called UAA. UAA is an OAuth provider which takes care of authentication and authorization. SAP used the base of UAA and extended it with SAP specific features to be used in SAP BTP.</BLOCKQUOTE><BR /> <A href="https://learning.sap.com/learning-journey/discover-sap-business-technology-platform/illustrating-sap-authorization-and-trust-management-service-xsuaa-_b9fde282-4cff-4dca-b146-7c8f8dde9955" target="test_blank" rel="noopener noreferrer">https://learning.sap.com/learning-journey/discover-sap-business-technology-platform/illustrating-sap-authorization-and-trust-management-service-xsuaa-_b9fde282-4cff-4dca-b146-7c8f8dde9955</A><BR /> <BR /> In the context of OAuth 2.0, XSUAA is acting as the authentication server, i.e. it manages authorization grants and issues and validates JWT tokens. Important to know is, that there is always one XSUAA service instance per subaccount. As you will also later see in the concrete example, it is best practice to bind a dedicated XSUAA "service" resource to every application service (in our example: Client and Server). It took me a while to understand that those XSUAA services are not real running services in terms of a deployed container or something similar, but actually this are "only" pairs of Client ID and Client Secret (plus some additional meta information) that are injected into the application environment variables (VCAP_SERVICES). I.e. this binding represents a client in the sense of OAuth 2.0 terminology.<BR /> <H1 id="ember609" class="ember-view" id="toc-hId--147607877">Cloud 2 Cloud - OAuth 2.0 Client Credentials</H1><BR /> <A href="https://github.com/jfranken/sap-btp-destinations/tree/cloud-2-cloud-oauth2-client-credentials" target="test_blank" rel="nofollow noopener noreferrer">https://github.com/jfranken/sap-btp-destinations/tree/cloud-2-cloud-oauth2-client-credentials</A><BR /> <BR /> This all sounds rather abstract so far, so at this point I will fall back on our well-known example from the previous parts of this series to illustrate the use case:<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/10/Bildschirmfoto-2023-10-03-um-17.09.00.png" /></P><BR /> In this scenario, the BTP Destinations Enthusiast acts as the resource owner, the server app is the resource server, and XSUAA represents the authorization server. When the user calls the client/helloWorldClientPlain(), the client app subsequently attempts to access the /server/helloWorldServer() endpoint upon execution, but not on behalf of the user, but in this scenarios by means of technical client credentials. This endpoint is secured using XSUAA, which means that the server app expects a JWT token in the request header, which is issued and validated by XSUAA. To obtain this token, the client makes use of an according OAuth2ClientCredentials destination in the destination service.<BR /> <H2 id="ember614" class="ember-view" id="toc-hId--215038663">Server Implementation</H2><BR /> <P id="ember615" class="ember-view reader-content-blocks__paragraph">At first, I will show you the basics of the implementation of the server app.</P><BR /> <P id="ember616" class="ember-view reader-content-blocks__paragraph">To be able to secure any endpoint of this service via XSUAA, we need to establish a binding between server app and XSUAA. This is done in the mta.yaml file that we use for the server app deployment:</P><BR /> <BR /> <PRE class="language-javascript"><CODE>...<BR /> resources:<BR /> ... <BR /> - name: xsuaa-server-service<BR /> type: org.cloudfoundry.managed-service<BR /> parameters:<BR /> service: xsuaa<BR /> service-plan: application<BR /> service-name: xsuaa-server-service</CODE></PRE><BR /> In addition, it is required to enable JWT authentication. With SAP CAP, this is pretty staightforward within the cds configuration, which is located in the .cdsrc.js:<BR /> <PRE class="language-javascript"><CODE>{<BR /> "requires": {<BR /> "auth": {<BR /> "kind": "jwt-auth"<BR /> },<BR /> "uaa": {<BR /> "kind": "xsuaa"<BR /> }<BR /> }<BR /> }</CODE></PRE><BR /> Authentication checks can be added by means of annotations which can be added in the service CDS files (the example below shows the server-service.cds file), either on service level or for single entities / functions / actions. In the given example, I only add a very rudimentary check that requires nothing else than the caller to be authenticated at all (i.e. sending a valid JWT token, authenticated-user is an according pseudo role). It is also possible to check for concrete role assignments within the annotation, which is in real world scenarios normally the case, however, since this series aims at keeping the focus on the pure communication flow between the different instances, I try to keep it as simple as possible:<BR /> <PRE class="language-javascript"><CODE>service ServerService @(requires: 'authenticated-user') {<BR /> function helloWorldServer() returns String;<BR /> }</CODE></PRE><BR /> The service implementation within the file server-service.js isn't very spectacular and should be familiar to the attentive readers of the first two parts of the series:<BR /> <PRE class="language-javascript"><CODE>module.exports = async (srv) =&gt; {<BR /> srv.on('helloWorldServer', async (req) =&gt; {<BR /> return 'Hello World from Server'<BR /> })<BR /> }</CODE></PRE><BR /> <H2 id="ember620" class="ember-view" id="toc-hId--411552168">Destination</H2><BR /> As described above, the client app needs to use a destination to obtain a valid JWT token that allows access to the endpoint of the server app, which is secured via XSUAA. The most important aspect here is that I store the client credentials from the XSUAA binding of the&nbsp;<STRONG>server app</STRONG>&nbsp;in the destination, because these represent the OAuth 2.0 client that is authorized to access the server app. The destination configuration in detail is as follows:<BR /> <UL><BR /> <LI>Name: Server</LI><BR /> <LI>Type: HTTP</LI><BR /> <LI>URL:&nbsp;https://${SERVER_APP_ROUTE}/server/helloWorldServer()</LI><BR /> <LI>ProxyType: Internet</LI><BR /> <LI>Authentication: OAuth2ClientCredentials</LI><BR /> <LI>Client ID: Server XSUAA Client ID from Service Binding</LI><BR /> <LI>Client Secret: Server XSUAA Client Secret from Service Binding</LI><BR /> <LI>Token Service URL:&nbsp;https://????????trial.authentication.????.hana.ondemand.com/oauth/token</LI><BR /> </UL><BR /> Please check the README.md file in the github repo. There you find a detailed description how you can find the concrete URLs and credentials via the BTP Cockpit and the Cloud Foundry CLI.<BR /> <H2 id="ember624" class="ember-view" id="toc-hId--608065673">Client Implementation</H2><BR /> As always, the client includes two alternative implementations. On the one hand, the server call via Cloud SDK, and on the other hand, a plain variant that illustrates the communication processes step by step.<BR /> <H3 id="toc-hId--675496459"><STRONG>Cloud SDK</STRONG></H3><BR /> <PRE class="language-javascript"><CODE>srv.on('helloWorldClientCloudSDK', async () =&gt; {<BR /> return executeHttpRequest({ <BR /> destinationName: 'Server' <BR /> }).then((response) =&gt; response.data)<BR /> })</CODE></PRE><BR /> <H3 id="toc-hId--947241333">Plain</H3><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/10/Bildschirmfoto-2023-09-27-um-07.45.19.png" /></P><BR /> First, the client authenticates against XSUAA with the client credentials from the destination service binding. I.e. here we already have the first client credentials flow to obtain a token that allows the client app to access the destination service. Afterwards, the client app requests the destination "Server" from the destination service, which is described in the chapter above. During this call, the destination service executes another client credentials flow and adds the token into the response which is then sent back to the client app. This could already be used to access the endpoint of the server app. However, for demonstration purposes, the client app implementation triggers another client credentials flow against XSUAA with the client credentials of the destination configuration.<BR /> <PRE class="language-javascript"><CODE>srv.on('helloWorldClientPlain', async () =&gt; {<BR /> // get all the necessary destination service parameters from the <BR /> // service binding in the VCAP_SERVICES env variable<BR /> const vcapServices = JSON.parse(process.env.VCAP_SERVICES)<BR /> const destinationServiceUrl =<BR /> vcapServices.destination[0].credentials.uri + <BR /> '/destination-configuration/v1/destinations/'<BR /> const destinationServiceClientId = <BR /> vcapServices.destination[0].credentials.clientid<BR /> const destinationServiceClientSecret = <BR /> vcapServices.destination[0].credentials.clientsecret<BR /> const destinationServiceTokenUrl = <BR /> vcapServices.destination[0].credentials.url + <BR /> '/oauth/token?grant_type=client_credentials'<BR /> <BR /> // before we can fetch the destination from the destination <BR /> // service, we need to retrieve an auth token<BR /> const token = await axios.post(<BR /> destinationServiceTokenUrl, <BR /> null, <BR /> {<BR /> headers: {<BR /> authorization: 'Basic ' + <BR /> Buffer.from(<BR /> destinationServiceClientId + <BR /> ':' + <BR /> destinationServiceClientSecret'<BR /> ).toString('base64'),<BR /> },<BR /> }<BR /> )<BR /> const destinationServiceToken = token.data.access_token<BR /> <BR /> // with this token, we can now request the "Server" destination <BR /> // from the destination service<BR /> const headers = {<BR /> authorization: 'Bearer ' + destinationServiceToken,<BR /> }<BR /> const destinationResult = await axios.get(<BR /> destinationServiceUrl + 'Server', <BR /> { headers }<BR /> )<BR /> const destination = destinationResult.data<BR /> <BR /> // now, we use the retrieved the destination information to send <BR /> // a HTTP request to the token service endpoint;<BR /> // to authenticate, we take the Client ID attribute and the <BR /> // Client Secret attribute from the destination,<BR /> // encode ClientId:ClientSecret to Base64 and send the resulting <BR /> // string prefixed with "Basic " as Authorization<BR /> // header of the request;<BR /> // as a response, we receive a JWT token that we can then use to <BR /> // authenticate against the server<BR /> // alternatively, the JWT token could directly be fetched from <BR /> // destination.authTokens[0].value<BR /> const jwtTokenResponse = await axios.get(<BR /> destination.destinationConfiguration.tokenServiceURL + <BR /> '?grant_type=client_credentials', <BR /> {<BR /> headers: {<BR /> Authorization: 'Basic ' +<BR /> btoa(destination.destinationConfiguration.clientId + <BR /> ':' + <BR /> destination.destinationConfiguration.clientSecret),<BR /> }<BR /> }<BR /> )<BR /> const jwtToken = jwtTokenResponse.data.access_token<BR /> <BR /> // here we call the server instance with the bearer token we <BR /> // received from the token service endpoint<BR /> const destinationResponse = await axios.get(<BR /> destination.destinationConfiguration.URL, <BR /> {<BR /> headers: {<BR /> Authorization: 'Bearer ' + jwtToken,<BR /> },<BR /> }<BR /> )<BR /> return destinationResponse.data<BR /> })</CODE></PRE><BR /> <H2 id="toc-hId--850351831">Execution</H2><BR /> Once the client and server are deployed and the destination is configured correctly, calls to both client endpoints should return the following result:<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/10/1684662117403.png" /></P><BR /> That's it! In the next part of this series, I will go one step further. Instead of using technical client credentials, I will show you how you can use OAuth2TokenExchange destinations with authorization delegation. The client app will call the server app by propagating the identity of the user who calls the client endpoint in the beginning, i.e. we will cover one of the core scenarios for which OAuth 2.0 has been invented.<BR /> <H1 id="toc-hId--753462329">Disclaimer</H1><BR /> The code examples provided are&nbsp;<STRONG>not suitable</STRONG>&nbsp;to be transferred 1:1 into productive implementations, but they only serve to illustrate the functioning of destinations and Destination Service. In some cases, the interaction with the Destination Service is deliberately implemented in a “cumbersome” manner in order to illustrate the communication processes as explicitly and in detail as possible. SAP CAP and the SAP Cloud SDK provide various functionality to simplify and abstract the use of destinations. However, this would be more of a hindrance than a benefit to the purpose of the illustration. 2023-10-08T09:15:07+02:00 https://community.sap.com/t5/technology-blogs-by-sap/abap-rfc-connectivity-from-btp-python-buildpack/ba-p/13575348 ABAP RFC connectivity from BTP Python buildpack 2023-10-30T15:52:39+01:00 Srdjan https://community.sap.com/t5/user/viewprofilepage/user-id/174007 ABAP RFC connectivity from BTP to ABAP systems is supported by <A href="https://help.sap.com/docs/connectivity/sap-btp-connectivity-cf/cloud-connector" target="_blank" rel="noopener noreferrer">SAP Cloud Connector</A>, for BTP Java runtime only. This blog describes the RFC connectivity enablement for Python runtime, so that Python BTP applications can consume ABAP RFCs, as described in <EM>Deployment options </EM>section of <A href="https://blogs.sap.com/2023/10/12/powerful-web-applications-with-old-and-new-abap-systems" target="_blank" rel="noopener noreferrer">Powerful web applications with old and new ABAP systems</A> and related blogs.<BR /> <BR /> Our "hello world" example is BTP Python buildpack, with <A href="https://flask.palletsprojects.com/" target="_blank" rel="nofollow noopener noreferrer">Flask</A> server, <A href="https://github.com/SAP/PyRFC" target="_blank" rel="nofollow noopener noreferrer">SAP/PyRFC</A> and <A href="https://support.sap.com/en/product/connectors/nwrfcsdk.html" target="_blank" rel="noopener noreferrer">SAP NW RFC SDK</A>.<BR /> <BR /> The example source code: <A href="https://github.com/SAP-samples/node-rfc-samples/tree/main/integration/pyrfc_btp" target="_blank" rel="nofollow noopener noreferrer">SAP-samples/node-rfc-samples/integration/pyrfc_btp</A> can be deployed on BTP, or tested locally inside <A href="https://github.com/SAP/fundamental-tools/blob/main/docker/btp-cflinuxfs4.Dockerfile" target="_blank" rel="nofollow noopener noreferrer">SAP/fundamental-tools/docker/btp_cflinuxfs4.Dockerfile</A> docker container.<BR /> <BR /> ABAP RFC connectivity from Python on Kyma works practically out of the box, using <A href="https://github.com/SAP/PyRFC" target="_blank" rel="nofollow noopener noreferrer">SAP/PyRFC</A> and <A href="https://support.sap.com/en/product/connectors/nwrfcsdk.html" target="_blank" rel="noopener noreferrer">SAP NW RFC SDK</A> inside docker container. Try <A href="http://SAP/fundamental-tools/blob/main/docker/cflinuxfs4.Dockerfile" target="_blank" rel="nofollow noopener noreferrer">SAP/fundamental-tools/docker/cflinuxfs4.Dockerfile</A> for example.<BR /> <H2 id="toc-hId-963984838">Preparation</H2><BR /> The ABAP RFC enablement of BTP Python buildpack requires the installation of&nbsp; <A href="https://github.com/SAP/PyRFC" target="_blank" rel="nofollow noopener noreferrer">SAP/PyRFC</A> package and <A href="https://support.sap.com/en/product/connectors/nwrfcsdk.html" target="_blank" rel="noopener noreferrer">SAP NW RFC SDK</A> registration on BTP host instance. It is similar to RFC enablement of NodeJS buildpack: <A href="https://blogs.sap.com/2023/10/26/abap-rfc-connect…ode.js-buildpack/" target="_blank" rel="noopener noreferrer">ABAP RFC connectivity from BTP Node.JS buildpack and Kyma,</A><BR /> <BR /> Python buildpack structure is shown on figure below<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/10/Buildpack-1.png" height="337" width="279" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">Buildpack</P><BR /> <A href="https://support.sap.com/en/product/connectors/nwrfcsdk.html" target="_blank" rel="noopener noreferrer">SAP NW RFC SDK</A> files for Linux x64 are copied to <EM>app/nwrfcsdk</EM> folder and excluded from repository, in <EM>.gitignore</EM>.<BR /> <BLOCKQUOTE>SAP NW RFC SDK is <STRONG>not included</STRONG> in <A href="https://github.com/sap/PyRFC" target="_blank" rel="nofollow noopener noreferrer">SAP/PyRFC</A> because the license is different. SAP Support Portal is the only allowed public distribution channel for SAP NW RFC SDK.</BLOCKQUOTE><BR /> The <EM>nwrfcsdk</EM> folder is added to app <EM>MANIFEST.in,</EM> to be included in app deployment<BR /> <BR /> <A href="https://github.com/SAP-samples/node-rfc-samples/blob/main/integration/pyrfc_btp/buildpack/app/MANIFEST.in" target="_blank" rel="nofollow noopener noreferrer">buildpack/app/MANIFEST.in</A><BR /> <PRE class="language-abap"><CODE>include nwrfcsdk<BR /> include sapnwrfc.ini</CODE></PRE><BR /> SAP NW RFC SDK home and library paths are added to buildpack <EM>manifest.yaml</EM>, for build and runtime registration<BR /> <BR /> <A href="https://github.com/SAP-samples/node-rfc-samples/blob/main/integration/pyrfc_btp/buildpack/manifest.yaml#L6" target="_blank" rel="nofollow noopener noreferrer">buildpack/manifest.yaml</A><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/10/Screenshot-2023-10-30-at-15.35.21.png" height="154" width="474" /></P><BR /> <P class="image_caption" style="text-align: center;font-style: italic">buildpack/manifest.yaml</P><BR /> &nbsp;<BR /> <H2 id="toc-hId-767471333">Local test</H2><BR /> <PRE class="language-python"><CODE>cd buildpack/app<BR /> pip install pyrfc flask<BR /> # do not install from requirements.txt unless your notebook runs on Linux<BR /> <BR /> python serve.py<BR /> * Serving Flask app 'serve'<BR /> * Debug mode: off<BR /> * Running on all addresses (0.0.0.0)<BR /> * Running on <A href="http://127.0.0.1:3000" target="test_blank" rel="nofollow noopener noreferrer">http://127.0.0.1:3000</A><BR /> * Running on <A href="http://10.98.207.132:3000" target="test_blank" rel="nofollow noopener noreferrer">http://10.98.207.132:3000</A></CODE></PRE><BR /> PyRFC and SAP NW RFC SDK are loaded and PyRFC version shown below<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/10/server.png" height="115" width="341" /></P><BR /> <P class="image_caption" style="font-style: italic;font-family: SAPRegular, 'Helvetica Neue', Arial, sans-serif;text-align: left">Flask server on <A href="http://127.0.0.1:3000" target="test_blank" rel="nofollow noopener noreferrer">http://127.0.0.1:3000</A></P><BR /> &nbsp;<BR /> <H2 id="toc-hId-570957828">BTP Deployment</H2><BR /> <PRE class="language-abap"><CODE>cd buildpack<BR /> cf push (py3.11.6) main<BR /> Pushing app pyrfcapp to org &lt;redacted&gt; / space dev as &lt;redacted&gt;...<BR /> Applying manifest file &lt;redacted&gt;/node-rfc-samples/integration/pyrfc_btp/buildpack/manifest.yaml...<BR /> <BR /> Updating with these attributes...<BR /> ---<BR /> applications:<BR /> - name: pyrfcapp<BR /> path: &lt;redacted&gt;/node-rfc-samples/integration/pyrfc_btp/buildpack/app<BR /> memory: 128M<BR /> + default-route: true<BR /> stack: cflinuxfs4<BR /> buildpacks:<BR /> <A href="https://github.com/cloudfoundry/python-buildpack.git" target="test_blank" rel="nofollow noopener noreferrer">https://github.com/cloudfoundry/python-buildpack.git</A><BR /> command: python serve.py<BR /> env:<BR /> LD_LIBRARY_PATH: /home/vcap/app/nwrfcsdk/lib<BR /> SAPNWRFC_HOME: /home/vcap/app/nwrfcsdk<BR /> routes:<BR /> - route: pyrfcapp.cfapps.eu10.hana.ondemand.com<BR /> Manifest applied<BR /> Packaging files to upload...<BR /> Uploading files...<BR /> <BR /> Instances starting...<BR /> <BR /> name: pyrfcapp<BR /> requested state: started<BR /> routes: pyrfcapp.cfapps.eu10.hana.ondemand.com<BR /> last uploaded: Mon 30 Oct 15:44:40 CET 2023<BR /> stack: cflinuxfs4<BR /> buildpacks: <BR /> name version detect output buildpack name<BR /> <A href="https://github.com/cloudfoundry/python-buildpack.git" target="test_blank" rel="nofollow noopener noreferrer">https://github.com/cloudfoundry/python-buildpack.git</A> 1.8.15 python python<BR /> <BR /> type: web<BR /> sidecars: <BR /> instances: 1/1<BR /> memory usage: 128M<BR /> start command: python serve.py<BR /> state since cpu memory disk logging details<BR /> #0 running 2023-10-30T14:44:56Z 1.1% 31M of 128M 372.2M of 1G 0/s of unlimited</CODE></PRE><BR /> When finished, the test route <A href="https://pyrfcapp.cfapps.eu10.hana.ondemand.com/" target="_blank" rel="nofollow noopener noreferrer">https://pyrfcapp.cfapps.eu10.hana.ondemand.com/</A> shows the same result as local test:<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/10/cfserver.png" height="91" width="486" /></P><BR /> <P style="overflow: hidden;margin-bottom: 0px">PyRFC with SAP NW RFC SDK on BTP</P><BR /> <BR /> <H2 id="toc-hId-374444323">Next Steps</H2><BR /> Once the RFC connectivity from Python is enabled, the connection parameters for ABAP system shall be configured, as described in <EM>Deployment options</EM> section of <A href="https://blogs.sap.com/2023/10/12/powerful-web-applications-with-old-and-new-abap-systems" target="_blank" rel="noopener noreferrer">Powerful web applications with old and new ABAP systems</A> and in related blogs<BR /> <UL><BR /> <LI><A href="https://blogs.sap.com/2021/07/19/websocket-rfc-rfc-for-the-internet/" target="_blank" rel="noopener noreferrer">WebSocket RFC – RFC For the Internet</A></LI><BR /> <LI><A href="https://blogs.sap.com/?p=1616280" target="_blank" rel="noopener noreferrer">WebSocket RFC to Cloud Using SAP Business Connector</A></LI><BR /> </UL><BR /> Hope you enjoyed reading and stay tuned for more updates. 2023-10-30T15:52:39+01:00 https://community.sap.com/t5/technology-blogs-by-members/transient-field-s-usage-in-c4c-custom-development-in-event-afterloading/ba-p/13581440 Transient field’s usage in C4C custom development in Event-AfterLoading.absl script file 2023-11-22T00:36:31+01:00 Nithish_Kumar https://community.sap.com/t5/user/viewprofilepage/user-id/174179 In this blog, I am going to provide a solution for a product gap using transient field in custom development.<BR /> <BR /> Below requirement has been taken as an example to explain the Transient field’s usage in a custom development using C4C Cloud application studio.<BR /> <BR /> <STRONG>Problem statement:</STRONG> Appointment is cancelled when one of the attendee cancels in C4C<BR /> <BR /> <STRONG><U>Requirement</U></STRONG>: When an attendee cancels the appointment in C4C (synced teams meeting from outlook), system is cancelling the appointment and sending the cancellation notification to all attendees though he is not the organizer. This is a gap in the solution. Ideally only organizer should be able to cancel the appointment and not the attendees.<BR /> <BR /> <STRONG><U>Challenge</U></STRONG>: As per the business custom logic this cannot be achieved from the SAP C4C UI. Only option is to do in SAP Cloud application studio. We need to develop the solution at the time of After-loading the appointment, but the challenge is custom KUT or standard SAP field’s can’t be modified because fields are read-only in after-loading event of the business object.<BR /> <BR /> <STRONG><U>Solution</U></STRONG>: To achieve this requirement, create a Transient Element (Field created in SDK) type indicator in business object extension and development custom logic updating this transient field to ‘True’ or ‘False’. Now when an user open an appointment in the after-loading event our custom logic will run and update transient element accordingly. Based on this transient element we can create a validation rule in the adaptation and apply the rule to the standard actions.<BR /> <BR /> Below are the detailed steps with screenshots provided to achieve this custom development through SDK.<BR /> <BR /> <STRONG><U>Step1:</U></STRONG> First open a solution in the SDK and we need to create a Business object extension for Activity management and then create a Transient Element type Indicator in the main node with proper naming.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/11/Picture1-41.png" /></P><BR /> <STRONG><U>Step2:</U></STRONG> Create an Event-AfterLoading.absl script file under Root.node and write the custom logic as per the requirement.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/11/Picture2-32.png" /></P><BR /> <STRONG><U>Step3:</U></STRONG> Here is the logic that I have used for this development.<BR /> <PRE class="language-javascript"><CODE>import ABSL;<BR /> import AP.PC.IdentityManagement.Global;<BR /> import AP.Common.GDT;<BR /> import AP.FO.BusinessPartner.Global;<BR /> <BR /> //development for hiding actions complete &amp; cancel based on user loggedin with involved parties.<BR /> var lv_emp = Context.GetCurrentIdentityUUID();<BR /> <BR /> if(!lv_emp.IsInitial())<BR /> {<BR /> var query = Identity.QueryByElements;<BR /> // 2. Selection<BR /> var selectionParams = query.CreateSelectionParams();<BR /> selectionParams.Add(query.UUID.content, "I", "EQ", Context.GetCurrentIdentityUUID().content);<BR /> // Result<BR /> var resultData = query.ExecuteDataOnly(selectionParams);<BR /> if (resultData.Count() &gt; 0)<BR /> {<BR /> var lv_query = Employee.QueryByIdentification;<BR /> // 2. Selection<BR /> var lv_selectionParams = lv_query.CreateSelectionParams();<BR /> lv_selectionParams.Add(lv_query.UUID.content, "I", "EQ", resultData.GetFirst().BusinessPartnerUUID.content);<BR /> // Result<BR /> var lv_resultData = lv_query.Execute(lv_selectionParams);<BR /> var empname;<BR /> if(lv_resultData.CurrentCommon.GetFirst().IsSet())<BR /> {<BR /> if(!lv_resultData.CurrentCommon.GetFirst().BusinessPartnerFormattedName.IsInitial())<BR /> {<BR /> empname = lv_resultData.CurrentCommon.GetFirst().BusinessPartnerFormattedName;<BR /> }<BR /> } <BR /> if(this.Party.GetFirst().IsSet())<BR /> {<BR /> var lv_x = this.Party.Where(n =&gt; n.PartyName == empname);<BR /> if(this.Party.Count() &gt; 0 &amp;&amp; this.Party.Where(n =&gt; n.PartyName == empname).Count() &gt; 0)<BR /> {<BR /> if(lv_x.Where(n=&gt;n.RoleCode == "36").Count() != 0 &amp;&amp; lv_x.Where(n=&gt;n.RoleCode == "35").Count() == 0 &amp;&amp; lv_x.Where(n=&gt;n.RoleCode == "39").Count() == 0 )<BR /> {<BR /> this.GetFirst().Z_Action_Cancel = true;<BR /> }<BR /> }<BR /> else<BR /> {<BR /> this.GetFirst().Z_Action_Cancel = true;<BR /> }<BR /> }<BR /> }<BR /> }</CODE></PRE><BR /> <STRONG>Step4:</STRONG> Now we need to add the transient field to the Appointment header using UI designer.<BR /> <UL><BR /> <LI>Go to Administration &gt;&gt; Open UI Designer.</LI><BR /> <LI>Open COD_Appointment (TI screen) &gt;&gt; using Extensibility explorer add the transient field to the appointment header section( This field can be hidden from the frontend adaptation if not needed)</LI><BR /> </UL><BR /> <STRONG>Step5:</STRONG> Now Save and Activate the Event-AfterLoading.absl and .XBO and entire solution. Till this step we have done from the SDK side and moving to SAP C4C UI.<BR /> <BR /> <STRONG>Step6:</STRONG> Logon to SAP C4C with admin credentials &gt;&gt; Open Appointment’s Business object under activities &gt;&gt;Now open any Appointment and you will see the transient field which we have added at the header section(Default value as NO).<BR /> <BR /> <STRONG>Step7:</STRONG> Now Open Adaptation mode and click on the action’s menu &gt;&gt; Select the ‘Set as Cancelled’ &gt;&gt; Now create a validation rule and assign it under the visibility of the ‘Action Cancelled’.<BR /> <UL><BR /> <LI>The below images shows the logic that I have written in the Validation Rule.</LI><BR /> </UL><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/11/Picture3-29.png" /><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/11/Picture4-28.png" /></P><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/11/Picture5-28.png" /></P><BR /> Note: Transient field’s created from SDK can be extended to UI but are not visible in Validation Rule because transient field’s are not available at the database level, So I have copied the namespace of the transient field from the properties in UI Designer.<BR /> <BR /> <STRONG>Step8:</STRONG> Now test the scenario in the SAP C4C.<BR /> <BR /> Hope this blog is helpful and addresses one of the product gap in groupware integration. Please let me know for any queries in the comments section. 2023-11-22T00:36:31+01:00 https://community.sap.com/t5/technology-blogs-by-sap/released-sap-cloud-sdk-for-java-version-5/ba-p/13576668 Released: SAP Cloud SDK for Java Version 5 2023-12-07T00:32:08+01:00 Junjie https://community.sap.com/t5/user/viewprofilepage/user-id/126697 The SAP Cloud SDK for Java has recently launched its latest major version (v5) on <A href="https://central.sonatype.com/artifact/com.sap.cloud.sdk/sdk-bom/5.0.0" target="_blank" rel="nofollow noopener noreferrer">Maven Central</A>.<BR /> <BR /> In this blog post, we'll explore the key values and improvements that will assist in planning your upgrade to SDK version 5.<BR /> <H2 id="toc-hId-964017574">Open Source Migration</H2><BR /> One of the key highlights of SAP Cloud SDK for Java 5 is its commitment to open source migration. (<A href="https://github.com/SAP/cloud-sdk-java" target="_blank" rel="nofollow noopener noreferrer">repo</A>)<BR /> <BR /> Historically, the SAP Cloud SDK for JavaScript (<A href="https://github.com/SAP/cloud-sdk-js" target="_blank" rel="nofollow noopener noreferrer">repo</A>) has been open sourced since 2020 with very positive experience and feedback. Over the years, the community has asked for the second open source migration of the Java variant. Now, this is the answer from the team.<BR /> <BR /> This move not only enhances transparency but also invites developers to actively contribute to the SDK's evolution. By opening up the source code, the SDK becomes a truly community-driven project, allowing developers to play a direct role in shaping the future of the SDK.<BR /> <BR /> Please contact us via the GitHub issues (<A href="https://github.com/SAP/cloud-sdk-java/issues/new/choose" target="_blank" rel="nofollow noopener noreferrer">link</A>) for questions, bug fixes, or feature requests.<BR /> <BR /> If you want to contribute to the SDK, please check our <A href="https://github.com/SAP/cloud-sdk-java/blob/main/CONTRIBUTING.md" target="_blank" rel="nofollow noopener noreferrer">contribution guidelines</A>.<BR /> <H2 id="toc-hId-767504069">Support: Java 17, Spring 6 and Spring Boot 3</H2><BR /> The SAP Cloud SDK for Java version 5 brings native support for the modern versions in the Java ecosystem, including Java 17, Spring 6, and Spring Boot 3. This ensures that developers can leverage the full potential of Java/Spring, taking advantage of the latest features and improvements for optimising application development.<BR /> <BR /> The SAP Cloud SDK for Java is used by CAP (SAP Cloud Application Programming Model). As CAP version 2 needs Java 17 &amp; Spring Boot 3 as minimal versions, you will gain the best user experience, when upgrading to SDK version 5 together with CAP 2.<BR /> <BR /> For users who have already tried our experimental feature of the Java 17 support in SDK v4, potential workarounds are no longer needed.<BR /> <BR /> Check our <A href="https://sap.github.io/cloud-sdk/docs/java/guides/5.0-upgrade-steps" target="_blank" rel="nofollow noopener noreferrer">upgrade guide</A>&nbsp;for more details.<BR /> <H2 id="toc-hId-570990564">Support: Apache HttpClient 5</H2><BR /> In SDK version 4, the experimental feature introduced the use of Apache HttpClient v5. Now, as an official feature, developers can confidently benefit from robust APIs.<BR /> <BR /> You can find a minimal code example for using the HttpClient v5:<BR /> <PRE class="language-java"><CODE>Destination destination = DestinationAccessor.getDestination("my-destination");<BR /> HttpClient client = ApacheHttpClient5Accessor.getHttpClient(destination);</CODE></PRE><BR /> To compare the usage of the HttpClient v4, here is another example for the v4:<BR /> <PRE class="language-java"><CODE>Destination destination = DestinationAccessor.getDestination("my-destination");<BR /> HttpClient client = HttpClientAccessor.getHttpClient(destination);</CODE></PRE><BR /> The complete <A href="https://sap.github.io/cloud-sdk/docs/java/features/connectivity/http-client#general-usage" target="_blank" rel="nofollow noopener noreferrer">documentation</A> about the HttpClient v5 feature can be found here.<BR /> <H2 id="toc-hId-374477059">Improved Module Structure</H2><BR /> Thanks to the new platform agnostic maven module structure, as a user, you only need to add the essential dependency (com.sap.cloud.sdk:sdk-core) for most of the use cases, instead of "scp-cf" or "scp-neo" for dedicated platforms. As a result, your SDK related maven dependency tree should be cleaner and smaller.<BR /> <BR /> <SPAN lang="EN-US">In addition to that, users will also benefit from a simplified, more powerful, and more extensible connectivity API. </SPAN><SPAN lang="EN-US">For example, you can build a destination from destination properties, a map, or another destination:</SPAN><BR /> <PRE class="language-java"><CODE>DefaultHttpDestination.fromProperties(myDestinationProperties)<BR /> DefaultHttpDestination.fromMap(myMap)<BR /> DefaultHttpDestination.fromDestination(myDestination)</CODE></PRE><BR /> You can conveniently modify properties form an existing instance by using "toBuilder":<BR /> <PRE class="language-abap"><CODE>myHttpDestination.toBuilder()</CODE></PRE><BR /> Check our <A href="https://sap.github.io/cloud-sdk/docs/java/release-notes" target="_blank" rel="nofollow noopener noreferrer">release notes</A> for more details.<BR /> <BR /> Lastly, as a side note, SDK version 5 also provides complete support for the DwC (Deploy with Confidence) Orbits architecture. Check the DwC documentation for more details.<BR /> <H2 id="toc-hId-177963554">Recommendation</H2><BR /> We strongly recommend upgrading your SAP Cloud SDK for Java dependency to version 5 at your earliest convenience, as it introduces significant improvements and new capabilities. Although SDK v4 will remain in maintenance mode for another six months, active development has shifted to SDK v5.<BR /> <BR /> If you have any questions during the upgrading, please open an issue <A href="https://github.com/SAP/cloud-sdk-java/issues/new/choose" target="_blank" rel="nofollow noopener noreferrer">here</A>. 2023-12-07T00:32:08+01:00 https://community.sap.com/t5/technology-blogs-by-members/utilizing-sap-cloud-sdk-for-javascript-in-a-btp-proxy-app-for-non-web-apps/ba-p/13572792 Utilizing SAP Cloud SDK for JavaScript in a BTP Proxy App for non-Web-Apps to access onpremise SAP Systems 2023-12-31T03:44:52+01:00 WRoeckelein https://community.sap.com/t5/user/viewprofilepage/user-id/3438 <H1 id="toc-hId-834816739">Introduction</H1><BR /> Oftern there is a need for Apps running outside of the corporate network to access SAP onpremise systems. Using a Proxy App running in the BTP (Business Technology Platform) Cloud Foundry Environment utilizing the SAP Cloud Connector is a well known pattern for such requirements.<BR /> <BR /> However using the destination and connectivity service to get access to the tunnel to the onpremise systems is not trivial and is best done with the help of libraries.The approuter (cf. <A href="https://www.npmjs.com/package/@sap/approuter)" target="test_blank" rel="nofollow noopener noreferrer">https://www.npmjs.com/package/@sap/approuter)</A> is a well known and proven solution for this. However approuter is aimed at web applications. Using it for eg native applicatios is a bit troublesome.<BR /> <BR /> Since March 2019 there is also the SAP Cloud SDK for JavaScript (in the beginning known as the SAP S/4HANA Cloud SDK for JavaScript and also going by SAP Cloud SDK for Node.js) available. The http-client of this SDK completly handles the interaction with the destination and connectivity service, you just have to provide the destination name (please check out other features of this SDK, there is a lot of other useful stuff there!). This blog intends to give you some guidance for using this SDK for this porpose.<BR /> <H1 id="toc-hId-638303234">Basics</H1><BR /> The SDK is availabe in the public npm repository. Add the line<BR /> <PRE class="language-javascript"><CODE>"@sap-cloud-sdk/http-client": "^3.9.0",</CODE></PRE><BR /> <DIV><BR /> <DIV>to the dependencies section in your package.json. Use at least version 3.9.0 to avoid being hit by the xssec security vulnerability (cf. <A href="https://me.sap.com/notes/3411067" target="_blank" rel="noopener noreferrer">Security Note 3411067</A>).</DIV><BR /> <DIV></DIV><BR /> <DIV>In your JavaScript file to be run add</DIV><BR /> <DIV><BR /> <PRE class="language-javascript"><CODE>const httpclient = require('@sap-cloud-sdk/http-client');​</CODE></PRE><BR /> The object thus obtained follows the&nbsp;<A href="https://axios-http.com/" target="_blank" rel="noopener noreferrer nofollow">axios HTTP client</A> API with an added first object parameter (second parameter is compatible to RawAxiosRequestConfig), eg to make a POST call to an onpremise destination use this code<BR /> <BR /> </DIV><BR /> <DIV><BR /> <PRE class="language-javascript"><CODE>await httpclient.executeHttpRequest(<BR /> {<BR /> destinationName: 'MYDESTINATION'<BR /> },<BR /> { <BR /> method: 'POST',<BR /> url: "/sap/opu/odata/sap/ZMY_SERV_SRV/MyEntitySet",<BR /> headers: {<BR /> "Content-Type":"application/json; charset=utf-8",<BR /> "Accept":"application/json"<BR /> },<BR /> data: body<BR /> }<BR /> ).then(response =&gt; {<BR /> // use eg response.status and response.data <BR /> }).catch(err =&gt; {<BR /> // use eg err.code or message<BR /> });​</CODE></PRE><BR /> (Note: All code examples in this blog are just examples, do not use in your productive code, eg consider adding logging and a more robust coding)<BR /> <BR /> CSRF handling is done by default.<BR /> <BR /> </DIV><BR /> <H1 id="toc-hId-441789729">Proxy with Basic Authentication</H1><BR /> </DIV><BR /> <DIV>For a first simple proxy example we will use Basic Authentication from Outside and also Basic Authentication to the onpremise system. The latter is an easy brainer: Just use Basic Authentication as Authentication Type when defining the destination in the BTP cockpit:</DIV><BR /> <DIV></DIV><BR /> <DIV><BR /> <DIV><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/12/2023-12-30_22h51_36.png" /></DIV><BR /> <DIV>(Do yourself a favor and pay attention to the warning in the picture!)</DIV><BR /> <DIV>With such a destination you need merely give the destinationName in the example above.</DIV><BR /> </DIV><BR /> <DIV></DIV><BR /> <DIV>In the mta.yaml define the depencies to the destination and connectivity service:</DIV><BR /> <DIV><BR /> <PRE class="language-javascript"><CODE>...<BR /> modules:<BR /> - name: myproxy<BR /> type: nodejs<BR /> requires:<BR /> - name: myproxy-destination-service<BR /> parameters:<BR /> content-target: true<BR /> - name: myproxy-connectivity-service<BR /> parameters:<BR /> health-check-type: process<BR /> ...<BR /> resources:<BR /> - name: myproxy-destination-service<BR /> type: org.cloudfoundry.managed-service<BR /> parameters:<BR /> config:<BR /> version: 1.0.0<BR /> service: destination<BR /> service-name: myproxy-destination-service<BR /> service-plan: lite<BR /> - name: myproxy-connectivity-service<BR /> type: org.cloudfoundry.managed-service<BR /> parameters:<BR /> service: connectivity<BR /> service-plan: lite<BR /> </CODE></PRE><BR /> Health check is set to process because otherwise health check uses an unauthenticated HTTP access to / which won't work with our basic authentication requirement and thus would give constant app restarts.<BR /> <BR /> </DIV><BR /> <DIV><BR /> <DIV></DIV><BR /> <DIV>For the proxy function we use express and passport, ie in the package.json</DIV><BR /> <DIV><BR /> <PRE class="language-javascript"><CODE> "express": "^4.17.3",<BR /> "body-parser": "^1.20.2",<BR /> "passport": "^0.6.0",<BR /> "passport-http": "^0.3.0"</CODE></PRE><BR /> Preperation in the JavaScript file<BR /> <PRE class="language-javascript"><CODE>const express = require('express');<BR /> const bodyParser = require('body-parser')<BR /> const passport = require('passport');<BR /> const passportHTTP = require('passport-http');<BR /> <BR /> const auth_env = {login: process.env['AUTH_LOGIN'], password: process.env['AUTH_PASSWORD']};<BR /> const app = express();<BR /> passport.use(new passportHTTP.BasicStrategy(<BR /> function(username, password, done) {<BR /> if (username === auth_env.login &amp;&amp; password === auth_env.password) {<BR /> return done(null, username);<BR /> } else {<BR /> return done(null, false);<BR /> }<BR /> }<BR /> ));<BR /> app.use(passport.initialize());<BR /> app.use(passport.authenticate('basic', { session: false }));<BR /> app.use(bodyParser.text({ type: 'application/json' }));<BR /> ...<BR /> app.listen(process.env.PORT || 5000, function () {<BR /> console.log('Proxy app started');<BR /> });</CODE></PRE><BR /> and code for proxying a POST call<BR /> <PRE class="language-javascript"><CODE>app.post('/MyEntitySet', async (req, res) =&gt; {<BR /> if (!req.user) { res.sendStatus(403); return; }<BR /> await httpclient.executeHttpRequest(<BR /> {<BR /> destinationName: 'MY_DESTINATION'<BR /> },<BR /> { <BR /> method: 'POST',<BR /> url: "/sap/opu/odata/sap/ZMY_SERV_SRV/MyEntitySet",<BR /> headers: {<BR /> "Content-Type":"application/json; charset=utf-8",<BR /> "Accept":"application/json"<BR /> },<BR /> data: req.body<BR /> }<BR /> ).then(response =&gt; {<BR /> res.send(response.data);<BR /> }).catch(err =&gt; {<BR /> res.status(500).send('Backend Error');<BR /> }); <BR /> });</CODE></PRE><BR /> (in real life you might want to use wildcards and parse req.url)<BR /> <H1 id="toc-hId-245276224">Proxy with Principal Propagation</H1><BR /> Principal Propagation means the client needs to authenticate the user aka principal against the BTP and obtain tokens which need to be stored securely. When accessing the proxy the token needs to be presented. The token is then forwared to the cloud connector which generates authorization info using the principal for the onpremise system (configuring cloud connector and onpremise systems to achieve this is beyond the scope of this blog).<BR /> <BR /> In this example the native client needs to obtain a JWT token and send it along with request to the proxy. The JWT token will eg be obtained and renewed by utilizing SAML 2.0 and OAuth 2 protocols with the XSUAA service, cf. <A href="https://sap.github.io/cloud-sdk/docs/java/guides/cloud-foundry-xsuaa-service" target="test_blank" rel="nofollow noopener noreferrer">https://sap.github.io/cloud-sdk/docs/java/guides/cloud-foundry-xsuaa-service</A> . The native client should use libraries for this tasks (this is however beyond the scope of this blog). After deploying the proxy app to the BTP go to the deployed app in the BTP cockpit, select "Service Bindings" on the left and click on "Show sensitive data" to obtain the data for the libraries. You need<BR /> <UL><BR /> <LI>token_service_url : Add /oauth/authorize for the SAML 2.0 login endpoint, /oauth/token for the OAuth 2.0 endpoint and /logout.do for the SAML 2.0 logout endpoint</LI><BR /> <LI>clientid and clientsecret for the OAuth 2 protocol</LI><BR /> </UL><BR /> Also go to "Scopes" on the left and use the displayed scope name in the OAuth 2 protocol.<BR /> <BR /> The configuration for xsuaa in the xs-security.json file is needed (add scopes and role-templates as needed):<BR /> <PRE class="language-javascript"><CODE>{<BR /> "scopes": [<BR /> {<BR /> "name": "$XSAPPNAME.access",<BR /> "description": "Access"<BR /> }<BR /> ],<BR /> "role-templates": [<BR /> {<BR /> "name": "Access",<BR /> "default-role-name": "My Proxy Access Authorization",<BR /> "scope-references": [<BR /> "$XSAPPNAME.access"<BR /> ]<BR /> }<BR /> ],<BR /> "oauth2-configuration": {<BR /> "redirect-uris": [<BR /> "http://localhost:9999/success"<BR /> ]<BR /> }<BR /> }</CODE></PRE><BR /> Use Redirect-URIs as needed by the native libraries (can also use different schemes than http oder https as commonly used on mobile OS).<BR /> <BR /> </DIV><BR /> In the mta.yaml there is now a depedency to the xsuaa service (add role-collections as needed):<BR /> <DIV><BR /> <PRE class="language-javascript"><CODE> requires:<BR /> - name: my_proxy-uaa<BR /> ...<BR /> resources:<BR /> - name: my_proxy-uaa<BR /> type: org.cloudfoundry.managed-service<BR /> parameters:<BR /> path: ./xs-security.json<BR /> service-plan: application<BR /> service: xsuaa<BR /> config:<BR /> xsappname: my_proxy-${space}<BR /> tenant-mode: dedicated<BR /> role-collections:<BR /> - name: 'my_proxy-Access-${space}'<BR /> role-template-references:<BR /> - $XSAPPNAME.Access<BR /> </CODE></PRE><BR /> The xsappname and the role collections name thus contains the space name in order to be able to deploy the proxy app to multiple spaces in the same subacount (eg for three-tier development, test, production spaces). In this case the destination need to be defined at app-level in the respective destination service instance instead of subaccount level to have identical named destinations pointing to development, test, production onpremise systems respectivly (destination can't be defined at space level). Assign the role collection to users, either individually or via groups or via IdP configuration.<BR /> <BR /> The destination is defined with Principal Propagation:<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/12/2023-12-31_03h05_31.png" /></P><BR /> In the package.json we need now additional dependencies to xsenv and xssec:<BR /> <PRE class="language-abap"><CODE> "@sap/xsenv": "^4.2.0",<BR /> "@sap/xssec": "^3.6.0",</CODE></PRE><BR /> (Use at least version 3.6.0 of xssec because of mentioned security issue)<BR /> <BR /> In the JavaScript file the preperation now includes verification of the JWT token with the xsuaa service:<BR /> <PRE class="language-javascript"><CODE>const httpclient = require('@sap-cloud-sdk/http-client');<BR /> const express = require('express');<BR /> const bodyParser = require('body-parser')<BR /> const xsenv = require('@sap/xsenv');<BR /> const passport = require('passport');<BR /> const xssec = require('@sap/xssec');<BR /> <BR /> xsenv.loadEnv();<BR /> const app = express();<BR /> const services = xsenv.getServices({ uaa: 'my_proxy-uaa' });<BR /> passport.use(new xssec.JWTStrategy(services.uaa));<BR /> app.use(passport.initialize());<BR /> app.use(passport.authenticate('JWT', { session: false }));<BR /> app.use(bodyParser.text({ type: 'application/json' }));</CODE></PRE><BR /> The code for proxying a call now contains code for checking the scope and for fowarding the JWT token for principal propagation:<BR /> <PRE class="language-javascript"><CODE>app.post('/MyEntitySet', async (req, res) =&gt; {<BR /> if (!req.authInfo.checkLocalScope('access')) {<BR /> return res.status(403).send('Forbidden');<BR /> }<BR /> await httpclient.executeHttpRequest( <BR /> {<BR /> destinationName: 'MY_DESTINATION'<BR /> jwt: req.authInfo.getAppToken()<BR /> },<BR /> { <BR /> method: 'POST',<BR /> url: "/sap/opu/odata/sap/ZMY_SERV_SRV/MyEntitySet",<BR /> headers: {<BR /> "Content-Type":"application/json; charset=utf-8",<BR /> "Accept":"application/json"<BR /> },<BR /> data: req.body<BR /> }<BR /> )</CODE></PRE><BR /> <H1 id="toc-hId-48762719">Conclusion</H1><BR /> The SAP Cloud SDK for JavaScript makes it easy to use onpremise destinations with principal propagation in a BTP proxy app and hides the complexity in dealing with the destination, connectivity and xsuaa service. Happy Coding and have a succesful and peaceful new year!<BR /> <BR /> </DIV><BR /> </DIV> 2023-12-31T03:44:52+01:00 https://community.sap.com/t5/technology-blogs-by-members/validation-for-different-identity-cards-via-absl-code-in-sap-c4c/ba-p/13674119 Validation for different Identity Cards via ABSL code in SAP C4C 2024-04-18T08:27:04.382000+02:00 tkbisoyi9118 https://community.sap.com/t5/user/viewprofilepage/user-id/162380 <P><STRONG>Validation for different Identity Cards via ABSL code in SAP C4C</STRONG></P><P>In day–to-day life, the need of unique identification cards are common. So verfifications on identity cards in different sectors are also a basic requirement. Suppose we are working for a client from India and the project is about Sales cloud. In this case, the client wants to maintain every customer’s data like Name, Contact, Address, PAN number, Adhaar number, Passport details etc. Out of those fields PAN number, Adhaar number &amp; Passport number are unique IDs provided to each person in India. So we need to put some validations against them, so that wrong values should not be stored.</P><P>We have an option to put the validations on these Identity card numbers is via ABSL validation logic through cloud application studio. Here the steps mentioned below to validate different identity cards.</P><P>Identity cards mostly required in customer/Employee work centers. So, we can add the below logics in Event- Validation on Save and Event – After Modify of Customer/Employee BO in SDK.</P><P><STRONG>Case1 – PAN Card number should be alphanumeric and should maintain exact pattern. Also PAN card number should have only 10 characters length.</STRONG></P><P>To validate the length of any field we have the method “.length()”Which we can use for this requirement.</P><P>For PAN Card number the format in India as</P><OL><LI>The PAN Card number should be only 10 characters long.</LI><LI>First five characters should be alphabeting ranges from [A-Z]</LI><LI>From 6th to 9th places should be numeric values ranges from [0-9]</LI><LI>Last digit should be alphabetic values within [A-Z]</LI></OL><P>Using ABSL we have some logic using substring to implement the validation for any mismatch of the above-mentioned format. Added the code snippet for your reference.</P><P>Here we will use FindRegex() : This function <SPAN>Searches from left to right and returns the position of a regular expression pattern in a string. If it doesn’t find same pattern then it </SPAN>returns the value “-1” and raises a message as we define.</P><OL><LI>First five characters should be alphabeting ranges from [A-Z].</LI></OL><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tkbisoyi9118_0-1713528643323.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98781i2BC49C5D7E096630/image-size/medium?v=v2&amp;px=400" role="button" title="tkbisoyi9118_0-1713528643323.png" alt="tkbisoyi9118_0-1713528643323.png" /></span></P><P>&nbsp;</P><OL><LI>From 6th to 9th places should be numeric values ranges from [0-9]</LI></OL><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tkbisoyi9118_1-1713528643329.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98780i5A0B7FBFB58CD180/image-size/medium?v=v2&amp;px=400" role="button" title="tkbisoyi9118_1-1713528643329.png" alt="tkbisoyi9118_1-1713528643329.png" /></span></P><P>&nbsp;</P><OL><LI>Last digit should be alphabetic values within [A-Z]</LI></OL><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tkbisoyi9118_2-1713528643334.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98782iEBDF5C23F15258F5/image-size/medium?v=v2&amp;px=400" role="button" title="tkbisoyi9118_2-1713528643334.png" alt="tkbisoyi9118_2-1713528643334.png" /></span></P><P>&nbsp;</P><OL><LI>The PAN Card number should be only 10 characters long.</LI></OL><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tkbisoyi9118_3-1713528643336.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98783iC3F9D53112B88171/image-size/medium?v=v2&amp;px=400" role="button" title="tkbisoyi9118_3-1713528643336.png" alt="tkbisoyi9118_3-1713528643336.png" /></span></P><P>&nbsp;</P><P>Result: - After implementing the above ABSL code, when user tried to add wrong values of PAN Card or incorrect length, the error displayed and not allowed to SAVE the data.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tkbisoyi9118_4-1713528643339.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98784i18CE92864638DD6C/image-size/medium?v=v2&amp;px=400" role="button" title="tkbisoyi9118_4-1713528643339.png" alt="tkbisoyi9118_4-1713528643339.png" /></span></P><P>&nbsp;</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tkbisoyi9118_5-1713528643344.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98785i875F96029DCB663C/image-size/medium?v=v2&amp;px=400" role="button" title="tkbisoyi9118_5-1713528643344.png" alt="tkbisoyi9118_5-1713528643344.png" /></span></P><P>&nbsp;</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tkbisoyi9118_6-1713528643349.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98788i721E1DA3B2D2CA0B/image-size/medium?v=v2&amp;px=400" role="button" title="tkbisoyi9118_6-1713528643349.png" alt="tkbisoyi9118_6-1713528643349.png" /></span></P><P>&nbsp;</P><P>&nbsp;</P><P><STRONG>Case 2 – Adhaar Card number should be 12 characters length &amp; all digits should be numeric values. </STRONG></P><P>To validate the length of any field we have the method “.length()”Which we can use as of the requirement.</P><P>For Adhaar card all the digits should be numeric and length should be 12 characters only. The below ABSL code can restrict any mismatch to the Adhaar card format.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tkbisoyi9118_7-1713528643351.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98786iDB8A4BF4EB381ADB/image-size/medium?v=v2&amp;px=400" role="button" title="tkbisoyi9118_7-1713528643351.png" alt="tkbisoyi9118_7-1713528643351.png" /></span></P><P>&nbsp;</P><P>Result: - After implementing the above ABSL code, when user tried to add wrong values of Adhaar Card or incorrect length, the error displayed and not allowed to SAVE the data.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tkbisoyi9118_8-1713528643357.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98787iA667C465BEC3B62F/image-size/medium?v=v2&amp;px=400" role="button" title="tkbisoyi9118_8-1713528643357.png" alt="tkbisoyi9118_8-1713528643357.png" /></span></P><P>&nbsp;</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tkbisoyi9118_9-1713528643362.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98789i852777571AB81B2E/image-size/medium?v=v2&amp;px=400" role="button" title="tkbisoyi9118_9-1713528643362.png" alt="tkbisoyi9118_9-1713528643362.png" /></span></P><P>&nbsp;</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tkbisoyi9118_10-1713528643366.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98790iD8C707077F307965/image-size/medium?v=v2&amp;px=400" role="button" title="tkbisoyi9118_10-1713528643366.png" alt="tkbisoyi9118_10-1713528643366.png" /></span></P><P>&nbsp;</P><P><STRONG>Case3 – Indian Passport number should be alphanumeric and should maintain exact pattern. Also Passport card number should have only 8 characters length.</STRONG></P><P>To validate the length of any field we have the method “.length()”Which we can use as of the requirement.</P><P>For Passport number the format in India as</P><OL><LI>The Passport number should be only 8 characters long.</LI><LI>First one character should be alphabeting ranges from [A-Z].</LI><LI>For 2nd position, it should be numeric value within range 1 to 9.</LI><LI>For 3rd position, it should be numeric value within range 0 to 9.</LI><LI>From position 4th to 7th position, digits should be numeric value within range 0 to 9.</LI><LI>For the last one digit, it should be numeric value within range 1-9.</LI></OL><P>Using ABSL we have some logic using substring to implement the validation for any mismatch of the above-mentioned format. Added the code snippet for your reference.</P><P>Here we will use FindRegex() : This function <SPAN>Searches from left to right and returns the position of a regular expression pattern in a string. If it doesn’t find same pattern then it </SPAN>returns the value “-1” and raises a message as we define.</P><OL><LI>First one character should be alphabeting ranges from [A-Z].</LI></OL><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tkbisoyi9118_11-1713528643372.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98791i1F8F4A87DFD9790E/image-size/medium?v=v2&amp;px=400" role="button" title="tkbisoyi9118_11-1713528643372.png" alt="tkbisoyi9118_11-1713528643372.png" /></span></P><P>&nbsp;</P><OL><LI>For 2nd position, it should be numeric value within range 1 to 9.</LI></OL><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tkbisoyi9118_12-1713528643376.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98794i7FD15A846EC18C3C/image-size/medium?v=v2&amp;px=400" role="button" title="tkbisoyi9118_12-1713528643376.png" alt="tkbisoyi9118_12-1713528643376.png" /></span></P><P>&nbsp;</P><OL><LI>For3rd position, it should be numeric value within range 0 to 9.</LI></OL><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tkbisoyi9118_13-1713528643380.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98792iC1D70C1171FED582/image-size/medium?v=v2&amp;px=400" role="button" title="tkbisoyi9118_13-1713528643380.png" alt="tkbisoyi9118_13-1713528643380.png" /></span></P><P>&nbsp;</P><P>&nbsp;</P><OL><LI>From position 4th to 7th position, digits should be numeric value within range 0 to 9.</LI></OL><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tkbisoyi9118_14-1713528643384.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98793i2903687EE940A4BD/image-size/medium?v=v2&amp;px=400" role="button" title="tkbisoyi9118_14-1713528643384.png" alt="tkbisoyi9118_14-1713528643384.png" /></span></P><P>&nbsp;</P><OL><LI>For the last one digit, it should be numeric value within range 1-9.</LI></OL><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tkbisoyi9118_15-1713528643388.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98795iD5A1320DB7FBCFA6/image-size/medium?v=v2&amp;px=400" role="button" title="tkbisoyi9118_15-1713528643388.png" alt="tkbisoyi9118_15-1713528643388.png" /></span></P><P>&nbsp;</P><OL><LI>The Passport number should be only 8 characters long.</LI></OL><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tkbisoyi9118_16-1713528643392.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98797i76763F678260AA8F/image-size/medium?v=v2&amp;px=400" role="button" title="tkbisoyi9118_16-1713528643392.png" alt="tkbisoyi9118_16-1713528643392.png" /></span></P><P>&nbsp;</P><P>&nbsp;</P><P>Result: - After implementing the above ABSL code, when user tried to add wrong values of Adhaar Card or incorrect length, the error displayed and not allowed to SAVE the data.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tkbisoyi9118_17-1713528643397.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98796i3FD77F6543724906/image-size/medium?v=v2&amp;px=400" role="button" title="tkbisoyi9118_17-1713528643397.png" alt="tkbisoyi9118_17-1713528643397.png" /></span></P><P>&nbsp;</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tkbisoyi9118_18-1713528643402.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98798iCAC3EFB2B95EF0C5/image-size/medium?v=v2&amp;px=400" role="button" title="tkbisoyi9118_18-1713528643402.png" alt="tkbisoyi9118_18-1713528643402.png" /></span></P><P>&nbsp;</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tkbisoyi9118_19-1713528643406.png" style="width: 400px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/98799i9D8CAD495D1ADE11/image-size/medium?v=v2&amp;px=400" role="button" title="tkbisoyi9118_19-1713528643406.png" alt="tkbisoyi9118_19-1713528643406.png" /></span></P><P>&nbsp;</P><P><STRONG>Conclusion: -</STRONG></P><P>This solution can help customers to restrict unauthorized entry of identity card numbers.</P> 2024-04-18T08:27:04.382000+02:00 https://community.sap.com/t5/technology-blogs-by-members/handle-the-behavior-of-extension-field-by-toggle-button-using-sdk-ui/ba-p/13677684 Handle the behavior of extension field by toggle button using SDK UI designer. 2024-04-22T11:07:54.330000+02:00 Sunil5 https://community.sap.com/t5/user/viewprofilepage/user-id/162675 <P style=" text-align: center; "><STRONG><U>Handle the behavior of extension field by toggle button using SDK UI designer.</U></STRONG></P><P>Suppose there is one such requirement: We should have one toggle button and using that toggle button we can control the field behaviors like “Mandatory”, “Read Only” or “Visible” so, fields will behave the same as mentioned above when toggle button is set to true. To implement this requirement, we have created 3 different extension fields as “Extension field M”, “Extension field V”, “Extension field R” and one indicator field as “Manage Field” (indicator field act as a toggle button in front-end) in Service Request (Ticket) standard BO. We can make the “Extension field M” field as mandatory, the “Extension field V” field as visible, and the “Extension field R” field as read-only by toggle button (“Manage Field”) using UI designer in SDK.</P><P><STRONG>Procedure: -</STRONG></P><P>Here We have added extension fields in Service Request Extension BO (Ticket).</P><P>To add extension field to Extension BO we need to follow below steps:</P><OL><LI>Open your solution and click on Add New Item and select the “Extension” and from the list select “Business Object Extension” then click on Add. Select required namespace and BO name then click ok.</LI></OL><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Sunil5_1-1713769816813.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/99723iC00AFECE7B19DC90/image-size/large?v=v2&amp;px=999" role="button" title="Sunil5_1-1713769816813.png" alt="Sunil5_1-1713769816813.png" /></span></P><P>&nbsp;</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Sunil5_2-1713769857108.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/99724i9EAE96BEEB435F52/image-size/large?v=v2&amp;px=999" role="button" title="Sunil5_2-1713769857108.png" alt="Sunil5_2-1713769857108.png" /></span></P><P>&nbsp; &nbsp; &nbsp;2. After creation of “Business Object Extension” then add extension fields in this BO as shown below.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Sunil5_3-1713769964246.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/99726iA2812F76701CE990/image-size/large?v=v2&amp;px=999" role="button" title="Sunil5_3-1713769964246.png" alt="Sunil5_3-1713769964246.png" /></span></P><P>We now have extension fields created in Service Request Extension BO in Cloud Application Studio. Based on our requirement add these extension fields in the UI screen of Extension BO in Cloud Application Studio. Here We have added these extension fields in the TI screen of Service Request Extension BO. Now you can see these Extension fields in below SS.</P><P>To add extension field in UI screen of Extension BO we need to follow below steps:</P><OL><LI>Right click on BO and select “Enhance Screen” then select the screen as your requirement.</LI><LI>In screen, select group section and select “Add Extension field to Section Group” under the “Extensibility explorer” then select field which need to add in the screen then save and activate the UI screen.</LI></OL><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Sunil5_4-1713770008184.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/99728i4758431A052D4AA3/image-size/large?v=v2&amp;px=999" role="button" title="Sunil5_4-1713770008184.png" alt="Sunil5_4-1713770008184.png" /></span></P><P>Extension fields have been added successfully in UI screen as below.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Sunil5_5-1713770045689.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/99730i8C197C9B333DE6B3/image-size/large?v=v2&amp;px=999" role="button" title="Sunil5_5-1713770045689.png" alt="Sunil5_5-1713770045689.png" /></span></P><P>As per our requirement, now we will make the "Extension field M" field as mandatory field, the "Extension field R" field as read-only field and the "Extension field V" field as visible field in the UI screen using toggle button ("Manage Field") in cloud application studio. Here you need to follow the below steps:</P><OL><LI>Open the UI screen in cloud application studio where we have added to the extension fields. Here we have opened the TI screen of Service Request Extension BO. Select the field group where we have added the extension fields and click on “Adjust Properties” under the “Extensibility Explorer” as shown below.</LI></OL><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Sunil5_6-1713770101138.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/99732iC5F838F5D9D1BEDF/image-size/large?v=v2&amp;px=999" role="button" title="Sunil5_6-1713770101138.png" alt="Sunil5_6-1713770101138.png" /></span></P><P>&nbsp; &nbsp; &nbsp;2. Now we need to bind "Extension field M" field to the indicator field (toggle button) for mandatory, bind "Extension field R" field to the indicator field for ReadOnly and "Extension field V" field to the indicator field for Visible. Then, click on “Apply” as shown below, save and activate to the UI screen to finish this setup.</P><P><STRONG>Note</STRONG>- if we do not bind these fields with indicator field and select the “True” value there, then by default these fields will have same behavior every time.</P><P>For an example: if for "Extension field M" field, property “Mandatory” is set to “True” then this field will become mandatory by default.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Sunil5_7-1713770151109.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/99734i55779E28F4EDE0EE/image-size/large?v=v2&amp;px=999" role="button" title="Sunil5_7-1713770151109.png" alt="Sunil5_7-1713770151109.png" /></span></P><P><STRONG>Result: -</STRONG></P><P>After Completion of all the setup in SDK, now we can preview our changes when we will turn on the toggle button (“Manage Field”), then all the fields will behave as we expected.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Sunil5_8-1713770182573.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/99735i566C5E9FAA303EC4/image-size/large?v=v2&amp;px=999" role="button" title="Sunil5_8-1713770182573.png" alt="Sunil5_8-1713770182573.png" /></span></P><P>when we will turn off the toggle button (“Manage Field”), then all the fields will behave as we expected.</P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Sunil5_9-1713770213324.png" style="width: 999px;"><img src="https://community.sap.com/t5/image/serverpage/image-id/99736i8A9526207D26F4F4/image-size/large?v=v2&amp;px=999" role="button" title="Sunil5_9-1713770213324.png" alt="Sunil5_9-1713770213324.png" /></span></P><P><STRONG>Conclusion: -</STRONG></P><P>Now you can change the behavior of these fields based on toggle button (Manage field).</P><P>&nbsp;</P> 2024-04-22T11:07:54.330000+02:00 https://community.sap.com/t5/technology-blogs-by-sap/configuration-as-code-cac-with-destinations/ba-p/13699003 Configuration as code (CaC) with destinations. 2024-05-13T12:54:57.123000+02:00 quovadis https://community.sap.com/t5/user/viewprofilepage/user-id/743 <H1 id="toc-hId-865494464">Configuration as code (CaC) with destinations.</H1><P>Destinations are very handy and powerful mechanism to facilitate access to target systems and devices.</P><P>When it comes to SAP BTP destinations, the idea is to manage both <STRONG>subaccount</STRONG> and <STRONG>instance</STRONG> level destinations (and/or their certificates) as<SPAN>&nbsp;</SPAN><STRONG>shared</STRONG><SPAN>&nbsp;</SPAN>configuration resources on a provider subaccount level.</P><P>That way, the destinations configurations can be stored as versioned assets in a source repository and need to be maintained only once per provider, thus, without incurring application runtime tie-in.</P><P>Last but not least, BTP destination service is used as a self-configuration tool.</P><H2 id="toc-hId-798063678"><A href="https://gist.github.com/ptesny/aa8bc30ce043e1e11c145fe15278db62#configuration-as-code-cac-quovadis-master" target="_blank" rel="noopener nofollow noreferrer">Configuration as code with SAP BTP destination service</A></H2><P>&nbsp;</P><TABLE border="1"><TBODY><TR><TD>Table of Contents<OL><LI><A href="https://gist.github.com/ptesny/aa8bc30ce043e1e11c145fe15278db62#cac-dest" target="_blank" rel="noopener nofollow noreferrer">Configuration as code with SAP BTP destination service.</A></LI><OL><LI><A href="https://gist.github.com/ptesny/aa8bc30ce043e1e11c145fe15278db62#create-dest-service" target="_blank" rel="noopener nofollow noreferrer">create shared destination service instance and binding</A>.</LI></OL><LI><A href="https://gist.github.com/ptesny/aa8bc30ce043e1e11c145fe15278db62#create-bootstrap" target="_blank" rel="noopener nofollow noreferrer">Provision bootstrap destinations.</A></LI><OL><LI><A href="https://gist.github.com/ptesny/aa8bc30ce043e1e11c145fe15278db62#get-dest-credentials" target="_blank" rel="noopener nofollow noreferrer">retrieve destination service credentials from binding</A>.</LI><LI><A href="https://gist.github.com/ptesny/aa8bc30ce043e1e11c145fe15278db62#create-bootstrap-payload" target="_blank" rel="noopener nofollow noreferrer">describe bootstrap destination definitions.</A></LI><LI><A href="https://gist.github.com/ptesny/aa8bc30ce043e1e11c145fe15278db62#apply-payload" target="_blank" rel="noopener nofollow noreferrer">create bootstrap destinations on subaccount</A>.</LI></OL><LI><A href="https://gist.github.com/ptesny/aa8bc30ce043e1e11c145fe15278db62#configure-dest" target="_blank" rel="noopener nofollow noreferrer">Configure destination resources.</A></LI><OL><LI><A href="https://gist.github.com/ptesny/aa8bc30ce043e1e11c145fe15278db62#dynamic_dest" target="_blank" rel="noopener nofollow noreferrer">dynamic_dest route with managed approuter</A>.</LI><LI><A href="https://gist.github.com/ptesny/aa8bc30ce043e1e11c145fe15278db62#cloud-sdk" target="_blank" rel="noopener nofollow noreferrer">SAP Cloud SDK built-in destinations</A>.</LI></OL><LI><A href="https://gist.github.com/ptesny/aa8bc30ce043e1e11c145fe15278db62#documentation" target="_blank" rel="noopener nofollow noreferrer">Documentation.</A></LI></OL></TD></TR></TBODY></TABLE><P>PS.</P><P><STRONG>Bootstrap destinations definitions. </STRONG></P><P>Even, if there is no intrinsic BTP CLI command to assist in creation of destinations from service bindings, this can be achieved quite easily with a bit of jq gimmick by applying service binding credentials to a json payload template, for instance:</P><P>&nbsp;</P><pre class="lia-code-sample language-json"><code>{ "init_data": { "subaccount": { "destinations": [ { "Description": "dest-httpbin", "Type": "HTTP", "clientId": "sb-clone12847c4c89544b4f9234b26ede429f62!b282590|destination-xsappname!b62", "HTML5.DynamicDestination": "true", "HTML5.Timeout": "60000", "Authentication": "OAuth2ClientCredentials", "Name": "dest-httpbin", "tokenServiceURL": "https://&lt;subdomain&gt;.authentication.us10.hana.ondemand.com/oauth/token", "ProxyType": "Internet", "URL": "https://httpbin.org", "tokenServiceURLType": "Dedicated", "clientSecret": "&lt;clientSecret&gt;" }, { "Description": "SAP Destination Service APIs", "Type": "HTTP", "clientId": "sb-clone12847c4c89544b4f9234b26ede429f62!b282590|destination-xsappname!b62", "HTML5.DynamicDestination": "true", "HTML5.Timeout": "60000", "Authentication": "OAuth2ClientCredentials", "Name": "destination-service", "tokenServiceURL": "https://&lt;subdomain&gt;.authentication.us10.hana.ondemand.com/oauth/token", "ProxyType": "Internet", "URL": "https://destination-configuration.cfapps.us10.hana.ondemand.com/destination-configuration/v1", "tokenServiceURLType": "Dedicated", "clientSecret": "&lt;clientSecret&gt;" } ], "certificates": [ ], "existing_certificates_policy": "update", "existing_destinations_policy": "update" } } }</code></pre><P>&nbsp;</P><P>Alternatively, one could resort to using SAP Cloud SDK built-in <A href="https://sap.github.io/cloud-sdk/docs/js/features/connectivity/destinations#service-binding-environment-variables" target="_self" rel="nofollow noopener noreferrer">service binding destinations</A>.</P><P>The below nodejs code snippet demonstrates how to leverage&nbsp;SAP Cloud SDK with its service binding destinations with the likes of service manager and destinations services.</P><pre class="lia-code-sample language-yaml"><code>apiVersion: serverless.kyma-project.io/v1alpha2 kind: Function metadata: name: {{ .Values.services.srv.name }} labels: {{- include "app.labels" . | nindent 4 }} app: {{ .Values.services.srv.name }} spec: runtime: {{ .Values.services.srv.runtime }} # runtimeImageOverride: {{ .Values.services.srv.runtimeImageOverride }} source: inline: dependencies: | { "name": "{{ .Values.services.srv.name }}", "version": "0.0.1", "dependencies": { "axios":"latest" ,"debug": "latest" ,"@sap/xsenv": "latest" ,"@sap-cloud-sdk/http-client": "latest" ,"@sap-cloud-sdk/connectivity": "latest" ,"@sap-cloud-sdk/resilience": "latest" ,"async-retry": "latest" } } source: | const debug = require('debug')('{{ .Values.services.srv.name }}:function'); const NOT_FOUND = 'Not Found'; const xsenv = require('@sap/xsenv'); const services = xsenv.getServices({ sm: { label: 'service-manager', name: 'saas-sm' } , dest: { label: 'destination' } }); console.log('saas-sm: ', services.sm); const readServices = xsenv.readServices(); console.log('readServices: ', readServices); const httpClient = require('@sap-cloud-sdk/http-client'); const cloudSdkConnectivity = require('@sap-cloud-sdk/connectivity'); const { retrieveJwt, decodeJwt, Destination } = require('@sap-cloud-sdk/connectivity'); const { setGlobalLogLevel, createLogger } = require('@sap-cloud-sdk/util'); const { retry } = require ('@sap-cloud-sdk/resilience'); const { resilience } = require ('@sap-cloud-sdk/resilience'); const ResilienceOptions = { retry: 10, circuitBreaker: false, timeout: 300*1000 // 5 minutes in milliseconds }; const retryme = require('async-retry'); setGlobalLogLevel('debug'); const logger = createLogger('http-logs'); module.exports = { main: async function (event, context) { const req = event.extensions.request; const message = `Hello World` + ` from the Kyma Function ${context['function-name']}` + ` running on ${context.runtime}!` + ` with the request headers ${JSON.stringify(req.headers,0,2)}`; console.log(message); if (typeof req.path !== undefined) { console.log('path: ', JSON.stringify(req.path,0,2)) } if (typeof req.params !== undefined) { console.log('params: ', JSON.stringify(req.params,0,2)) } if (typeof req.url !== undefined) { console.log('url: ', JSON.stringify(req.url,0,2)) } if (typeof req.authInfo !== undefined) { console.log('authInfo: ', JSON.stringify(req.authInfo,0,2)) } const { pathname } = new URL(req.url || '', `https://${req.headers.host}`) console.log('pathname: ', pathname) const url = require("url"); var url_parts = url.parse(req.url); console.log(url_parts); console.log(url_parts.pathname); // returns an array with paths let path_array = req.url.match('^[^?]*')[0].split('/').slice(1); console.log(path_array) console.log(req.url.match('^[^?]*')[0]) if (!path_array?.length) return 'Please use an API verb'; const actions = [ { name: 'offerings', verb: 'service_offerings', dest: 'saas-sm', url: '/v1/' }, { name: 'plans', verb: 'service_plans', dest: 'saas-sm', url: '/v1/' }, { name: 'instances', verb: 'service_instances', dest: 'saas-sm', url: '/v1/' }, { name: 'bindings', verb: 'service_bindings', dest: 'saas-sm', url: '/v1/' }, { name: 'instanceDestinations', verb: 'instanceDestinations', dest: 'faas-dest-x509', url: '/destination-configuration/v1/' }, { name: 'subaccountDestinations', verb: 'subaccountDestinations', dest: 'faas-dest-x509' , url: '/destination-configuration/v1/' } ]; const action = actions.find( ({ name }) =&gt; name === path_array[1] ) console.log('action found: ', action) if (path_array[0] == 'srv' &amp;&amp; action !== undefined) { path_array = req.url.match('^[^?]*')[0].split('/').slice(2); console.log('path_array: ', path_array) const queryString = req.query; console.log('queryString: ', queryString) const urlParams = new URLSearchParams(queryString); const params = req.params; console.log('params: ', params) try { // https://sap.github.io/cloud-sdk/docs/js/features/connectivity/destinations#service-binding-environment-variables const endpoint = path_array[1] !== undefined ? '/' + path_array[1] : ''; console.log(endpoint) let res = await httpClient.executeHttpRequest({ destinationName: action.dest }, { method: 'GET', url: action.url + action.verb + endpoint }); return res.data; } catch (err) { console.log(err.stack); return err.message; } } } } scaleConfig: maxReplicas: 5 minReplicas: 3 resourceConfiguration: function: profile: S env: ## https://kyma-project.io/docs/kyma/latest/05-technical-reference/00-configuration-parameters/svls-02-environment-variables/#node-js-runtime-specific-environment-variables - name: FUNC_TIMEOUT ## Specifies the number of seconds in which a runtime must execute the code. value: '1800' - name: REQ_MB_LIMIT ## payload body size limit in megabytes. value: "10" - name: DEBUG value: '{{ .Values.services.srv.name }}:*' - name: SERVICE_BINDING_ROOT value: /bindings secretMounts: - secretName: {{ .Values.services.sm.bindingSecretName }} mountPath: "/bindings/saas-sm" - secretName: {{ .Values.services.dest.bindingSecretNamex509 }} mountPath: "/bindings/faas-dest-x509"</code></pre><P>&nbsp;</P> 2024-05-13T12:54:57.123000+02:00