https://raw.githubusercontent.com/ajmaradiaga/feeds/main/scmt/topics/SAP-BTP-serverless-runtime-blog-posts.xml SAP Community - SAP BTP, serverless runtime 2024-05-20T11:12:02.969119+00:00 python-feedgen SAP BTP, serverless runtime blog posts in SAP Community https://community.sap.com/t5/technology-blogs-by-sap/develop-sap-cloud-platform-serverless-runtime-application-using-sap/ba-p/13467752 Develop SAP Cloud Platform Serverless Runtime application using SAP Business Application Studio 2020-08-18T18:58:23+02:00 pradeep_panda https://community.sap.com/t5/user/viewprofilepage/user-id/230882 Before you go ahead and read through this blog, you need to have some basic know-how on SAP Cloud Platform Serverless Runtime and SAP Business Application Studio.<BR /> <BR /> If SAP Cloud Platform Serverless Runtime is new to you, I recommend you to go through the <A href="https://blogs.sap.com/2020/06/17/writing-functions-as-a-service-overview-of-blogs/" target="_blank" rel="noopener noreferrer">Overview of Function as a Service</A> blog from dear <SPAN class="mention-scrubbed">carlos.roggan</SPAN> . Not only has he explained the concept and how to work with it beautifully, but also it has links to other reference blogs and materials associated with SAP Cloud Platform Serverless Runtime.<BR /> <BR /> If you are even new to SAP Business Application Studio (BAS), please follow this <A href="https://blogs.sap.com/2020/07/14/sap-business-application-studio-info-blog/" target="_blank" rel="noopener noreferrer">info blog</A>, which points to other blogs from this central blog.<BR /> <BR /> Now that you have knowledge of both SAP Cloud Platform Serverless Runtime and SAP Business Application Studio, let us discuss in this blog how can you develop a SAP Cloud Platform Serverless Runtime application and&nbsp; build &amp; deploy on SAP Cloud Platform using SAP Business Application Studio.<BR /> <BR /> Let us understand the steps which need to be performed and than we will go in detail of each step.<BR /> <UL><BR /> <LI>Open BAS and Create Dev Space<B>.</B></LI><BR /> <LI>Create Project from Template</LI><BR /> <LI>Open the Project in a workspace</LI><BR /> <LI>Debug the Function as a Service</LI><BR /> <LI>Deploy to SAP Cloud Platform</LI><BR /> </UL><BR /> Let us dig deeper.<BR /> <BR /> <B><SPAN style="text-decoration: underline">Open BAS and Create Dev Space</SPAN> -&nbsp; &nbsp;</B>A dev space is a pre-configured environment with the required tools and extensions tailored for a specific business scenario. Before developing any application, you should create a dev space that is suitable to your development scenario.<BR /> <BR /> In our case, we’ll need to create a dev space for developing applications using SAP Cloud Platform Serverless Runtime.<BR /> <BR /> There are a couple of advantages for using a dev space. First, it contains only a pre-defined set of tools required to develop, so your environment is cleaner, faster, and easier to use. Second, you have the freedom to install your own tools to configure your dev space as you please, providing a local-like development experience.<BR /> <BR /> &nbsp;<BR /> <P style="text-align: center"><B>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <EM>The dev space Manager</EM></B>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/08/CreateDevSp-1.jpg" height="223" width="489" /></P><BR /> &nbsp;<BR /> <P style="text-align: center"><B>Creating a new dev space</B><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/08/selectAppCreateDevSp.jpg" height="220" width="486" /></P><BR /> The dev space enables working environment to be cleaner by allowing to download only required tools and&nbsp; extensions. In our case, to be able to work, we need to select the application type as Basic and Extension Factory Serverless Runtime Development Tools from the list of available SAP basic tools extension. It automatically selects the MTA Tools.<BR /> <BR /> The MTA Tools allow you to perform operations such as build, deploy &amp; validation on multi-target applications. The MTA Tools are provided as an extension to SAP Business Application Studio and contains Cloud Foundry CLI, Cloud MTA Build Tool.<BR /> <BR /> <SPAN style="text-decoration: underline"><B>Create Project from Template - </B></SPAN>Now that the dev space with required extensions created, let us go ahead and create a new project using from template. We need to select "<EM>Serverless Extensions Project</EM>" template to create a new SAP Cloud Platform Extension Factory, serverless runtime project.<BR /> <P style="overflow: hidden;margin-bottom: 0px">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<B>New project from template</B></P><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/08/SelectProjectFromTemplate.jpg" height="227" width="498" /></P><BR /> On clicking Next button, the Business Application Studio opens a set of guided widget to create a project, a function and a trigger sequentially.<BR /> <BR /> <B>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Create a FaaS Project</B>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/08/createproj.jpg" height="223" width="487" /><BR /> <BR /> &nbsp;<BR /> <BR /> <B>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Create a Function</B><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/08/createfunc.jpg" height="227" width="494" /><BR /> <BR /> <I>A function is part of an extension. If you notice here, while creating a function you need </I><I>to have a module and a handler also. The module should be created locally. The handler </I><I>method must contain parameters that call the function such as event, context, and </I><I>so on. Also, it can have additional configuration data. </I><BR /> <BR /> <B>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Create a Trigger for the Function</B>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/08/createtrig.jpg" height="222" width="485" /><BR /> <BR /> &nbsp;<BR /> <BR /> <I>A Function is instantiated in response to events (trigger).</I><I> Each trigger is defined as a JSON object in the following format:</I><BR /> <UL><BR /> <LI style="list-style-type: none"><BR /> <UL><BR /> <LI><SPAN style="text-decoration: underline"><I>HTTP trigger - </I><I>Sample Code<BR /> </I></SPAN><I></I><I></I><I>“&lt;</I><I>trigger_name</I><I>&gt;” : {</I><I><BR /> </I><I>“</I><I>type</I><I>”: “</I><I>HTTP</I><I>”,</I><I><BR /> </I><I>“</I><I>function</I><I>”: &lt;</I><I>function_name_that_should_be_triggered</I><I>&gt;</I><I><BR /> </I><I>}</I></LI><BR /> <LI><SPAN style="text-decoration: underline"><I>Timer trigger - </I><I>Sample Code<BR /> </I></SPAN><I>“&lt;</I><I>trigger_name</I><I>&gt;” : {</I><I><BR /> </I><I>“</I><I>type</I><I>”: “</I><I>Timer</I><I>”,</I><I><BR /> </I><I>“</I><I>function</I><I>”: &lt;</I><I>function_name_that_should_be_triggered</I><I>&gt;</I><I><BR /> </I><I>“</I><I>timerCronExpression</I><I>”: &lt;</I><I>cronexpression_schedule</I><I>&gt;</I><I><BR /> </I><I>}</I></LI><BR /> </UL><BR /> </LI><BR /> </UL><BR /> As of now, HTTP and TIMER based trigger are supported from BAS. AMQP and Cloud Events based triggers will be supported shortly.<BR /> <BR /> <SPAN style="text-decoration: underline"><B>Open the Project in a workspace - </B></SPAN>Once you complete all steps above, you will get an alert as below.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/08/openProj.png" height="82" width="488" /></P><BR /> &nbsp;Select to open in new workspace and you will have your project open as below in a new workspace.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/08/Openproj_1.jpg" height="216" width="492" /></P><BR /> <P style="overflow: hidden;margin-bottom: 0px">You can view the project structure in the Explorer. It is a node.js project. The lib folder contains the following sections describe how you can write function code using node.js 8 and node.js 10. Write a handler method as a JavaScript function in a node.js module. It receives the event and context parameters from the runtime. The handler is called for each function invocation. It can return a simple value directly, undefined or a promise to handle the asynchronous execution.</P><BR /> In the project we have created, if you notice in the index.js module, you can find the handler template as below. You can write your customized business logic here.<BR /> <PRE class="language-javascript"><CODE>handler: function (event, context) {<BR /> <BR /> /*Enter your function's business logic here*/<BR /> <BR /> return 'hello world from a function!';<BR /> <BR /> }</CODE></PRE><BR /> &nbsp;<BR /> <BR /> <B><SPAN style="text-decoration: underline">Debug the Function as a Service -&nbsp;</SPAN></B>It is always better to try out the function locally before deploying it in the SCP.If you give a close look, you will also find a <B>test</B> folder, which does contain an <B>integration </B>folder. This helps in debugging and thus helps in checking the correctness of the function&nbsp;before deploying it.<BR /> <BR /> Below steps need to be performed for each function before starting debugging of it. It follows the standard <A href="https://help.sap.com/viewer/bf7b2ff68518427c85b30ac3184ad215/Cloud/en-US/2fbca2eec0f74c1099e72320dd3c3f0f.html" target="_blank" rel="noopener noreferrer">Run Configurations for an Extension</A> process.&nbsp;Do find the exact steps to be followed to be able to debug developed function.<BR /> <BR /> Click on the Run Configuration as shown below.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/08/Debug_runconfiguration.jpg" height="154" width="515" /></P><BR /> &nbsp;<BR /> <BR /> Click on the Create Configuration as shown below.<BR /> <P style="overflow: hidden;margin-bottom: 0px">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/08/Debug_createconfiguration.jpg" height="175" width="526" /></P><BR /> &nbsp;<BR /> <BR /> Select the faas.json file from the command palate<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/08/Debug_selectfaas.jpg" height="38" width="516" /></P><BR /> &nbsp;<BR /> <BR /> Finally allow to execute the below command.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/08/Debug_runValuesyaml.jpg" height="31" width="523" /></P><BR /> &nbsp;<BR /> <BR /> A configuration tree appears in the RUN CONFIGURATIONS view containing the run&nbsp;configurations that were created for the runnable objects. A new configuration is&nbsp;added to your launch.json file.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/08/Debug_runconfig_valueyaml.jpg" height="58" width="518" /></P><BR /> &nbsp;<BR /> <BR /> To run the configuration, select the configuration and choose the Run icon.&nbsp;Open the &lt;&lt;function_name&gt;&gt;.http file and you can send GET and POST Request&nbsp;to test if the functionality is working fine locally. You can also put a break point&nbsp;to check the flow.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/08/testFunction.jpg" height="227" width="514" /></P><BR /> &nbsp;<BR /> <BR /> <SPAN style="text-decoration: underline"><B>Deploy on SAP Cloud Platform - </B></SPAN><B> </B>Now that you have created a project having function and trigger, it needs to be deployed&nbsp;in SAP Cloud Platform for productive usage. Thankfully this also can be done directly from&nbsp;SAP Cloud Platform Business Application Studio.<BR /> <BR /> As of now, building and deploying an MTA deployable directly from Project Context is yet&nbsp;to be done for SAP Cloud Platform serverless runtime. We need to do this using the Terminal&nbsp;feature of SAP Cloud Platform Business Application Studio.<BR /> <BR /> The overall process of deploying on SAP Cloud Platform consists of two steps.<BR /> <BR /> <SPAN style="text-decoration: underline"><I>Connecting the Business Application Studio to the SAP Cloud Platform</I></SPAN><BR /> <BR /> Connect to the SCP Cloud Platform organization and space where you want to deploy the&nbsp;deploy-able.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/08/SCPInstance.jpg" height="67" width="529" /></P><BR /> With the right credentials, it allows to select the organization and the space. And you get&nbsp;an alert as below.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/08/Org_space.png" height="55" width="529" /></P><BR /> <SPAN style="text-decoration: underline"><I><U>Deploying the deploy-able&nbsp;in the right SAP Cloud Platform space</U></I></SPAN><BR /> <BR /> To be able to deploy, we need to start a Terminal in Business Application Studio.&nbsp;Log in to the SAP Cloud Platform Extension Factory, serverless runtime CLI with following command.<BR /> <BR /> <IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/08/xfsrt-login-1.png" height="28" width="120" /><BR /> <BR /> <I>Please make sure you have an SAP Cloud Platform Serverless Runtime </I><I>instance with its service key created.&nbsp;</I><I>After successful login, it will show the serverless instances available in the same space. Under&nbsp;</I><I>BINDING heading is the service key name of the serverless instance.&nbsp; </I><BR /> <P style="overflow: hidden;margin-bottom: 0px">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/08/xfsrt_login.png" height="150" width="460" /></P><BR /> Provide the service instance&nbsp;number which you want to use to deploy the created function project.&nbsp;Once successful log in is done, you can deploy the project to the selected service using&nbsp;following command.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/08/deploy.png" height="29" width="207" /></P><BR /> After successful deploy, you can retrieve metadata, status information, and links to the project using the following command:<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/08/get.png" height="30" width="160" /></P><BR /> Congrats...&nbsp; Following the steps given above, you would have now been able to create a Function as a Service Project with a serverless runtime function. You can enhance your function logic to meet your business need and experience the magic. SAP Cloud Platform Serverless Runtime becomes quite powerful, when it is integrated with a service like SAP Cloud Platform Enterprise Messaging. It brings in a decoupled architectural essence, which definitely is one of the most important advantages of an Extension for which a serverless runtime is used. You can implement similar use cases from Business Application Studio.<BR /> <BR /> In summary, you would have noticed, how easy the development process has become to develop a serverless runtime project and deploy the same in SAP Cloud Platform when you try to build it from SAP Business Application Studio.<BR /> <BR /> So do enjoy working with SAP Business Application Studio and SAP Cloud Platform Serverless Runtime.<BR /> <BR /> Do not hesitate to provide your feedback on the blog and of course do mention if any issue you face while following this blog. 2020-08-18T18:58:23+02:00 https://community.sap.com/t5/technology-blogs-by-sap/writing-function-as-a-service-10-call-protected-endpoint-across-subaccounts/ba-p/13479226 Writing Function-as-a-Service [10]: Call protected endpoint across Subaccounts 2020-08-27T10:02:41+02:00 CarlosRoggan https://community.sap.com/t5/user/viewprofilepage/user-id/5495 This blog is part of a&nbsp;<A href="https://blogs.sap.com/2020/06/17/writing-functions-as-a-service-overview-of-blogs/" target="_blank" rel="noopener noreferrer">series of tutorials</A>&nbsp;explaining how to write serverless functions using the Functions-as-a-Service offering in&nbsp;<STRONG>SAP Cloud Platform Serverless Runtime</STRONG><BR /> <P style="text-align: right">Quicklinks:<BR /> <SPAN style="font-size: smaller"><A href="#quickguide" target="_blank" rel="nofollow noopener noreferrer">Quick Guide</A><BR /> <A href="#samples" target="_blank" rel="nofollow noopener noreferrer">Sample Code</A></SPAN></P><BR /> <BR /> <H2 id="toc-hId-935473826">Introduction</H2><BR /> In the <A href="https://blogs.sap.com/2020/08/19/writing-function-as-a-service-9-how-to-call-oauth-protected-endpoint/" target="_blank" rel="noopener noreferrer">previous tutorial</A> we‘ve learned how to call a service which is protected with OAuth and requires a scope.<BR /> The challenge was:<BR /> -&gt; how can the function possess the scope?<BR /> The solution was:<BR /> -&gt; configuration of both xs-security.json files<BR /> <BR /> BUT:<BR /> There was a precondition:<BR /> -&gt; both app and function have to live in the same subaccount<BR /> <BR /> This is necessary because the central XSUAA of the subaccount creates one oauth-client for each instance and assigns the granted scope to the other client.<BR /> Thus, it has to resolve the names of the scope and involved clients<BR /> This is possible because the name of the scope is made unique and identifiable by adding the variable <SPAN style="font-family: Courier New">$XSAPPNAME</SPAN> to the scope name.<BR /> As we all know, the value of the variable is not just the same as the name of the property <SPAN style="font-family: Courier New">xsappname<BR /> </SPAN>The value of <SPAN style="font-family: Courier New">$XSAPPNAME</SPAN> is generated at runtime and contains some mystic suffix <SPAN style="font-family: Courier New">!t1234</SPAN><BR /> <BR /> OK.<BR /> Today we want to call from the function to a service which lives in a different subaccount.<BR /> So now, the XSUAA has to find not only the correct scope and oauth-client.<BR /> It has to find it in a different subaccount (identityzone)<BR /> <BR /> How to do it?<BR /> -&gt; communicate with the other central XSUAA<BR /> <BR /> How to find that one?<BR /> -&gt; By the unique identifier of the subaccount (identityzone)<BR /> <BR /> As such, we have to add the subaccountID to the <SPAN style="font-family: Courier New">GRANT</SPAN> statement<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/08/diagram1-1.jpg" /></P><BR /> And that’s already all for today<BR /> <BR /> Nevertheless, let’s make it real<BR /> <H2 id="toc-hId-738960321">Overview</H2><BR /> In this tutorial, we’re going to learn how to assign a scope to an application in a different subaccount<BR /> <BR /> The scenario is almost the same as in the <A href="https://blogs.sap.com/2020/08/19/writing-function-as-a-service-9-how-to-call-oauth-protected-endpoint/" target="_blank" rel="noopener noreferrer">previous tutorial</A>.<BR /> We can either re-use it and do the required little changes<BR /> Or create the project as described below, everything based on the previous blog<BR /> <BR /> In the first part of this tutorial, we’re creating a very basic app which exposes an endpoint which is protected with OAuth and which requires a certain scope<BR /> In the second part, we’re creating a Function which tries to call that endpoint<BR /> <BR /> <A href="#part1" target="_blank" rel="nofollow noopener noreferrer">Part 1</A>: The Protected App<BR /> <SPAN style="padding-left: 20px">Create xsuaa, define scope</SPAN><BR /> <SPAN style="padding-left: 20px">Create app, check scope</SPAN><BR /> <BR /> <A href="#part2" target="_blank" rel="nofollow noopener noreferrer">Part 2</A>: The Calling Function<BR /> <SPAN style="padding-left: 20px">Create xsuaa, define authority</SPAN><BR /> <SPAN style="padding-left: 20px">Create Function, do OAuth flow</SPAN><BR /> <H2 id="toc-hId-542446816">Prerequisites</H2><BR /> <UL><BR /> <LI>If you’re new to the topic, the previous tutorial is a prerequisite, along with all its <A href="https://blogs.sap.com/2020/08/19/writing-function-as-a-service-9-how-to-call-oauth-protected-endpoint/#prerequisites" target="_blank" rel="noopener noreferrer">prerequisites</A> and blablabla</LI><BR /> <LI>In addition:<BR /> To follow this tutorial, we need 2 different subaccounts.<BR /> In my example, I’m using my trial account, in addition to my FaaS-account (containing the instance of SAP Cloud Platform serverless runtime)<BR /> Limitation:<BR /> Both accounts have to live in the same data center (in my example, eu10)</LI><BR /> </UL><BR /> <H2 id="preparation" id="toc-hId-345933311">Preparation: Create Project Structure</H2><BR /> Same <A href="https://blogs.sap.com/2020/08/19/writing-function-as-a-service-9-how-to-call-oauth-protected-endpoint/#preparation" target="_blank" rel="noopener noreferrer">preparation</A> like in previous blog: create files and folders<BR /> <BR /> In addition:<BR /> We need to find the ID of the FaaS-subaccount.<BR /> It is easy to find: just open the subaccount in the cloud cockpit<BR /> Which subaccount?<BR /> We need the ID of the subaccount where the FaaS is located<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/08/subacc_ID.jpg" /></P><BR /> <BR /> <H2 id="part1" id="toc-hId-149419806">Part 1: <STRONG>The Protected App</STRONG></H2><BR /> Almost same as <A href="https://blogs.sap.com/2020/08/19/writing-function-as-a-service-9-how-to-call-oauth-protected-endpoint/#part1" target="_blank" rel="noopener noreferrer">part 1</A> of previous tutorial<BR /> Really only the <SPAN style="font-family: Courier New">xs-security.json</SPAN> file is little bit different<BR /> <H3 id="toc-hId-81989020">1.1. Security Configuration</H3><BR /> This is the essential section of this tutorial:<BR /> Here we’re using the subaccount ID:<BR /> -&gt; grant the scope to an oauth-client living in the specified subaccount<BR /> <PRE class="language-javascript"><CODE>{<BR /> "xsappname" : "xsappforsafeapp",<BR /> "scopes": [{<BR /> "name": "$XSAPPNAME.scopeformysafety",<BR /> "grant-as-authority-to-apps" : [ "$XSAPPNAME(application, 12ab12ab-34cd-56ef-34cd-12ab12ab12ab, xsappforfaas)"]<BR /> }]<BR /> }<BR /> </CODE></PRE><BR /> &nbsp;<BR /> <BR /> Syntax:<BR /> <PRE class="language-javascript"><CODE>"grant-as-authority-to-apps" : [ <BR /> "$XSAPPNAME(&lt;service_plan&gt;, &lt;subaccount_id&gt;, &lt; xsappname_of_caller &gt;)"<BR /> ]</CODE></PRE><BR /> After clarifying the new security descriptor, we create an instance of XSUAA in our Trial account (or whatever account you’ve chosen)<BR /> <BR /> We have to make sure that we're targeting the different account, e.g. trial<BR /> To change location:<BR /> <BR /> <SPAN style="background-color: black;color: white;font-family: Courier New">cf t -o p123456trial</SPAN><BR /> <BR /> see:<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/08/cftarget.jpg" height="129" width="303" /></P><BR /> OK, for your convenience, here's again the command to create a service instance:<BR /> In my example, we jump into <SPAN style="background-color: #ffe78f;font-family: Courier New">C:\tmp_faas_callsafe\safeapp</SPAN> and run the following command<BR /> <BR /> <SPAN style="background-color: black;color: white;font-family: Courier New">cf cs xsuaa application xsuaaforsafetyapp -c xs-security-safe.json</SPAN><BR /> <H3 id="toc-hId--114524485">1.2. Create Application</H3><BR /> No change needed to the app.<BR /> Just take the sample code (Part 1) from <A href="https://blogs.sap.com/2020/08/19/writing-function-as-a-service-9-how-to-call-oauth-protected-endpoint/#samples" target="_blank" rel="noopener noreferrer">previous tutorial</A><BR /> <H3 id="toc-hId--311037990">1.3. Deploy and Run the App</H3><BR /> Yapp, just deploy it to the different account.<BR /> No need to run it, we did it in the previous torture<BR /> <H3 id="toc-hId--507551495">1.4. Small Recap</H3><BR /> We deploy a protected app to trial account.<BR /> We specify that the Function of FAC account is allowed to call us<BR /> So we add a statement to grant access to the calling xsapp<BR /> And here is the place to enter the ID of the FAC account<BR /> <H2 id="part2" id="toc-hId--833147719">Part 2: The Calling Function</H2><BR /> Again, all the same as in <A href="https://blogs.sap.com/2020/08/19/writing-function-as-a-service-9-how-to-call-oauth-protected-endpoint/#part2" target="_blank" rel="noopener noreferrer">one</A> of the other boring tutorials<BR /> <H3 id="toc-hId--975809874">2.1. Security Configuration</H3><BR /> In part 1 we learned how to grant a scope to an xsuaa instance in a different subaccount<BR /> Now we’re on the receiving side: we receive the granted scope and we need to accept it<BR /> In the previous tutorial, we used the following statement:<BR /> <BR /> <SPAN style="font-family: Courier New">"authorities":["$XSAPPNAME(application,xsappforsafeapp).scopeformysafety"]</SPAN><BR /> <BR /> Now we would need to make clear where to find that foreign xsapp<BR /> However, I haven’t found a way to add the subaccountID in this statement<BR /> OK, no prob.<BR /> -&gt; we have to fall back to the generic statement:<BR /> <BR /> <SPAN style="font-family: Courier New">"authorities":["$ACCEPT_GRANTED_AUTHORITIES"]</SPAN><BR /> <BR /> Using this statement, we accept all scopes granted by anybody to our app (xsapp, to be more precise)<BR /> <BR /> So now we open the file <SPAN style="font-family: Courier New;background-color: #f5f5f5">xs-security-faas.json</SPAN>, in folder <SPAN style="background-color: #ffe78f;font-family: Courier New">unsafefunction</SPAN> and enter the following content<BR /> <PRE class="language-javascript"><CODE>{<BR /> "xsappname" : "xsappforfaas",<BR /> "tenant-mode" : "dedicated",<BR /> "authorities":["$ACCEPT_GRANTED_AUTHORITIES"]<BR /> }</CODE></PRE><BR /> Note:<BR /> This statement doesn't apply only for different subaccounts, it can be used in any scenario<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/08/diagramDetailed-1.jpg" /></P><BR /> As usual. this JSON config can be used to create or update&nbsp; an instance of XSUAA.<BR /> <BR /> Before executing a command, don't forget that this time, we have to make sure that we target the subaccount where FaaS is living<BR /> <BR /> To create the XSUAA-instance for FaaS, we jump into the function folder <SPAN style="background-color: #ffe78f;font-family: Courier New">unsafefunction</SPAN> then:<BR /> <BR /> <SPAN style="background-color: black;color: white;font-family: Courier New">cf cs xsuaa application xsuaaforfaas -c xs-security-faas.json</SPAN><BR /> <BR /> And create a service key:<BR /> <BR /> <SPAN style="background-color: black;color: white;font-family: Courier New">cf csk xsuaaforfaas servicekeyforfaas</SPAN><BR /> <BR /> BUT:<BR /> If you have the scenario in place, It is enough to update the existing service:<BR /> <BR /> <SPAN style="background-color: black;color: white;font-family: Courier New">cf update-service xsuaaforfaas -c xs-security-faas.json</SPAN><BR /> <BR /> &nbsp;<BR /> <BR /> &nbsp;<BR /> <H3 id="toc-hId--1172323379">2.2. Create Function</H3><BR /> All the same as in <A href="https://blogs.sap.com/2020/08/19/writing-function-as-a-service-9-how-to-call-oauth-protected-endpoint/#part2" target="_blank" rel="noopener noreferrer">previous</A> hands-on. It shouldn’t be necessary to do any change, register or deploy.<BR /> But it might be necessary to repeat steps, if the xsuaa instance was deleted, etc<BR /> Or to adapt the code, if the name of the protected app was changed in trial<BR /> <BR /> Otherwise, we can just use the deployed function, if remaining from the previous blog<BR /> <BR /> Or we create everything from scratch, based on the <A href="https://blogs.sap.com/2020/08/19/writing-function-as-a-service-9-how-to-call-oauth-protected-endpoint/#samples" target="_blank" rel="noopener noreferrer">sample code Part 2</A><BR /> <BR /> &nbsp;<BR /> <BR /> And then, finally, we invoke the function and are happy to see the same result which we had before<BR /> No shame to be happy:<BR /> We’ve learned the little trick which enables us to cross the borders of subaccounts<BR /> <H2 id="toc-hId--1075433877">Summary</H2><BR /> In this blog we’ve learned almost nothing<BR /> Just adding a cryptic guid in the middle of a cryptic statement<BR /> Luckily, the blog post hasn’t been too long…<BR /> <H2 id="quickguide" id="toc-hId--1271947382">Quick Guide</H2><BR /> The protected app which is called by the Function has to grant the scope to the Function<BR /> If both are not located in the same subaccount, then the subaccountID of the Function has to be added (ID can be found in the cockpit)<BR /> <BR /> <SPAN style="font-family: Courier New">xs-security.json</SPAN> of protected app:<BR /> <PRE class="language-javascript"><CODE>"scopes": [{<BR /> "name": "$XSAPPNAME.scopeformysafety",<BR /> "grant-as-authority-to-apps" : [ <BR /> "$XSAPPNAME(application, 12345678-abcd-..., xsappforfaas)"<BR /> <BR /> <BR /> </CODE></PRE><BR /> The calling Function has to accept the grant. In case of different subaccounts, the generic statement has to be used to accept all granted scopes<BR /> <BR /> <SPAN style="font-family: Courier New">xs-security.json</SPAN>: of Function<BR /> <BR /> &nbsp;<BR /> <PRE class="language-javascript"><CODE>"authorities":["$ACCEPT_GRANTED_AUTHORITIES"]</CODE></PRE><BR /> <H2 id="links" id="toc-hId--1468460887">Links</H2><BR /> Same as in <A href="https://blogs.sap.com/2020/08/19/writing-function-as-a-service-9-how-to-call-oauth-protected-endpoint/#links" target="_blank" rel="noopener noreferrer">previous tuutorial</A><BR /> <H2 id="samples" id="toc-hId--1664974392">Appendix: All Project Files</H2><BR /> The whole project can be found in <A href="https://blogs.sap.com/2020/08/19/writing-function-as-a-service-9-how-to-call-oauth-protected-endpoint/#samples" target="_blank" rel="noopener noreferrer">previous tutorial</A><BR /> <BR /> However, we have to adjust the following files in both projects<BR /> <H3 id="toc-hId-2140076392">Part 1: The Protected App</H3><BR /> These files are located in the folder "safeapp"<BR /> <BR /> <SPAN style="text-decoration: underline">xs-security-safe.json</SPAN><BR /> <PRE class="language-javascript"><CODE>{<BR /> "xsappname" : "xsappforsafeapp",<BR /> "tenant-mode" : "dedicated",<BR /> "scopes": [{<BR /> "name": "$XSAPPNAME.scopeformysafety",<BR /> "grant-as-authority-to-apps" : [ <BR /> "$XSAPPNAME(application, 1a2b3c4d-0000-1111-aaaa-..., xsappforfaas)"<BR /> ]<BR /> }]<BR /> }<BR /> </CODE></PRE><BR /> <H3 id="toc-hId-1943562887">Part 2: The Calling Function</H3><BR /> They are located in the folder "unsafefunction"<BR /> <BR /> <SPAN style="text-decoration: underline">xs-security-faas.json</SPAN><BR /> <PRE class="language-javascript"><CODE>{<BR /> "xsappname" : "xsappforfaas",<BR /> "tenant-mode" : "dedicated",<BR /> "authorities":["$ACCEPT_GRANTED_AUTHORITIES"]<BR /> }</CODE></PRE><BR /> &nbsp; 2020-08-27T10:02:41+02:00 https://community.sap.com/t5/technology-blogs-by-sap/the-evolution-of-sap-cloud-platform-extension-factory-into-sap-cloud/ba-p/13472375 The Evolution of SAP Cloud Platform Extension Factory into SAP Cloud Platform Extension Suite 2020-09-14T13:46:05+02:00 cecihuergo https://community.sap.com/t5/user/viewprofilepage/user-id/386 <SPAN style="color: #0000ff"><EM><STRONG>Note that this blog was published before our branding changes related to SAP technology announced in January 2021.</STRONG></EM></SPAN><BR /> <H2 id="toc-hId-935266404"><STRONG>Where the story begins</STRONG></H2><BR /> When we first released the new concept of “SAP Cloud Platform Extension Factory”, our goal was to simplify the extension journey for our SAP customers. SAP Cloud Platform was and still is THE platform to build extensions for existing SAP applications. To improve that experience, we wanted to provide connectivity capabilities that would enable customers to easily and securely connect to the needed data sources, access APIs and events and manage those connections with an intuitive UI. Essentially, the goal of Extension Factory was to provide:<BR /> <UL><BR /> <LI>A standardized way to register SAP LoB solutions on SAP Cloud Platform</LI><BR /> <LI>A central registry for registered solutions with their APIs, events, and credentials</LI><BR /> <LI>One developer experience for applications built on the SAP Cloud Platform, regardless of the runtime</LI><BR /> </UL><BR /> But as we soon realized, that was just the first step...<BR /> <H2 id="toc-hId-738752899"><STRONG>Where we are today</STRONG></H2><BR /> The <A href="https://www.sap.com/products/cloud-platform/capabilities/enterprise-extensions.html" target="_blank" rel="noopener noreferrer">SAP Cloud Platform Extension Suite</A> not only includes everything outlined above, it also provides services, tools and low-code capabilities to help realize your extension use cases. The complete portfolio is available on the <A href="https://discovery-center.cloud.sap/serviceCatalog" target="_blank" rel="nofollow noopener noreferrer">SAP Cloud Platform Discovery Center</A>, but let’s break it down into 3 main pillars:<BR /> <UL><BR /> <LI><STRONG><U>Digital Experience</U></STRONG></LI><BR /> </UL><BR /> Establish new, engaging and contextual multi-channel experiences to facilitate access to relevant data for both internal and external users. Enhance digital collaboration functionalities with intelligent technologies, like integrated chatbots to assist and guide users throughout their day. Create native mobile apps using our SAP Cloud Platform SDKs for Android and iOS.<BR /> <UL><BR /> <LI><STRONG><U>Digital </U></STRONG><STRONG><U>Process</U></STRONG><STRONG><U> Automation</U></STRONG></LI><BR /> </UL><BR /> Digitalize and automate paper-based tasks and business processes to increase efficiency, empower the end user and allow your workforce to focus on value-adding tasks. Combine workflow capabilities with automation technologies to achieve your desired business result faster. Since Q2 2020, we offer live process content packages on the <A href="https://api.sap.com/themes/WorkflowManagement" target="_blank" rel="noopener noreferrer">SAP API Business Hub</A> to accelerate implementation of digital business processes.<BR /> <UL><BR /> <LI><STRONG><U>Development Efficiency</U></STRONG></LI><BR /> </UL><BR /> Jumpstart or accelerate your project, from development through lifecycle management. Within this pillar you’ll find tools, services and APIs that can help you start building your application extension. For example,<BR /> <UL><BR /> <LI>Use our SAP Business Application Studio as your cloud-based IDE, complete with templates for mobile, workflow and UI development.</LI><BR /> <LI>Implement important security concepts and develop secure applications with our Enterprise Security Services</LI><BR /> <LI>Manage the lifecycle of your applications using our integrated DevOps portfolio.</LI><BR /> <LI>Looking for deployment options? Choose the runtime that best fits your business requirements and skill set: Cloud Foundry Runtime on the Cloud Foundry environment, leverage Kubernetes-based technology with Kyma Runtime or Serverless Runtime. And of course, transform existing ABAP assets unlocking the full potential of ABAP in the cloud, a.k.a, the ABAP environment.</LI><BR /> </UL><BR /> <H2 id="toc-hId-542239394"><STRONG>What comes next</STRONG></H2><BR /> We will continue to enhance the capabilities of our SAP Cloud Platform Integration and Extension Suites to cover more use cases. For information on what's to come, check out:<BR /> <UL><BR /> <LI><A href="https://open.sap.com/courses/cp11" target="_blank" rel="noopener noreferrer">Introduction to SAP Cloud Platform Extension Suite (OpenSAP course)</A></LI><BR /> <LI><A href="https://www.sap.com/products/roadmaps/finder-all.html?pdf-asset=cad48d29-c37c-0010-82c7-eda71af511fa&amp;page=1&amp;sort=title_asc" target="_blank" rel="noopener noreferrer">SAP Cloud Platform Road Map</A></LI><BR /> <LI><A href="https://discovery-center.cloud.sap/serviceCatalog" target="_blank" rel="nofollow noopener noreferrer">SAP Cloud Platform Discovery Center</A></LI><BR /> </UL><BR /> Oh, and don’t be surprise if you stop seeing SAP Cloud Platform Extension Factory on slides, road maps or service names. For example, our runtime names, will no longer include “Extension Factory”. They’ll follow the regular service naming standards:<BR /> <UL><BR /> <LI><A href="https://discovery-center.cloud.sap/serviceCatalog/cloud-foundry-runtime" target="_blank" rel="nofollow noopener noreferrer">SAP Cloud Platform Cloud Foundry Runtime</A></LI><BR /> <LI><A href="https://discovery-center.cloud.sap/serviceCatalog/kyma-runtime" target="_blank" rel="nofollow noopener noreferrer">SAP Cloud Platform Kyma Runtime</A></LI><BR /> <LI><A href="https://discovery-center.cloud.sap/serviceCatalog/serverless-runtime" target="_blank" rel="nofollow noopener noreferrer">SAP Cloud Platform Serverless Runtime</A></LI><BR /> </UL><BR /> In Summary, if you are looking for information on how SAP Cloud Platform can help you build and manage your extensions, look for <STRONG>SAP Cloud Platform Extension Suite</STRONG> and you’ll be in the right place. 2020-09-14T13:46:05+02:00 https://community.sap.com/t5/technology-blogs-by-sap/sap-cloud-platform-extension-factory-serverless-runtime-function-as-a/ba-p/13482670 SAP Cloud Platform [Extension Factory], serverless runtime | Function-as-a-Service | FaaS 2020-09-21T14:49:15+02:00 CarlosRoggan https://community.sap.com/t5/user/viewprofilepage/user-id/5495 <P style="text-align: center"><STRONG>SAP Cloud Platform Extension Factory, serverless runtime</STRONG></P><BR /> <P style="text-align: center">|</P><BR /> <P style="text-align: center"><STRONG>SAP Cloud Platform Serverless Runtime</STRONG></P><BR /> <P style="text-align: center">|</P><BR /> <P style="text-align: center"><STRONG>SAP Cloud Platform Functions - Beta</STRONG></P><BR /> <P style="text-align: center">|</P><BR /> <P style="text-align: center"><STRONG>Function-as-a-Service</STRONG></P><BR /> <P style="text-align: center">|</P><BR /> <P style="text-align: center"><STRONG>FaaS</STRONG></P><BR /> <P style="text-align: center">|</P><BR /> &nbsp;<BR /> <BR /> <SPAN style="color: #999999">I'm confused...</SPAN><BR /> <SPAN style="color: #999999">What’s the difference?</SPAN><BR /> <BR /> To give a short answer: It’s all the same<BR /> (almost)<BR /> At the end, we can write some javascript code and it runs in a serverless environment<BR /> <BR /> <SPAN style="color: #999999">What is it, precisely?</SPAN><BR /> <BR /> It is a service offering in the SAP Cloud Platform, Cloud Foundry environment<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/09/tile-1.jpg" height="324" width="506" /></P><BR /> &nbsp;<BR /> <BR /> <SPAN style="color: #999999">But why that strange name?</SPAN><BR /> <BR /> While the name itself, <STRONG>Serverless Runtime</STRONG>, might still sound confusing, it makes more sense if we compare it to other “runtime” offerings in SAP Cloud Platform:<BR /> <BR /> <EM>Application Runtime</EM><BR /> The classic way of writing e.g. a java web application and deploying it to the cloud where it runs on classic java server with underlying JRE. The application developer takes care of operating and maintaining, etc.<BR /> Agree that these efforts are already less that in the even more classical onPrem world<BR /> <BR /> <EM>Serverless Runtime</EM><BR /> Here the developer doesn’t need to care about the runtime, meaning that he writes the code and the environment takes care about scaling etc just like it is expected of a serverless environment.<BR /> And, as expected, it causes cost only when running<BR /> This is the right choice for lightweight extensions, small portions of javascript code<BR /> It is nicely coupled with other offerings like Enterprise Messaging, Backend Service, OData Provisioning<BR /> <BR /> <EM>Kyma Runtime</EM><BR /> Bigger, more powerful, more flexible, more costly<BR /> <BR /> While the <EM>Serverless Runtime</EM> is a "service" offering, it also provides a subscription-based tool:<BR /> The <EM>Extension Center</EM><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/09/ExtensionCenter-1.jpg" /></P><BR /> <SPAN style="color: #999999">Nice, but where are the functions?</SPAN><BR /> <BR /> The screenshot helps us to understand:<BR /> <BR /> The name "Serverless Runtime" is an umbrella for several capabilities that can be used to build serverless extensions.<BR /> Writing functions is only one of the capabilities, provided by "Serverless Runtime"<BR /> We don't see any "Function" in the Extension Center UI. Instead, a&nbsp; function project is called "Extension".<BR /> <BR /> <SPAN style="color: #999999">Why?</SPAN><BR /> <BR /> We understand that this is not a general worldwide FaaS technology product. Functions are meant to be part of a serverless extension scenario.<BR /> An extension scenario which is meant to be simple and still provides the possibility to write code.<BR /> And in fact: it is REALLY easy<BR /> <BR /> <SPAN style="color: #999999">Blablabla...</SPAN><BR /> <BR /> Really.<BR /> Try to imagine this example scenario:<BR /> Get notified about Backend changes with Enterprise Messaging<BR /> On every change, a Function is triggered<BR /> It can call an API with OData provisioning to get more details<BR /> The function can store data with Backend Service<BR /> <BR /> Such a powerful extension scenario can be realized completely serverless, with few lines of code and little configuration<BR /> No local dev, no operation, no maintenance, no database trouble, no scaling headaches.<BR /> And at low cost, as everything has to be payed only when it does its work<BR /> <BR /> <SPAN style="color: #999999">OK, cool.</SPAN><BR /> <SPAN style="color: #999999">But what if the scenario grows and the offerings don't cover the required functionality?</SPAN><BR /> <BR /> In that case, the function can be easily and seamlessly migrated to <EM>Kyma</EM><BR /> <BR /> <SPAN style="color: #999999">Sounds like a marketing slogan...</SPAN><BR /> <BR /> It can be easily proven:<BR /> Both Kyma and Functions have the same underlying technology (Kybernetes)<BR /> <BR /> <SPAN style="color: #999999">Cool, thanks</SPAN><BR /> <BR /> Cool, time to close the blog....<BR /> <BR /> <SPAN style="color: #999999">Ehmmm - didn't you forget anything?</SPAN><BR /> <BR /> Thank you for reading<BR /> <BR /> <SPAN style="color: #999999">Welcome. Missing info: which is the <EM>CORRECT</EM> name?</SPAN><BR /> <BR /> <STRONG>SAP Cloud Platform Serverless Runtime</STRONG><BR /> <BR /> <SPAN style="color: #999999">Last question: how can we learn more?</SPAN><BR /> <BR /> This <A href="https://blogs.sap.com/2020/01/17/sap-cloud-platform-extension-factory-serverless-runtime-is-ga-now/" target="_blank" rel="noopener noreferrer">announcement blog</A> gives an introduction and overview about Serverless Runtime<BR /> SAP Help Portal: Serverless Runtime <A href="https://help.sap.com/viewer/bf7b2ff68518427c85b30ac3184ad215/Cloud/en-US/7b8cc2b0e8d141d6aa37c7dff4d70b82.html" target="_blank" rel="noopener noreferrer">official docu</A><BR /> Recommended <A href="https://blogs.sap.com/2020/06/17/writing-functions-as-a-service-overview-of-blogs" target="_blank" rel="noopener noreferrer">series of tutorials</A> which explain in detail how to implement functions<BR /> <BR /> <SPAN style="color: #999999">Thanks</SPAN> 2020-09-21T14:49:15+02:00 https://community.sap.com/t5/technology-blogs-by-sap/writing-function-as-a-service-11-how-and-why-access-http-api/ba-p/13481267 Writing Function-as-a-Service [11]: How and Why access HTTP API 2020-10-15T09:57:49+02:00 CarlosRoggan https://community.sap.com/t5/user/viewprofilepage/user-id/5495 This blog is part of a&nbsp;<A href="https://blogs.sap.com/2020/06/17/writing-functions-as-a-service-overview-of-blogs/" target="_blank" rel="noopener noreferrer">series of tutorials</A>&nbsp;explaining how to write serverless functions using the Functions-as-a-Service offering in&nbsp;<STRONG>SAP Cloud Platform Serverless Runtime</STRONG><BR /> <P style="text-align: right">Quicklinks:<BR /> <SPAN style="font-size: smaller"><A href="#quickguide" target="_blank" rel="nofollow noopener noreferrer">Quick Guide</A><BR /> <A href="#samples" target="_blank" rel="nofollow noopener noreferrer">Sample Code</A></SPAN></P><BR /> <BR /> <H2 id="toc-hId-936159144">Introduction</H2><BR /> In this blog we're talking about functions with HTTP trigger only. These are functions that are invoked with HTTP request.<BR /> In such scenarios, the function returns a value which ends up in the response body of the calling client (e.g. browser)<BR /> Sometimes, the function handler code needs more information that it gets from the FaaS runtime<BR /> Also, it may need to write custom info to the response<BR /> <BR /> For these cases, the FaaS runtime allows access to the underlying native node.js HTTP API<BR /> For those of you who require such functionality, I’m providing a silly example, to make your life easier<BR /> <BR /> First of all, 2 basic info that we have to understand:<BR /> <OL><BR /> <LI>In most cases, access to the underlying HTTP API is not needed.<BR /> As such, if we need it, we have to enable it<BR /> That’s done in <SPAN style="font-family: Courier New">faas.json</SPAN>, for each function definition</LI><BR /> <LI>The underlying HTTP API is the standard node.js <SPAN style="font-family: Courier New">http</SPAN> module<BR /> As such, no special tutorial needed here, please refer to the standard documentation<BR /> Here: <A style="font-size: 1rem" href="https://nodejs.org/api/http.html" target="_blank" rel="nofollow noopener noreferrer">https://nodejs.org/api/http.html</A></LI><BR /> <LI>And there’s one more basic info<BR /> We cannot mix both approaches<BR /> Either use the standard FaaS convenience methods OR use the HTTP API<BR /> With "FaaS convenience methods" I mean the following<BR /> Use return value to set the response:<BR /> <SPAN style="font-family: Courier New">return ‘Error, invalid function invocation’</SPAN><BR /> Use convenience method to set the status<BR /> <SPAN style="font-family: Courier New">event.setUnauthorized()</SPAN><BR /> With other words: if we want to add custom header to the response, we cannot use <SPAN style="font-family: Courier New">event.setUnauthorized()</SPAN> to set the status. We have to set the status with <SPAN style="font-family: Courier New">response.writeHead(400)</SPAN></LI><BR /> </OL><BR /> <H2 id="toc-hId-739645639">Overview</H2><BR /> <UL><BR /> <LI><A href="#howto" target="_blank" rel="nofollow noopener noreferrer">How to use HTTP API</A></LI><BR /> <LI><A href="#usecases" target="_blank" rel="nofollow noopener noreferrer">Example use cases</A></LI><BR /> <LI><A href="#create" target="_blank" rel="nofollow noopener noreferrer">Create sample function</A></LI><BR /> <LI><A href="#run" target="_blank" rel="nofollow noopener noreferrer">Run sample function</A></LI><BR /> </UL><BR /> <H2 id="toc-hId-543132134">Prerequisites</H2><BR /> If you're new to Serverless Runtime, Function-as-a-Service, you should check out the <A href="https://blogs.sap.com/2020/06/17/writing-functions-as-a-service-overview-of-blogs/" target="_blank" rel="noopener noreferrer">overview of blogs</A> and read all of them...<BR /> <H2 id="howto" id="toc-hId-346618629">How to use HTTP API</H2><BR /> First of all, the access to the API needs to be enabled.<BR /> This is done in a function definition in&nbsp; <SPAN style="font-family: Courier New">faas.json</SPAN><BR /> <PRE class="language-javascript"><CODE>"functions": {<BR /> "function-with-httpapi": {<BR /> "httpApi": true</CODE></PRE><BR /> Once enabled, the <SPAN style="font-family: Courier New">http</SPAN> property of <SPAN style="font-family: Courier New">event</SPAN> will be filled with <SPAN style="font-family: Courier New">request</SPAN> and <SPAN style="font-family: Courier New">response</SPAN> objects<BR /> <PRE class="language-javascript"><CODE>module.exports = async function (event, context) {<BR /> const request = event.http.request<BR /> const response = event.http.response</CODE></PRE><BR /> The <SPAN style="font-family: Courier New">request</SPAN> object represents the class <A href="https://nodejs.org/api/http.html#http_class_http_clientrequest" target="_blank" rel="noopener noreferrer nofollow">http.ClientRequest&nbsp;</A><BR /> and the <SPAN style="font-family: Courier New">response</SPAN> object the <A href="https://nodejs.org/api/http.html#http_class_http_serverresponse" target="_blank" rel="noopener noreferrer nofollow">http.ServerResponse</A><BR /> <BR /> And that's it about accessing the HTTP API<BR /> <H2 id="usecases" id="toc-hId-150105124">Example use cases</H2><BR /> Now let's see why and how we might need to use it<BR /> <BR /> A few example use cases where we need access to HTTP API:<BR /> <UL><BR /> <LI>HTTP method</LI><BR /> <LI>Query parameters</LI><BR /> <LI>Request Headers</LI><BR /> <LI>Trigger name</LI><BR /> <LI>Response Headers</LI><BR /> <LI>Response Body</LI><BR /> <LI>Response Status</LI><BR /> </UL><BR /> <SPAN style="text-decoration: underline">HTTP method</SPAN><BR /> <BR /> Sometimes we need to know with which HTTP verb we've been invoked. For instance, if our function should distinguish between GET or POST, etc<BR /> We can throw an error, or react accordingly<BR /> <PRE class="language-javascript"><CODE>const httpMethod = request.method<BR /> if (httpMethod != 'POST'){<BR /> response.writeHead(405, {<BR /> 'Content-Type': 'text/plain',<BR /> 'Allow': 'POST'<BR /> });<BR /> response.write('Request failed. Method not allowed. See response headers for hint');<BR /> response.end();<BR /> </CODE></PRE><BR /> <SPAN style="text-decoration: underline">Query parameters</SPAN><BR /> <BR /> Query parameters are the params that can be added to a URL after the <SPAN style="font-size: larger;font-family: Courier New">?</SPAN><BR /> Multiple parameters are appended with <SPAN style="font-size: larger;font-family: Courier New"><STRONG>&amp;</STRONG>&nbsp;</SPAN><BR /> E.g.<BR /> <SPAN style="color: #0000ff">xxxxx?customerName=otto&amp;userid=123</SPAN><BR /> <BR /> They’re accessed via the <SPAN style="font-family: Courier New">query</SPAN> property<BR /> <PRE class="language-javascript"><CODE>const name = event.http.request.query.customerName</CODE></PRE><BR /> It returns the value of the param<BR /> <BR /> <SPAN style="text-decoration: underline">Request Headers</SPAN><BR /> <BR /> We can find the headers sent with the request in the headers property<BR /> <PRE class="language-javascript"><CODE>request.headers</CODE></PRE><BR /> <SPAN style="text-decoration: underline">Trigger name</SPAN><BR /> <BR /> Two interesting headers are those provided by the <EM>FaaS</EM> runtime, giving info about the used trigger<BR /> <PRE class="language-javascript"><CODE>const triggerName = request.headers['sap-faas-http-trigger-name']<BR /> const triggerPath = request.headers['sap-faas-http-trigger-path'] </CODE></PRE><BR /> What is the difference?<BR /> /<BR /> Yes, the slash makes the path<BR /> In our example, the trigger name is <EM>customlogin</EM> and the path&nbsp; customlogin/<BR /> <BR /> <SPAN style="text-decoration: underline">Response Headers</SPAN><BR /> <BR /> In case of response object, we're interested in modifying it.<BR /> For instance, we might want to send some additional information in the response header, as it might be required by the caller of our function<BR /> To add own headers to the response:<BR /> <PRE class="language-javascript"><CODE>response.set('MyHeader', 'MyValue')<BR /> <BR /> response.append('CustomHeader', 'CustomValue')</CODE></PRE><BR /> Alternatively, set multiple headers and status at once<BR /> <PRE class="language-abap"><CODE>response.writeHead(403, {<BR /> 'Content-Type': 'text/plain',<BR /> 'FailureHint': 'Authorization required, see docu'<BR /> });</CODE></PRE><BR /> <SPAN style="text-decoration: underline">Response Body</SPAN><BR /> <BR /> In most cases, we set the response body using the standard way in FaaS: as return value<BR /> However, we might need to switch to http API, due to requirements of caller who might need some custom text in the response body in case of failure, etc<BR /> If this is the case we can use standard way of <SPAN style="font-family: Courier New">http.ServerResponse</SPAN> class<BR /> <PRE class="language-javascript"><CODE>response.write('Error. Don't ask admin. Don't see log for no info')</CODE></PRE><BR /> Note:<BR /> As mentioned, we cannot mix the used APIs.<BR /> If we set a header in the response, then we have to use this way of writing response<BR /> <BR /> <SPAN style="text-decoration: underline">Response Status </SPAN><BR /> <BR /> There can be several reasons why we might wish to set the response status code.<BR /> For instance, if we don’t support all the HTTP methods, then we have to set the response status to 405, which means Method not allowed<BR /> Also, we might have special requirements to the incoming call, so we would have to decide on our own to set the status code to 400, Bad Request<BR /> Please see Links section for reference<BR /> <BR /> Setting the response status code to a custom value can be again done in several ways<BR /> <BR /> E.g. directly setting the property value:<BR /> <PRE class="language-javascript"><CODE>response.statusCode = 405</CODE></PRE><BR /> Or again using the convenience method, where we can set a custom header at the same time:<BR /> <PRE class="language-javascript"><CODE>response.writeHead(405, {<BR /> 'Content-Type': 'text/plain',<BR /> </CODE></PRE><BR /> <H2 id="create" id="toc-hId--46408381">Create sample Function</H2><BR /> To make things less theoretical, you can find here a reusable sample project, which is meant to showcase how the HTTP API can be used.<BR /> As usual, it is a small silly sample, without real use case, but focusing on demonstrating some capabilities for your convenience, so you can easily copy&amp;paste and adapt for your own needs<BR /> <BR /> Please refer to the <A href="#samples" target="_blank" rel="nofollow noopener noreferrer">Appendix</A> for the full sample code<BR /> <BR /> Note:<BR /> In case that it doesn’t suit your needs, you can send me a personal message<BR /> <BR /> In this example, we’re simulating a kind of strange special login process for a customer app<BR /> The user of the function is required to pass a couple of pieces of login information:<BR /> <BR /> Customer Name as query param<BR /> Customer Password as request header<BR /> Authorization scope as body in a POST request<BR /> As such, only POST is supported<BR /> In addition, our function simulates usage of multiple endpoints and only one of them is meant for productive usage with login<BR /> As such, the function code has to access request header to determine the used trigger<BR /> <H3 id="toc-hId--113839167">Code walkthrough</H3><BR /> Our function does nothing than accessing the HTTP API and using it for some login-checks<BR /> In case of success, it does nothing, just return some silly text<BR /> <BR /> <SPAN style="text-decoration: underline">Preparation</SPAN><BR /> <BR /> First we declare the usage of the HTTP API in <SPAN style="font-family: Courier New">faas.json</SPAN><BR /> <PRE class="language-javascript"><CODE>"functions": {<BR /> "function-with-httpapi": {<BR /> "httpApi": true</CODE></PRE><BR /> Then we can access the HTTP API in function code.<BR /> Otherwise, the object would be empty<BR /> <PRE class="language-javascript"><CODE>const request = event.http.request<BR /> const response = event.http.response</CODE></PRE><BR /> Now, in our function, we can implement custom checks which wouldn't be possible without the HTTP API.<BR /> Our function contains 4 checks:<BR /> <BR /> <SPAN style="text-decoration: underline">1. Check for correct HTTP verb:</SPAN><BR /> <PRE class="language-javascript"><CODE>const httpMethod = request.method<BR /> if (httpMethod != 'POST'){<BR /> response.writeHead(405, {<BR /> 'Content-Type': 'text/plain',<BR /> 'Allow': 'POST'<BR /> });<BR /> response.write('Request failed. Method not allowed. See response headers for hint');<BR /> </CODE></PRE><BR /> <SPAN style="text-decoration: underline">2. Check for desired productive endpoint</SPAN><BR /> <BR /> In <SPAN style="font-family: Courier New">faas.json</SPAN> we’ve defined 2 triggers.<BR /> The only reason for the second one (<EM>nologin</EM>) is to be able to run this check<BR /> <PRE class="language-javascript"><CODE>const triggerName = request.headers['sap-faas-http-trigger-name']<BR /> if(triggerName != 'customlogin'){<BR /> response.statusCode = 400<BR /> </CODE></PRE><BR /> <SPAN style="text-decoration: underline">3. Check for authentication</SPAN><BR /> <BR /> Note that we don’t verify the customer name, only password – for the sake of simplicity<BR /> We need to access the request header<BR /> <PRE class="language-javascript"><CODE>const customerAuth = request.headers['customer-auth']<BR /> if(! customerAuth){<BR /> response.writeHead(401, {<BR /> 'Content-Type': 'text/plain',<BR /> 'FailureHint': 'Required: request header customer-auth containing customer password'<BR /> });<BR /> </CODE></PRE><BR /> <SPAN style="text-decoration: underline">4. Check scope</SPAN><BR /> <BR /> We use this to show how to access the request body<BR /> <PRE class="language-javascript"><CODE>if((! request.body) || (JSON.parse(request.body).customerAccess != 'true')){<BR /> response.writeHead(403, {<BR /> 'FailureHint': 'Authorization required...'<BR /> <BR /> </CODE></PRE><BR /> <SPAN style="text-decoration: underline">Success response</SPAN><BR /> <BR /> If the request has passed all checks, then we do nothing,<BR /> Just note that here we’re using the standard way of using a function:<BR /> The response body is sent as return value of the function<BR /> When I mentioned earlier that we cannot mix the HTTP API with standard API, I meant we cannot mix in one response definition. But here, in case of success, we don't do any custom header setting, etc, so we can just return a text<BR /> <PRE class="language-javascript"><CODE>const customerName = request.query.customerName <BR /> return `Function called successfully. Customer '${customerName}' is welcome.`<BR /> </CODE></PRE><BR /> <H2 id="run" id="toc-hId--439435391">Run the sample Function</H2><BR /> Let's deploy and run the sample action, to see our HTTP API implementation in action<BR /> After deploy, we want to see if your checks are executed properly and if we get the expected results in response body , status and header<BR /> <BR /> <SPAN style="text-decoration: underline"><span class="lia-unicode-emoji" title=":right_arrow:">➡️</span>1. Wrong HTTP verb</SPAN><BR /> <BR /> In our first example, we choose to use a wrong HTTP method, to see our first check working<BR /> <TABLE style="height: 117px;width: 100%;border-collapse: collapse;border-style: none" border="0"><BR /> <TBODY><BR /> <TR style="height: 13px"><BR /> <TD style="width: 100%;height: 13px" colspan="2"><STRONG>Request</STRONG></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">URL</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller;font-family: Courier New"><A href="https://...faas.../customlogin/" target="test_blank" rel="nofollow noopener noreferrer">https://...faas.../customlogin/</A></SPAN></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">Verb</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller;font-family: Courier New">GET</SPAN></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">Header</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller;font-family: Courier New">-</SPAN></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">Body</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller;font-family: Courier New">-</SPAN></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 100%;height: 13px" colspan="2"><STRONG>Response</STRONG></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">Body</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller">Error text</SPAN></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">Status</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller;font-family: Courier New">405</SPAN></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">Header</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller;font-family: Courier New">allow</SPAN></TD><BR /> </TR><BR /> </TBODY><BR /> </TABLE><BR /> See result:<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/10/postman_405.jpg" height="210" width="401" /></P><BR /> &nbsp;<BR /> <BR /> <SPAN style="text-decoration: underline"><span class="lia-unicode-emoji" title=":right_arrow:">➡️</span>2. Wrong endpoint</SPAN><BR /> <BR /> Now we use the correct HTTP method, but the wrong trigger<BR /> <TABLE style="height: 117px;width: 100%;border-collapse: collapse;border-style: none" border="0"><BR /> <TBODY><BR /> <TR style="height: 13px"><BR /> <TD style="width: 100%;height: 13px" colspan="2"><STRONG>Request</STRONG></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">URL</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller;font-family: Courier New"><A href="https://...faas.../nologin/" target="test_blank" rel="nofollow noopener noreferrer">https://...faas.../nologin/</A></SPAN></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">Verb</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller;font-family: Courier New">POST</SPAN></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">Header</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller;font-family: Courier New">-</SPAN></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">Body</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-family: Courier New"><SPAN style="font-size: 11.6667px">-</SPAN></SPAN></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 100%;height: 13px" colspan="2"><STRONG>Response</STRONG></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">Body</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller">Error text</SPAN></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">Status</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller;font-family: Courier New">400</SPAN></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">Header</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller;font-family: Courier New">-</SPAN></TD><BR /> </TR><BR /> </TBODY><BR /> </TABLE><BR /> See result:<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/10/2postman_400.jpg" height="123" width="398" /></P><BR /> <SPAN style="text-decoration: underline"><span class="lia-unicode-emoji" title=":right_arrow:">➡️</span>3. Missing authentication</SPAN><BR /> <BR /> Next try: correct endpoint, but we don't send the required authentication data<BR /> <TABLE style="height: 117px;width: 100%;border-collapse: collapse;border-style: none" border="0"><BR /> <TBODY><BR /> <TR style="height: 13px"><BR /> <TD style="width: 100%;height: 13px" colspan="2"><STRONG>Request</STRONG></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">URL</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller;font-family: Courier New"><A href="https://...faas.../customlogin/" target="test_blank" rel="nofollow noopener noreferrer">https://...faas.../customlogin/</A></SPAN></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">Verb</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller;font-family: Courier New">POST</SPAN></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">Header</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller;font-family: Courier New">-</SPAN></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">Body</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-family: Courier New"><SPAN style="font-size: 11.6667px">-</SPAN></SPAN></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 100%;height: 13px" colspan="2"><STRONG>Response</STRONG></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">Body</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller">Error text</SPAN></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">Status</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller;font-family: Courier New">401</SPAN></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">Header</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller;font-family: Courier New">failurehint</SPAN></TD><BR /> </TR><BR /> </TBODY><BR /> </TABLE><BR /> See result:<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/10/postman_401.jpg" height="213" width="395" /></P><BR /> <SPAN style="text-decoration: underline"><span class="lia-unicode-emoji" title=":right_arrow:">➡️</span>4. Missing authorization</SPAN><BR /> <BR /> We send a request with mostly correct settings, only the scope, to be passed in the request body, is&nbsp; missing<BR /> <TABLE style="height: 117px;width: 100%;border-collapse: collapse;border-style: none" border="0"><BR /> <TBODY><BR /> <TR style="height: 13px"><BR /> <TD style="width: 100%;height: 13px" colspan="2"><STRONG>Request</STRONG></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">URL</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller;font-family: Courier New"><A href="https://...faas.../customlogin/" target="test_blank" rel="nofollow noopener noreferrer">https://...faas.../customlogin/</A></SPAN></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">Verb</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller;font-family: Courier New">POST</SPAN></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">Header</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller;font-family: Courier New">customer-auth : abc123</SPAN></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">Body</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-family: Courier New"><SPAN style="font-size: 11.6667px">-</SPAN></SPAN></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 100%;height: 13px" colspan="2"><STRONG>Response</STRONG></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">Body</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller">Error text</SPAN></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">Status</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller;font-family: Courier New">403</SPAN></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">Header</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller;font-family: Courier New">failurehint</SPAN></TD><BR /> </TR><BR /> </TBODY><BR /> </TABLE><BR /> See result:<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/10/4postman_403-1.jpg" height="77" width="401" /></P><BR /> <P style="overflow: hidden;margin-bottom: 0px"><SPAN style="text-decoration: underline"><span class="lia-unicode-emoji" title=":right_arrow:">➡️</span>5. Successful call</SPAN></P><BR /> Finally we send a request with correct settings, including the name parameter in the URL<BR /> <TABLE style="height: 117px;width: 100%;border-collapse: collapse;border-style: none" border="0"><BR /> <TBODY><BR /> <TR style="height: 13px"><BR /> <TD style="width: 100%;height: 13px" colspan="2"><STRONG>Request</STRONG></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">URL</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller;font-family: Courier New"><A href="https://...faas.../customlogin/?customerName=otto" target="test_blank" rel="nofollow noopener noreferrer">https://...faas.../customlogin/?customerName=otto</A></SPAN></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">Verb</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller;font-family: Courier New">POST</SPAN></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">Header</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller;font-family: Courier New">customer-auth : abc123</SPAN></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">Body</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller;font-family: Courier New">{ "customerAccess" : "true" }</SPAN></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 100%;height: 13px" colspan="2"><STRONG>Response</STRONG></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">Body</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller">Success text</SPAN></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">Status</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller;font-family: Courier New">200</SPAN></TD><BR /> </TR><BR /> <TR style="height: 13px"><BR /> <TD style="width: 9.68%;height: 13px"><SPAN style="font-size: smaller">Header</SPAN></TD><BR /> <TD style="width: 90.32%;height: 13px"><SPAN style="font-size: smaller;font-family: Courier New">-</SPAN></TD><BR /> </TR><BR /> </TBODY><BR /> </TABLE><BR /> See result:<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/10/5postman_200.jpg" height="191" width="375" /></P><BR /> <BR /> <H2 id="toc-hId--635948896">Summary</H2><BR /> In this tutorial, we’ve learned which steps are required to access the HTTP API<BR /> This is probably not necessary in most use cases of serverless function<BR /> But sometimes it required, so we need to know how it works<BR /> <BR /> We've learned that we need to enable it first i<SPAN style="font-size: 1rem">n </SPAN><SPAN style="font-family: Courier New">faas.json</SPAN><SPAN style="font-size: 1rem"><BR /> Then we can access it via the <SPAN style="font-family: Courier New">event.http </SPAN></SPAN><SPAN style="font-size: 1rem">property<BR /> And we've understood that we can use the standard node.js http methods&nbsp;</SPAN><BR /> <H2 id="quickguide" id="toc-hId--832462401">Quick Guide</H2><BR /> faas.json:<BR /> <PRE class="language-javascript"><CODE>"my-function": {<BR /> "httpApi": true<BR /> </CODE></PRE><BR /> Function code:<BR /> <PRE class="language-javascript"><CODE>const request = event.http.request<BR /> const response = event.http.response</CODE></PRE><BR /> <H2 id="links" id="toc-hId--681721549">Links</H2><BR /> <UL><BR /> <LI>Reference for underlying HTTP API: <A href="https://nodejs.org/api/http.html" target="_blank" rel="noopener noreferrer nofollow">https://nodejs.org/api/http.html</A></LI><BR /> <LI>API for request: <A href="https://nodejs.org/api/http.html#http_class_http_clientrequest" target="_blank" rel="noopener noreferrer nofollow">https://nodejs.org/api/http.html#http_class_http_clientrequest</A></LI><BR /> <LI>API for response: <A href="https://nodejs.org/api/http.html#http_class_http_serverresponse" target="_blank" rel="noopener noreferrer nofollow">https://nodejs.org/api/http.html#http_class_http_serverresponse</A></LI><BR /> <LI>Spec for status codes: <A href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html" target="_blank" rel="noopener noreferrer nofollow">https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html</A></LI><BR /> <LI>Spec for status code 401:&nbsp;<A href="https://tools.ietf.org/html/rfc7235#section-3.1" target="_blank" rel="noopener noreferrer nofollow">https://tools.ietf.org/html/rfc7235#section-3.1</A></LI><BR /> <LI>Spec for status code 403: <A href="https://tools.ietf.org/html/rfc7231#section-6.5.3" target="_blank" rel="noopener noreferrer nofollow">https://tools.ietf.org/html/rfc7231#section-6.5.3</A></LI><BR /> <LI>Spec for status code 405: <A href="https://tools.ietf.org/html/rfc7231#section-6.5.5" target="_blank" rel="noopener noreferrer nofollow">https://tools.ietf.org/html/rfc7231#section-6.5.5</A></LI><BR /> </UL><BR /> <H2 id="samples" id="toc-hId--878235054">Appendix: All Project Files</H2><BR /> Here you can find the project files used for the sample, ready for copy&amp;paste<BR /> <BR /> <SPAN style="text-decoration: underline">faas.json</SPAN><BR /> <PRE class="language-javascript"><CODE>{<BR /> "project": "httpapiproject",<BR /> "version": "1",<BR /> "runtime": "nodejs10",<BR /> "library": "./src",<BR /> "functions": {<BR /> "function-with-httpapi": {<BR /> "module": "mymodule.js",<BR /> "httpApi": true<BR /> }<BR /> },<BR /> "triggers": {<BR /> "customlogin": {<BR /> "type": "HTTP",<BR /> "function": "function-with-httpapi"<BR /> },<BR /> "nologin": {<BR /> "type": "HTTP",<BR /> "function": "function-with-httpapi"<BR /> }<BR /> }<BR /> }</CODE></PRE><BR /> <SPAN style="text-decoration: underline">package.json</SPAN><BR /> <BR /> Adding dev dependency for local testing<BR /> <PRE class="language-javascript"><CODE>{<BR /> "devDependencies": {<BR /> "@sap/faas": "&gt;=0.7.0"<BR /> }<BR /> }<BR /> </CODE></PRE><BR /> <SPAN style="text-decoration: underline">mymodule.js</SPAN><BR /> <PRE class="language-javascript"><CODE>module.exports = async function (event, context) {<BR /> <BR /> // to access HTTP API, add param to function definition in faas.json: "httpApi": true<BR /> const request = event.http.request<BR /> const response = event.http.response<BR /> <BR /> // check request method<BR /> const httpMethod = request.method<BR /> if (httpMethod != 'POST'){<BR /> response.writeHead(405, {<BR /> 'Content-Type': 'text/plain',<BR /> 'Allow': 'POST'<BR /> });<BR /> response.write('Request failed. Method not allowed. See response headers for hint');<BR /> response.end();<BR /> return<BR /> }<BR /> <BR /> // check which HTTP trigger was used<BR /> const triggerName = request.headers['sap-faas-http-trigger-name']<BR /> if(triggerName != 'customlogin'){<BR /> response.statusCode = 400<BR /> response.write("Endpoint not supported. Use 'customlogin' endpoint")<BR /> response.end();<BR /> return<BR /> }<BR /> <BR /> // check authentication via request header<BR /> const customerAuth = request.headers['customer-auth']<BR /> if(! customerAuth){<BR /> response.writeHead(401, {<BR /> 'Content-Type': 'text/plain',<BR /> 'FailureHint': 'Required: request header customer-auth containing customer password'<BR /> });<BR /> response.write('Request failed. Unauthorized. Customer login data missing. See hint for more info');<BR /> response.end();<BR /> return<BR /> }<BR /> <BR /> // check authorization via request body <BR /> if((! request.body) || (JSON.parse(request.body).customerAccess != 'true')){<BR /> response.writeHead(403, {<BR /> 'Content-Type': 'text/plain',<BR /> 'FailureHint': 'Authorization for customer required: Request body with customer JSON access must be true'<BR /> });<BR /> response.write('Request failed. Forbidden. Customer authorization not sufficient. See hint for more info');<BR /> response.end();<BR /> return <BR /> }<BR /> <BR /> // use standard way of writing response<BR /> const customerName = request.query.customerName <BR /> return `Function called successfully. Customer '${customerName}' is welcome.`<BR /> };<BR /> </CODE></PRE> 2020-10-15T09:57:49+02:00 https://community.sap.com/t5/technology-blogs-by-sap/writing-function-as-a-service-13-secure-scenario-with-scope-and-consumer/ba-p/13466000 Writing Function-as-a-Service [13]: Secure scenario with scope and consumer 2020-10-29T15:06:37+01:00 CarlosRoggan https://community.sap.com/t5/user/viewprofilepage/user-id/5495 This blog is part of a&nbsp;<A href="https://blogs.sap.com/2020/06/17/writing-functions-as-a-service-overview-of-blogs/" target="_blank" rel="noopener noreferrer">series of tutorials</A>&nbsp;explaining how to write serverless functions using the Functions-as-a-Service offering in&nbsp;<STRONG>SAP Cloud Platform Serverless Runtime</STRONG><BR /> <P style="text-align: right">Quicklinks:<BR /> <SPAN style="font-size: smaller"><A href="#quickguide" target="_blank" rel="nofollow noopener noreferrer">Quick Guide</A><BR /> <A href="#samples" target="_blank" rel="nofollow noopener noreferrer">Sample Code</A></SPAN></P><BR /> <BR /> <H2 id="toc-hId-934458942">Introduction</H2><BR /> In the <A href="https://blogs.sap.com/2020/10/29/writing-function-as-a-service-12-adding-security/" target="_blank" rel="noopener noreferrer">previous blog</A> we’ve learned the basics about protecting a function with OAuth<BR /> What we didn’t learn: our function didn’t require a <STRONG>scope<BR /> </STRONG>In this blog, let’s learn how to enforce a scope in the JWT token and<BR /> - assign the scope to our user and call the function (REST client)<BR /> - call the function from a client application (node.js)<BR /> <H2 id="toc-hId-737945437">Overview</H2><BR /> Small recap:<BR /> In the previous tutorial, we’ve created a very silly small function and we’ve used framework functionality to protect it with small configuration snippet.<BR /> Furthermore, we created a very basic instance of XSUAA and connect the function to it<BR /> That was enough to protect our function with OAuth 2.0<BR /> The FaaS Runtime took care of rejecting HTTP requests which didn't send a valid JWT token<BR /> The FaaS Runtime used the connected XSUAA instance for validation<BR /> That was OK.<BR /> Fair enough for the beginning<BR /> Now, in today's tutorial we’re going to<BR /> - add a scope<BR /> - and in the function we check if the scope exists in the JWT<BR /> <BR /> These are the steps we're going to cover:<BR /> <OL><BR /> <LI>Create XSUAA</LI><BR /> <LI>Create Function<BR /> Implement scope check</LI><BR /> <LI>Call Function in user centric scenario</LI><BR /> <LI>Call Function with client app</LI><BR /> </OL><BR /> <H2 id="toc-hId-541431932">Prerequisites</H2><BR /> <UL><BR /> <LI>Basic understanding of OAuth, <A href="https://blogs.sap.com/2019/05/06/sap-cloud-platform-backend-service-tutorial-14-about-oauth-mechanism/" target="_blank" rel="noopener noreferrer">see easy intro</A>&nbsp;and <A href="https://blogs.sap.com/2019/04/29/sap-cloud-platform-backend-service-tutorial-13-api-called-from-external-tool/" target="_blank" rel="noopener noreferrer">description for using REST client</A></LI><BR /> <LI><A href="https://blogs.sap.com/2020/10/29/writing-function-as-a-service-12-adding-security/" target="_blank" rel="noopener noreferrer">Previous blog</A></LI><BR /> <LI>HTTP API <A href="https://blogs.sap.com/2020/10/15/writing-function-as-a-service-11-how-and-why-access-http-api/" target="_blank" rel="noopener noreferrer">blog post</A></LI><BR /> </UL><BR /> <H2 id="toc-hId-344918427">1. Create Instance of XSUAA</H2><BR /> We need an instance of XSUAA which is configured with a <STRONG>scope<BR /> </STRONG>We can <A href="#commands" target="_blank" rel="nofollow noopener noreferrer">update</A> the existing one, or create a new one<BR /> In my example, I create a new instance with the following security configuration in a file called&nbsp;<SPAN style="font-family: Courier New">xs-security_faas_scope.json</SPAN><BR /> <PRE class="language-javascript"><CODE>{<BR /> "xsappname" : "xsappforfaaswithscope",<BR /> "tenant-mode" : "dedicated",<BR /> "scopes": [<BR /> {<BR /> "name": "$XSAPPNAME.scopeforfunction",<BR /> "description": "Scope required for accessing function"<BR /> }<BR /> ],<BR /> "role-templates": [ { <BR /> "name" : "FunctionRoleTemplate", <BR /> "description" : "Role for serverless function", <BR /> "default-role-name" : "RoleForFunction",<BR /> "scope-references" : ["$XSAPPNAME.scopeforfunction"]<BR /> }],<BR /> "authorities":["$XSAPPNAME.scopeforfunction"]<BR /> }<BR /> </CODE></PRE><BR /> <SPAN style="text-decoration: underline">Explanation:</SPAN><BR /> <BR /> <SPAN style="font-family: Courier New">scopes</SPAN><BR /> We define a scope.<BR /> For us, thie means: when calling the function, a JWT token is not enough. The caller must have the scope. If yes, the scope is contained in the token<BR /> However, in the security configuration we only define the scope, such that XSUAA knows about it<BR /> If things go well (see below) XSUAA will issue a JWT token that contains the scope<BR /> However, XSUAA doesn't enforce the scope.<BR /> <BR /> <SPAN style="font-family: Courier New">role-templates</SPAN><BR /> A scope is nothing that can be assigned to a human user. For that, we need to define a “role”, along with “role-template”. That can be found in the Cloud Cockpit and an admin can assign the role to users<BR /> <BR /> <SPAN style="font-family: Courier New">authorities</SPAN><BR /> This attribute is meant for non-human users, for client apps, in a client-credentials scenario<BR /> With this statement, we accept that scope. A client application bound to XSUAA will get the scope in the JWT token<BR /> <BR /> <STRONG><SPAN style="text-decoration: underline">Create XSUAA</SPAN></STRONG><BR /> <BR /> We create an instance of XSUAA and we use above JSON parameters<BR /> Can be done in the Cloud Cockpit, or on command line:<BR /> <BR /> <SPAN style="background-color: black;color: white;font-family: Courier New">cf&nbsp;cs&nbsp;xsuaa&nbsp;application&nbsp;xsuaa_faas_scope&nbsp;-c&nbsp;xs-security_faas_scope.json</SPAN><BR /> <BR /> <STRONG><SPAN style="text-decoration: underline">Create Service Key</SPAN></STRONG><BR /> <BR /> As usual, we need a service key in order to reference it from FaaS and also from REST client (see below)<BR /> <BR /> <SPAN style="background-color: black;color: white;font-family: Courier New">cf csk xsuaa_faas_scope xsuaa_faasscope_servicekey</SPAN><BR /> <BR /> See <A href="#commands" target="_blank" rel="nofollow noopener noreferrer">Appendix</A> for all commands<BR /> <H2 id="toc-hId-148404922">2. Create Function</H2><BR /> After creating an instance of XSUAA service, we need to register it in FaaS, and use it in the function definition.<BR /> We’ve learned that in a <A href="https://blogs.sap.com/2020/07/23/writing-function-as-a-service-8-how-to-easily-use-platform-services/" target="_blank" rel="noopener noreferrer">previous tutorial</A><BR /> <BR /> <STRONG><U>Register the service in faas</U></STRONG><BR /> <BR /> For your convenience, find here the necessary commands<BR /> <BR /> Always need to login first to Cloud Foundry and/or FaaS client<BR /> <BR /> <SPAN style="background-color: black;color: white;font-family: Courier New">xfsrt-cli login</SPAN><BR /> <BR /> The convenient command to register a service interactively (the command line client will propose existing services, so we can choose. Precondition: only service instances with service key are proposed)<BR /> <BR /> <SPAN style="background-color: black;color: white;font-family: Courier New">xfsrt-cli faas service register</SPAN><BR /> <BR /> After registration, in the console, we get the info which we need to specify in <SPAN style="font-family: Courier New">faas.json</SPAN>:<BR /> the service key and the GUID of the service instance<BR /> <BR /> <STRONG><SPAN style="text-decoration: underline">Use the service in FaaS project</SPAN></STRONG><BR /> <BR /> <SPAN style="font-family: Courier New">faas.json</SPAN><BR /> <PRE class="language-javascript"><CODE> "services": {<BR /> "xsuaa-with-scope": {<BR /> "type": "xsuaa",<BR /> "instance": "&lt;your GUID of service instance&gt;",<BR /> "key": "xsuaa_faasscope_servicekey" <BR /> }<BR /> }<BR /> </CODE></PRE><BR /> See <A href="#samples" target="_blank" rel="nofollow noopener noreferrer">Appendix</A> for full <SPAN style="font-family: Courier New">faas.json</SPAN><BR /> <BR /> <STRONG><SPAN style="text-decoration: underline">Configure Security</SPAN></STRONG><BR /> <BR /> As learned in previous blog post, with below setting, we tell the FaaS runtime that we want them to enforce a valid JWT token<BR /> <PRE class="language-javascript"><CODE>"triggers": {<BR /> "prot": {<BR /> "type": "HTTP",<BR /> "function": "prot-func-with-scope",<BR /> "auth": {<BR /> "type": "xsuaa",<BR /> "service": "xsuaa-with-scope"<BR /> </CODE></PRE><BR /> <STRONG><SPAN style="text-decoration: underline">Enforce scope</SPAN></STRONG><BR /> <BR /> As mentioned earlier: the above setting will have the following consequence:<BR /> <BR /> Whenever our function is called with HTTP trigger, the request must contain a valid JWT token<BR /> Otherwise the call is rejected by the FaaS runtime (with proper status code and error message) and our function code is not even invoked.<BR /> <BR /> As such, the FaaS runtime enforces the authentication.<BR /> But it cannot take care of authorization in a generic way<BR /> <BR /> For example, a function might have the following logic:<BR /> If EDIT scope is available, the function may accept POST requests, otherwise only GET<BR /> Such logic has to be implemented manually by us<BR /> <BR /> We have to look into the JWT token, read the available scopes and check if the one which we require, is there.<BR /> The framework offers a convenience method which decodes the JWT token (if available)<BR /> We can then access the JWT payload as JSON object<BR /> <PRE class="language-javascript"><CODE>const jwtToken = event.decodeJsonWebToken()<BR /> const jwtScopes = jwtToken.payload.scope<BR /> </CODE></PRE><BR /> In order to check the scope, we need to know the exact scope name.<BR /> Background:<BR /> <BR /> We defined the scope name as<BR /> <SPAN style="font-family: Courier New">$XSAPPNAME.scopeforfunction</SPAN><BR /> The value of the variable <SPAN style="font-family: Courier New">$XSAPPNAME</SPAN> is generated on the cloud platform, as such we have to ask at runtime for the exact value.<BR /> The exact value is contained in the service key<BR /> And the service key is registered in FaaS<BR /> As such, we can ask FaaS for the xsuaa service<BR /> Then access the <SPAN style="font-family: Courier New">xsappname</SPAN> property<BR /> <PRE class="language-javascript"><CODE>const xsuaaCredentials = await context.getServiceCredentialsJSON('xsuaa-with-scope')<BR /> const requiredScope = xsuaaCredentials.xsappname + '.scopeforfunction'<BR /> </CODE></PRE><BR /> Based on above 2 code snippets we have the needed information:<BR /> Which scope do we expect (for whatever business case)<BR /> Which scope is contained in the JWT token<BR /> <BR /> In our example, we require a scope for calling the function.<BR /> To check if the scope is sent, we just look into the array of available scopes<BR /> If not available, we reject the request.<BR /> In our case, the correct status code is 403, because use is authenticated, but lacking authorization<BR /> In order to set the status, we need to use the HTTP API (see previous <A href="https://blogs.sap.com/2020/10/15/writing-function-as-a-service-11-how-and-why-access-http-api/" target="_blank" rel="noopener noreferrer">blog post</A>)<BR /> <BR /> Below snippet puts the snippets together:<BR /> <PRE class="language-javascript"><CODE>const xsuaaCredentials = await context.getServiceCredentialsJSON('xsuaa-with-scope')<BR /> const requiredScope = xsuaaCredentials.xsappname + '.scopeforfunction'<BR /> <BR /> // read the JWT token and check required scope<BR /> const jwtToken = event.decodeJsonWebToken()<BR /> const jwtScopes = jwtToken.payload.scope<BR /> if(! jwtScopes.includes(requiredScope)){<BR /> // fail with 403 <BR /> const response = event.http.response // must be enabled in faas.json<BR /> response.writeHead(403, {<BR /> ...</CODE></PRE><BR /> See <A href="#samples" target="_blank" rel="nofollow noopener noreferrer">Appendix</A> for full sample code<BR /> <BR /> Note:<BR /> Before using the HTTP API, it must be enabled, which is done in the <SPAN style="font-family: Courier New">faas.json</SPAN><BR /> <BR /> Note:<BR /> SAP provides security libraries and there’s a little helper function, recommended to use for the scope check<BR /> The function I’m talking about:<BR /> <SPAN style="font-family: Courier New"><a href="https://community.sap.com/t5/user/viewprofilepage/user-id/1387241">@Sap</a>/xssec: checkScope(scope)</SPAN><BR /> Please refer to Links section<BR /> In my examples, I’d like to keep the code free from dependencies (as there might be changes, etc), so I’m not using it. Please forgive<BR /> But for your convenience, I've created little sample code based on the library. See <A href="#samplewithlib" target="_blank" rel="nofollow noopener noreferrer">Appendix</A><BR /> <BR /> <STRONG><SPAN style="text-decoration: underline">Deploy function</SPAN></STRONG><BR /> <BR /> To deploy the function, you might find this command useful (run from project directory)<BR /> <SPAN style="background-color: black;color: white;font-family: Courier New">xfsrt-cli faas project deploy</SPAN><BR /> <H2 id="toc-hId--48108583">3.&nbsp;<STRONG>Call function in user centric scenario</STRONG></H2><BR /> After deploy, we want to test the security of our function<BR /> <UL><BR /> <LI>If we call the function in browser –&gt; error<BR /> Reason: no JWT token at all</LI><BR /> <LI>If we call the function in REST client with OAuth flow –&gt; error<BR /> Reason: JWT token available, but doesn't contain the required scope</LI><BR /> </UL><BR /> Solution: To call the function we need to assign the required role to our user<BR /> <BR /> <STRONG><SPAN style="text-decoration: underline">The Role</SPAN></STRONG><BR /> <BR /> In Cloud Foundry, authorization is controlled by means of Role Based Access Control (RBAC)<BR /> In the first step, we created an instance of XSUAA, based on a security configuration which defined a scope and a role-template.<BR /> After creating our instance of XSUAA, our role-definition has been added to the list of roles in the cockpit.<BR /> We can view it there<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/10/cockpit_roles-1.jpg" height="131" width="394" /></P><BR /> But viewing is not enough, we have to add the role to our user.<BR /> <BR /> <SPAN style="text-decoration: underline"><STRONG>Assign Role to User</STRONG></SPAN><BR /> <BR /> First, we create a new <EM>Role Collection</EM>, dedicated for your function<BR /> In the Cockpit, go to your subaccount-&gt;Security-&gt; Role Collections<BR /> <BR /> Second, we have to add the desired role to the new Role Collection<BR /> So we “edit” the new role collection and add our new role<BR /> Then press “save”<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/10/cockpit_rc.jpg" height="98" width="237" /></P><BR /> Third, we need to add our Role Collection to the Identity Provider (IDP)<BR /> Go to menu entry <EM>Trust Configuration</EM><BR /> Click on default IDP<BR /> Enter the E-Mail Address of your user<BR /> Click “show Assignments”<BR /> Then “Assign Role Collection”<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/10/cockpit_trust-1.jpg" height="189" width="403" /></P><BR /> <STRONG><U>Test the function with human user</U></STRONG><BR /> <BR /> Now that our user has the required role, we can call the function<BR /> We don’t have a user interface in our scenario, so we use a REST client<BR /> See <A href="https://blogs.sap.com/2019/04/29/sap-cloud-platform-backend-service-tutorial-13-api-called-from-external-tool/" target="_blank" rel="noopener noreferrer">here</A> for a detailed description about how to call an OAuth protected endpoint with REST client<BR /> <BR /> Short description:<BR /> 1. fetch a JWT token<BR /> 2. Use token when calling our function<BR /> <BR /> In my example, I’m using Postman which helps to do both steps in one request<BR /> To configure postman request, we need to view the service key of our xsuaa instance which we created above<BR /> To view the service key, we can use the following command (alternatively, use cockpit)<BR /> <BR /> <SPAN style="background-color: black;color: white;font-family: Courier New">cf service-key xsuaa_faas_scope xsuaa_faasscope_servicekey</SPAN><BR /> <BR /> Back in Postman, we have to configure the request as follows<BR /> <BR /> <SPAN style="font-family: Courier New">Method</SPAN>: GET<BR /> <SPAN style="font-family: Courier New">URL</SPAN>: The endpoint of our function, we get the info during deploy, or with xfsrt-cli faas project get<BR /> e.g. <SPAN style="color: #0000ff"><A href="https://...-faas.....functions.xfs.cloud.sap/prot/" target="test_blank" rel="nofollow noopener noreferrer">https://...-faas.....functions.xfs.cloud.sap/prot/</A><BR /> </SPAN>Don’t forget the slash at the end<BR /> <BR /> <SPAN style="font-family: Courier New">Authorization</SPAN>: Oauth 2.0<BR /> <SPAN style="font-family: Courier New">Access Token</SPAN>:<BR /> press "Get new Access Token"<BR /> "Get Access Token" Dialog:<BR /> <SPAN style="font-family: Courier New">Grant Type</SPAN>: Password Credentials<BR /> <SPAN style="font-family: Courier New">Access Token URL</SPAN>: we copy the “url” property from the service key and append&nbsp;&nbsp; <SPAN style="color: #0000ff">/oauth/token<BR /> </SPAN>Example: <SPAN style="color: #0000ff"><A href="https://&lt;subaccount&gt;.authentication.....hana.ondemand.com/oauth/token" target="test_blank" rel="nofollow noopener noreferrer">https://&lt;subaccount&gt;.authentication.....hana.ondemand.com/oauth/token</A><BR /> </SPAN><SPAN style="font-family: Courier New">Username</SPAN>: &lt;your cloud user&gt;<BR /> <SPAN style="font-family: Courier New">Password</SPAN>: &lt;your cloud user password&gt;<BR /> <SPAN style="font-family: Courier New">Client ID</SPAN>: copy the value of property <SPAN style="font-family: Courier New">clientid</SPAN> from service key<BR /> <SPAN style="font-family: Courier New">Client Secret</SPAN>: copy the value of property <SPAN style="font-family: Courier New">clientsecret</SPAN> from service key<BR /> <SPAN style="font-family: Courier New">Client Authentication</SPAN>: choose "Send as Basic Auth header"<BR /> <BR /> Then press “Request Token” on the dialog<BR /> After getting the token response, press “Use Token”<BR /> Then, back in the main Postman window, press “Send” to send the request to the Function endpoint<BR /> <BR /> As a result, we get our success message, which proves that the scope was included in the JWT token<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/10/postmanSuccess.jpg" height="220" width="432" /></P><BR /> Now we want to do the negative test, to check our function implementation works correctly and if the correct status code is sent<BR /> To do so, we have to remove the role from our user.<BR /> We can simply unassign the role collection in the "Trust Configuration"<BR /> Afterwards, we need to fetch a new JWT token via “Get New Access Token”<BR /> Then send the request again to call the function without scope<BR /> <BR /> The result is <SPAN style="font-family: Courier New">403</SPAN>, as coded by us, and the response message shows that the scope is not contained in the JWT token<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/10/postman403.jpg" height="72" width="433" /></P><BR /> Note:<BR /> In this scenario, we’re using only one instance of XSUAA<BR /> The function uses an instance of XSUAA to protect its endpoint<BR /> The user who calls the function, uses the same ClientID to call the function<BR /> This is OK, because we as developers of the function trust our user<BR /> In case that 2 instances of XSUAA are required, please refer to <A href="https://blogs.sap.com/2020/06/02/how-to-call-protected-app-from-external-app-as-external-user-with-scope/" target="_blank" rel="noopener noreferrer">this blog for more information</A><BR /> <BR /> &nbsp;<BR /> <H2 id="toc-hId--244622088">4.&nbsp;<STRONG>Call function in client credentials scenario</STRONG></H2><BR /> Now we want to call the protected function from an application<BR /> Again, we’re using only one instance of XSUAA.<BR /> We bind our application to the same instance which is used to protect the function<BR /> (Sure, in a future blog, we’ll describe a scenario with different XSUAA instances)<BR /> <BR /> In client credentials scenario, we may wonder: how to assign the required scope to the calling app?<BR /> We cannot assign it in the cockpit like we did for our (human) user.<BR /> To answer this question, somebody wrote <A href="https://blogs.sap.com/2020/06/02/how-to-call-protected-app-from-external-app-as-external-user-with-scope/" target="_blank" rel="noopener noreferrer">this useful blog post</A><BR /> <BR /> Our example is a bit different from above blog post, because both the function and the client app are "bound" to the same instance of XSUAA<BR /> The solution in our example:<BR /> When creating an instance of XSUAA, we defined a parameter called <SPAN style="font-family: Courier New">authorities<BR /> </SPAN>This is interesting and might be a new learning for us:<BR /> The function is attached to the XSUAA instance and the client app is bound to the same instance<BR /> As such, we would expect that the xsuaa instance (== OAuth client) trusts itself, because it is the same instance<BR /> In fact, trust is there. But the scope is not automatically there<BR /> In a client-credentials scenario, the scope must be explicitly granted, just like we assign a role to a user<BR /> To assign the scope to the client itself, no “grant” statement is required, but the <SPAN style="font-family: Courier New">authorities</SPAN> statement is necessary<BR /> This statement declares: our application wants to take the scope<BR /> <PRE class="language-javascript"><CODE>"authorities":["$XSAPPNAME.scopeforfunction"]</CODE></PRE><BR /> <STRONG>&nbsp;</STRONG><SPAN style="text-decoration: underline"><STRONG>Create Client app</STRONG></SPAN><BR /> <BR /> The only intention of our app is to call the function – and to send a JWT token which contains the required scope<BR /> Well... we’ve just learned how to get the required scope into the JWT token<BR /> Nothing special needs to be done in the app code<BR /> Just fetch a JWT token and then call the function<BR /> So we can skip explanations.<BR /> We can go ahead and copy the code from the <A href="#samples" target="_blank" rel="nofollow noopener noreferrer">Appendix</A><BR /> <BR /> Note:<BR /> Don’t forget to replace the <SPAN style="font-family: Courier New">FUNC_HOST</SPAN> URL with the URL of your function<BR /> <BR /> Note:<BR /> You might need to change the app name in the <SPAN style="font-family: Courier New">manifest.yml</SPAN><BR /> <BR /> Then deploy the clientapp with <SPAN style="background-color: black;color: white;font-family: Courier New">cf push<BR /> </SPAN>Finally, invoke the endpoint of our function caller app and hope to get a success message<BR /> <SPAN style="color: #0000ff"><A href="http://functioncallerapp.cfapps.sap.hana.ondemand.com/call" target="test_blank" rel="nofollow noopener noreferrer">http://functioncallerapp.cfapps.sap.hana.ondemand.com/call</A></SPAN><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/10/clientappSuccess.jpg" height="55" width="435" /></P><BR /> To test the negative scenario, we have to remove the <SPAN style="font-family: Courier New">authorities</SPAN> statement from our <SPAN style="font-family: Courier New">xs-security_faas_scope.json</SPAN> file and then execute an update-service command in Cloud Foundry<BR /> <BR /> <SPAN style="background-color: black;color: white;font-family: Courier New">cf&nbsp;update-service&nbsp;xsuaa_faas_scope&nbsp;-c&nbsp;xs-security_faas_scope.json</SPAN><BR /> <BR /> Note:<BR /> Instead of deleting the “authorities” statement, we can invalidate it by changing the name of the scope to anything non-existing<BR /> e.g.<BR /> <SPAN style="font-family: Courier New">"authorities":["$XSAPPNAME.scopeforfunctionXX"]</SPAN><BR /> <BR /> In fact, after running update-service, we can invoke our endpoint again and we get the expected error message:<BR /> It says that the function responded with 403, which was expected<BR /> <H2 id="toc-hId--441135593">Summary</H2><BR /> We’ve learned that the FaaS runtime uses XSUAA for token validation, there’s no automatic check of available scopes<BR /> To manually check the available scopes, we can access the decoded JW T token<BR /> We need to access the scope prefix from xsuaa service key<BR /> In client-credentials scenario, we need to use the <SPAN style="font-family: Courier New">authorities</SPAN> statement to assign the scope to ourselves<BR /> <H2 id="quickguide" id="toc-hId--637649098">Quick Guide</H2><BR /> Few Code snippets<BR /> <PRE class="language-javascript"><CODE>// access registered xsuaa service in order to get the value of variable $XSAPPNAME<BR /> const xsuaaCredentials = await context.getServiceCredentialsJSON('xsuaa-with-scope')<BR /> const requiredScope = xsuaaCredentials.xsappname + '.scopeforfunction'<BR /> <BR /> // the decoded JWT token<BR /> const jwtTokenDecoded = event.decodeJsonWebToken()<BR /> <BR /> // the raw JWT token<BR /> const jwtTokenRaw = event.auth.credentials<BR /> </CODE></PRE><BR /> <H2 id="toc-hId--834162603">Links</H2><BR /> <UL><BR /> <LI><a href="https://community.sap.com/t5/user/viewprofilepage/user-id/1387241">@Sap</a>/xssec <A href="https://www.npmjs.com/package/@sap/xssec" target="_blank" rel="noopener noreferrer nofollow">documentation</A></LI><BR /> <LI>Call OAuth protected service from <A href="https://blogs.sap.com/2019/04/29/sap-cloud-platform-backend-service-tutorial-13-api-called-from-external-tool/" target="_blank" rel="noopener noreferrer">REST client</A></LI><BR /> <LI>OAuth <A href="https://blogs.sap.com/2019/05/06/sap-cloud-platform-backend-service-tutorial-14-about-oauth-mechanism/" target="_blank" rel="noopener noreferrer">Intro</A></LI><BR /> <LI>JWT Token <A href="https://blogs.sap.com/2020/09/03/outdated-sap_jwt_trust_acl/" target="_blank" rel="noopener noreferrer">details</A></LI><BR /> <LI>Interesting article: <A href="https://blogs.sap.com/2020/10/21/how-to-add-custom-properties-to-jwt-token/" target="_blank" rel="noopener noreferrer">how to add property to JWT</A></LI><BR /> <LI>Overview of <A href="https://blogs.sap.com/2020/06/17/writing-functions-as-a-service-overview-of-blogs/" target="_blank" rel="noopener noreferrer">FaaS blog posts</A></LI><BR /> </UL><BR /> <H2 id="commands" id="toc-hId--683421751">Appendix 1: Console Commands</H2><BR /> <UL><BR /> <LI><SPAN style="background-color: black;color: white;font-family: Courier New">cf cs xsuaa application xsuaa_faas_scope -c xs-security_faas_scope.json</SPAN></LI><BR /> <LI><SPAN style="background-color: black;color: white;font-family: Courier New">cf&nbsp;csk&nbsp;xsuaa_faas_scope&nbsp;xsuaa_faasscope_servicekey</SPAN><BR /> <SPAN style="background-color: black;color: white;font-family: Courier New">cf service-key xsuaa_client xsuaa_client_servicekey&nbsp;</SPAN></LI><BR /> <LI><SPAN style="background-color: black;color: white;font-family: Courier New">cf update-service xsuaa_faas_scope -c xs-security_faas_scope.json</SPAN></LI><BR /> <LI><SPAN style="background-color: black;color: white;font-family: Courier New">xfsrt-cli login</SPAN></LI><BR /> <LI><SPAN style="background-color: black;color: white;font-family: Courier New">xfsrt-cli faas service register</SPAN></LI><BR /> <LI><SPAN style="background-color: black;color: white;font-family: Courier New">xfsrt-cli faas project deploy</SPAN></LI><BR /> <LI><SPAN style="background-color: black;color: white;font-family: Courier New">xfsrt-cli faas project get</SPAN></LI><BR /> <LI><SPAN style="background-color: black;color: white;font-family: Courier New">xfsrt-cli faas project logs</SPAN></LI><BR /> </UL><BR /> <H2 id="samples" id="toc-hId--879935256">Appendix 2: All sample project files</H2><BR /> For your convenience, I'm pasting the structure of my example project.<BR /> Folder names can be changed<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2020/10/projectStructure.jpg" height="191" width="185" /></P><BR /> <BR /> <H3 id="toc-hId--1369851768">Protected Function</H3><BR /> These are the files required for the function<BR /> They are located in the function project folder, with "lib" subfolder<BR /> <BR /> <SPAN style="text-decoration: underline;font-family: Courier New">xs-security_faas_scope.json</SPAN><BR /> <PRE class="language-javascript"><CODE>{<BR /> "xsappname" : "xsappforfaaswithscope",<BR /> "tenant-mode" : "dedicated",<BR /> "scopes": [<BR /> {<BR /> "name": "$XSAPPNAME.scopeforfunction",<BR /> "description": "Scope required for accessing function"<BR /> }<BR /> ],<BR /> "role-templates": [ { <BR /> "name" : "FunctionRoleTemplate", <BR /> "description" : "Role for serverless function", <BR /> "default-role-name" : "RoleForFunction",<BR /> "scope-references" : ["$XSAPPNAME.scopeforfunction"]<BR /> }],<BR /> "authorities":["$XSAPPNAME.scopeforfunction"]<BR /> }<BR /> </CODE></PRE><BR /> <SPAN style="text-decoration: underline;font-family: Courier New">faas.json</SPAN><BR /> <PRE class="language-javascript"><CODE>{<BR /> "project": "protectedwithscope",<BR /> "version": "0.0.1",<BR /> "runtime": "nodejs10",<BR /> "library": "./lib",<BR /> "functions": {<BR /> "prot-func-with-scope": {<BR /> "module": "functionImpl.js",<BR /> "httpApi": true,<BR /> "services": ["xsuaa-with-scope"]<BR /> }<BR /> },<BR /> "triggers": {<BR /> "prot": {<BR /> "type": "HTTP",<BR /> "function": "prot-func-with-scope",<BR /> "auth": {<BR /> "type": "xsuaa",<BR /> "service": "xsuaa-with-scope"<BR /> } <BR /> }<BR /> },<BR /> "services": {<BR /> "xsuaa-with-scope": {<BR /> "type": "xsuaa",<BR /> "instance": "d8819eda-41e6-40b0-9286-0afa1a59d12c",<BR /> "key": "xsuaa_faasscope_servicekey" <BR /> }<BR /> }<BR /> } </CODE></PRE><BR /> <SPAN style="text-decoration: underline;font-family: Courier New">package.json</SPAN><BR /> <PRE class="language-javascript"><CODE>{}</CODE></PRE><BR /> <SPAN style="text-decoration: underline;font-family: Courier New">functionImpl.js</SPAN><BR /> <PRE class="language-javascript"><CODE>module.exports = async function (event, context) { <BR /> // access registered xsuaa service in order to get the value of variable $XSAPPNAME<BR /> const xsuaaCredentials = await context.getServiceCredentialsJSON('xsuaa-with-scope')<BR /> const requiredScope = xsuaaCredentials.xsappname + '.scopeforfunction'<BR /> <BR /> // read the JWT token and check required scope<BR /> const jwtToken = event.decodeJsonWebToken()<BR /> const jwtScopes = jwtToken.payload.scope<BR /> if(! jwtScopes.includes(requiredScope)){<BR /> // HTTP API required for configuring response<BR /> const response = event.http.response // must be enabled in faas.json<BR /> response.writeHead(403, {<BR /> 'Content-Type': 'text/plain'<BR /> });<BR /> response.write(`Unauthorized: required scope '${requiredScope}' not found in JWT. Availbale scopes: '${jwtScopes}' ;-(`);<BR /> response.end();<BR /> } else{<BR /> return `Reached protected function. Scope check successful: required scope '${requiredScope}' found in JWT. Availbale scopes: '${jwtScopes}'`<BR /> }<BR /> } <BR /> </CODE></PRE><BR /> &nbsp;<BR /> <H3 id="toc-hId--1566365273">Function Caller Client App</H3><BR /> These are the files required for a little node.js app which calls the protected function<BR /> Make sure to adapt the URL of the function in the application code<BR /> <BR /> <SPAN style="text-decoration: underline;font-family: Courier New">manifest.yml</SPAN><BR /> <BR /> The application is bound to the same instance of XSUAA which we registered in FaaS<BR /> <PRE class="language-javascript"><CODE>---<BR /> applications:<BR /> - name: functioncallerapp<BR /> memory: 128M<BR /> buildpacks:<BR /> - nodejs_buildpack<BR /> services:<BR /> - xsuaa_faas_scope</CODE></PRE><BR /> <SPAN style="text-decoration: underline;font-family: Courier New">server.js</SPAN><BR /> <PRE class="language-javascript"><CODE>const express = require('express')<BR /> const app = express()<BR /> const https = require('https');<BR /> <BR /> const VCAP_SERVICES = JSON.parse(process.env.VCAP_SERVICES)<BR /> const CREDENTIALS = VCAP_SERVICES.xsuaa[0].credentials<BR /> //oauth<BR /> const CLIENTID = CREDENTIALS.clientid; <BR /> const SECRET = CREDENTIALS.clientsecret;<BR /> const OAUTH_HOST = CREDENTIALS.url;<BR /> <BR /> const FUNC_HOST = 'https://abcd1234-...-...-faas-...-functions.xfs.cloud.sap' // adapt URL<BR /> const FUNC_TRIGGER = 'prot'<BR /> <BR /> <BR /> app.get('/call', function(req, res){ <BR /> // call function endpoint <BR /> doCallEndpoint(FUNC_HOST, FUNC_TRIGGER, OAUTH_HOST, CLIENTID, SECRET)<BR /> .then((response)=&gt;{<BR /> res.status(202).send('Successfully called remote endpoint. Function response: ' + response);<BR /> }).catch((error)=&gt;{<BR /> res.status(500).send(`Error while calling remote endpoint: ${error} `);<BR /> })<BR /> });<BR /> <BR /> <BR /> // helper method to call the endpoint<BR /> const doCallEndpoint = function(host, endpoint, token_uri, client_id, client_secret){<BR /> return new Promise((resolve, reject) =&gt; {<BR /> return fetchJwtToken(token_uri, client_id, client_secret)<BR /> .then((jwtToken) =&gt; {<BR /> const options = {<BR /> host: host.replace('https://', ''),<BR /> path: `/${endpoint}/`,<BR /> method: 'GET',<BR /> headers: {<BR /> Authorization: 'Bearer ' + jwtToken<BR /> }<BR /> }<BR /> <BR /> const req = https.request(options, (res) =&gt; {<BR /> res.setEncoding('utf8')<BR /> const status = res.statusCode <BR /> const statusMessage = res.statusMessage <BR /> let response = ''<BR /> res.on('data', chunk =&gt; {<BR /> response += chunk<BR /> })<BR /> <BR /> res.on('end', () =&gt; {<BR /> if (status !== 200 &amp;&amp; status !== 201) {<BR /> return reject(new Error(`Failed to call function. Message: ${status} - ${statusMessage} - ${response}`))<BR /> }<BR /> resolve(response)<BR /> })<BR /> <BR /> });<BR /> <BR /> req.on('error', (error) =&gt; {<BR /> return reject({error: error})<BR /> });<BR /> <BR /> req.write('done')<BR /> req.end() <BR /> })<BR /> .catch((error) =&gt; {<BR /> reject(error)<BR /> })<BR /> })<BR /> }<BR /> <BR /> // jwt token required for calling REST api<BR /> const fetchJwtToken = function(token_uri, client_id, client_secret) {<BR /> return new Promise ((resolve, reject) =&gt; {<BR /> const options = {<BR /> host: token_uri.replace('https://', ''),<BR /> path: '/oauth/token?grant_type=client_credentials&amp;response_type=token',<BR /> // path: '?grant_type=client_credentials&amp;response_type=token',<BR /> headers: {<BR /> Authorization: "Basic " + Buffer.from(client_id + ':' + client_secret).toString("base64")<BR /> }<BR /> }<BR /> <BR /> https.get(options, res =&gt; {<BR /> res.setEncoding('utf8')<BR /> let response = ''<BR /> res.on('data', chunk =&gt; {<BR /> response += chunk<BR /> })<BR /> <BR /> res.on('end', () =&gt; {<BR /> try {<BR /> const jwtToken = JSON.parse(response).access_token <BR /> resolve(jwtToken)<BR /> } catch (error) {<BR /> return reject(new Error('Error while fetching JWT token')) <BR /> }<BR /> })<BR /> })<BR /> .on("error", (error) =&gt; {<BR /> return reject({error: error})<BR /> });<BR /> }) <BR /> }<BR /> <BR /> // Start server<BR /> app.listen(process.env.PORT || 8080, ()=&gt;{})<BR /> <BR /> </CODE></PRE><BR /> <SPAN style="text-decoration: underline;font-family: Courier New">package.json</SPAN><BR /> <PRE class="language-javascript"><CODE>{<BR /> "dependencies": {<BR /> "express": "^4.16.3"<BR /> }<BR /> }<BR /> </CODE></PRE><BR /> &nbsp;<BR /> <H2 id="samplewithlib" id="toc-hId--1469475771">Appendix 3: Sample code using <a href="https://community.sap.com/t5/user/viewprofilepage/user-id/1387241">@Sap</a>/xssec</H2><BR /> <SPAN style="text-decoration: underline;font-family: Courier New">package.json</SPAN><BR /> <PRE class="language-javascript"><CODE>{<BR /> "dependencies": {<BR /> "@sap/xssec": "latest"<BR /> }<BR /> }<BR /> </CODE></PRE><BR /> <SPAN style="text-decoration: underline;font-family: Courier New">functionImpl.js</SPAN><BR /> <PRE class="language-javascript"><CODE>const xssec = require('@sap/xssec')<BR /> const util = require('util');<BR /> const createSecurityContext = util.promisify(xssec.createSecurityContext);<BR /> <BR /> module.exports = async function (event, context) { <BR /> // access registered xsuaa service in order to get the value of variable $XSAPPNAME<BR /> const xsuaaCredentials = await context.getServiceCredentialsJSON('xsuaa-with-scope')<BR /> const requiredScope = xsuaaCredentials.xsappname + '.scopeforfunction'<BR /> <BR /> const jwtTokenRaw = event.auth.credentials<BR /> const securityContext = await createSecurityContext(jwtTokenRaw, xsuaaCredentials)<BR /> const jwtScopes = securityContext.getTokenInfo().getPayload().scope<BR /> <BR /> if(! securityContext.checkScope(requiredScope)){<BR /> // HTTP API required for configuring response<BR /> const response = event.http.response // must be enabled in faas.json<BR /> response.writeHead(403, {<BR /> 'Content-Type': 'text/plain'<BR /> });<BR /> response.write(`Unauthorized: required scope '${requiredScope}' not found in JWT. Availbale scopes: '${jwtScopes}'`);<BR /> response.end();<BR /> } else{<BR /> return `Reached protected function. Scope check successful: required scope found in JWT. All availbale scopes: '${jwtScopes}'`<BR /> }<BR /> }</CODE></PRE><BR /> &nbsp; 2020-10-29T15:06:37+01:00 https://community.sap.com/t5/technology-blogs-by-members/6-months-using-serverless-faas-environment-on-btp-my-review/ba-p/13502766 6 Months using serverless (FaaS) environment on BTP - My Review 2021-03-30T14:01:58+02:00 drvup https://community.sap.com/t5/user/viewprofilepage/user-id/747 <H2 id="toc-hId-957434722">Introduction</H2><BR /> I am a big fan trying to keep things as simple as possible. This is sometimes fighting against my philosophy as a developer but having the history and experience of doing operations in my mind, I was happy all the time if I did not have to read 5.000 lines of code before understanding what's going on. Moving from the onPremise world to the Cloud and therefore to BTP, it was my personal aim to implement in a microservice approach as much as possible.<BR /> <BR /> Therefore I was quite happy as I saw the announcements about the serverless service on BTP (previously known as 'Extension Center'), giving me the opportunity to have an easy entry to the world of Function-as-a-Service (FaaS) on the BTP.<BR /> <BR /> This blog post will provide my experience I did collect the last 6 months using serverless service on the Cloud Foundry environment, provide you some use-case ideas and background knowledge, but also show up the nuts and bolts of this service.<BR /> <BR /> &nbsp;<BR /> <H2 id="toc-hId-760921217">What's serverless-service and FaaS?</H2><BR /> Function-as-a-Service is providing you a function as a service. Yes, it's the easiest way to explain it. The combination of the runtime and environment is missing in this description. So let's say it's a function we do deploy to a kubernetes cluster (K8s) who is running this function and waiting for someone who is going to call / consume this function. We do only pay per usage. So if nothing is happening and no one is using it, we do not need to pay for the container.<BR /> <BLOCKQUOTE>The function is sleeping in a fluffy cloudy container and only when it is needed, it wakes up and does something<BR /> And the good news:<BR /> A sleeping function doesn’t cause cost<BR /> <BR /> # <SPAN class="mention-scrubbed">carlos.roggan</SPAN></BLOCKQUOTE><BR /> Check out this <A href="https://blogs.sap.com/2020/06/17/writing-functions-as-a-service-overview-of-blogs/" target="_blank" rel="noopener noreferrer">wonderful blog post series</A> about more background details and your first hands-on with the serverless services. Thx for this good job, Carlos.<BR /> <BR /> &nbsp;<BR /> <H2 id="toc-hId-564407712">How is it working?</H2><BR /> In a nutshell: You're setting up your own nodeJS application,<A href="https://blogs.sap.com/2020/06/17/writing-functions-as-a-service-1.1-first-function-using-extension-center/" target="_blank" rel="noopener noreferrer"> define a trigger</A> and additional configs in a separate config file (faas.json) and you're ready to deploy to the K8s instance. Therefore you're going to use a specific <A href="https://blogs.sap.com/2020/06/17/writing-functions-as-a-service-0.1-preparation/" target="_blank" rel="noopener noreferrer">xfsrt-cli</A> and you'll get the defined trigger endpoint back from the cli. Otherwise you can use the frontend to check the endpoint link, define secrets and have a look into the log.<BR /> <BR /> &nbsp;<BR /> <H2 id="toc-hId-367894207">My use cases</H2><BR /> My clients project is going to do a digital transformation for their R/3 landscape to a S/4 HANA Public Cloud solution. A lot of process-gaps or custom UIs were implemented on the BTP to fulfill the transformation. For environment specific operations I searched for an easy approach to host microservices and get rid of containers around it, I need to document and to take care of. One important point you need to think about are runtime-costs (check Pro and Cons chapter).<BR /> <H3 id="toc-hId-300463421">Use case FaaS001 - Set up IAS user</H3><BR /> On BTP we're using a lot of different services and I've sometimes the feeling that I am belonging to the glamour team of "first-customers" with some of them. Therefore we often do open OSS Incidents belonging to BTP services. Most of the time, SAP is requesting access to the cockpit / service-instance. I implemented a FaaS microservice to provide the ability to create a new IAS user on the IAS tenant, following a naming convention we defined first and assigning required rules.<BR /> <BR /> <IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2021/03/blog001.png" /><BR /> <BR /> The FaaS001 is the actual endpoint for some kind of 'user self service' where a developer can request such a 'OSS IAS User' with the required IAS-Groups.<BR /> <BR /> This approach is required as the IAS-SCIM-API (connected through a destination-service-instance) is to powerful to provide it directly to a UI5 application and the naming convention and security aspects (like a random password with numbers, special characters and so on) are easier to maintain and control.<BR /> <H3 id="toc-hId-103949916">Use case FaaS002 - Deactivate IAS user</H3><BR /> After generating users for the OSS support, we also want to check on these users and deactivate the users after 7 days automatically. So the next FaaS I did implement is doing exactly that. The endpoint published by FaaS002 is getting called by a Job Scheduler service instance.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2021/03/blog003.png" /></P><BR /> <EM><STRONG>Developer pro-tip:</STRONG></EM><BR /> <BR /> Both FaaS microservices communicate with me (and the authority team) via the Alert Notification Service. I'll get notifications for everything that is happening immediately. Something similar I also did with APIM, check <A href="https://blogs.sap.com/2021/01/29/sap-api-management-support-and-debugging-opportunities/" target="_blank" rel="noopener noreferrer">here</A>. So this message I do receive via Google Chat every morning at 00:59 (job planned time).<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2021/03/blog004.png" /></P><BR /> <BR /> <H3 id="toc-hId--92563589">Use case FaaS003 - Workflow checker</H3><BR /> We're using a lot of workflow instances on our BTP. Unfortunately sometimes they crash if the developer did not check his code or the endpoint isn't there at runtime. I want to inform us developers about these circumstances so we can check the workflow instances and restart it, if necessary.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2021/03/blog005.png" /></P><BR /> The Job Scheduler is calling every 20 minutes this microservice, who is using the <A href="https://api.sap.com/api/SAP_CP_Workflow_CF/resource" target="_blank" rel="noopener noreferrer">workflow API</A> to fetch workflow-instances in state "FAILURE". For every entry FaaS is sending a message via the Alert Notification Service to the developer Google Chat group.<BR /> <BR /> &nbsp;<BR /> <H2 id="toc-hId--418159813">Pro and Cons I did discover</H2><BR /> <H3 id="toc-hId--485590599">PRO</H3><BR /> <UL><BR /> <LI>Runtime-Costs: Instead of paying memory for deployed containers on the Cloud Foundry environment, we do only pay per usage of this microservice. This could be useful for functions getting called twice a day by a Job-Scheduler service but maybe expensive for 'wbs element checker invoked by a time-recording ui5 application' within 25.000 calls a day.</LI><BR /> <LI>There is "more less to care about". I mean, yes, deploying to Cloud Foundry is already easy and my responsibility outside the container is already low. But here it's just about 1 service instance. That's it. More less is impossible (!?).</LI><BR /> <LI>Easy handling. I like the xfsrt-cli and the approach, how to deploy FaaS projects to the serverless instance. We also managed to do this via an Azure DevOps pipeline within some minutes, so it's deploying now automatically.</LI><BR /> <LI>It's stable. Within the last 6 months, there were no service-interruptions, key changes or anything else we had to deal with (beside the renaming)</LI><BR /> </UL><BR /> <H3 id="toc-hId--682104104">CON</H3><BR /> <UL><BR /> <LI>Per serverless instance, there are only 5 projects allowed. Each project can contain up to 5 functions, so we can have 5x5 = 25 functions up and running on one serverless instance</LI><BR /> <LI>The maximum number of <A href="https://help.sap.com/viewer/bf7b2ff68518427c85b30ac3184ad215/Cloud/en-US/fdcf3f05bf1e408682ddb87b17522552.html" target="_blank" rel="noopener noreferrer">service instances allowed</A> for a subaccount is 1. So 25 is the final sum of possible functions on our subaccount. Why, SAP? Are you afraid of earning money with this service???</LI><BR /> <LI><A href="https://help.sap.com/viewer/bf7b2ff68518427c85b30ac3184ad215/Cloud/en-US/fdcf3f05bf1e408682ddb87b17522552.html" target="_blank" rel="noopener noreferrer">Limitation</A> continues; the maximum size of source code per project is 50mb. This sounds enough, but as soon as you're starting using modules from npm like suggested, this 50mb can be achieved very fast!</LI><BR /> <LI>Bindings to service instances (beside XSUAA) isn't supported. You'll need to add your secrets (e.g. for your destination service instance) to your faas-secrets.</LI><BR /> <LI>Logs. The logs are visible to you via the Extension-Center-UI and the xfsrt-cli. Fine! But there is no way to forward these log entries to Kibana / Cloud Foundry application logging service.</LI><BR /> <LI>No HANA client usage possible. We wanted to connect a FaaS with an AMQP trigger, related to Enterprise Messaging Service, and generate something on a HANA database. Unfortunately, beside the missing bindings, the library would be too big to use it here.</LI><BR /> <LI>Updates. I am sitting on the customer site, but it feels like there is some kind of silence on the "<A href="https://help.sap.com/viewer/bf7b2ff68518427c85b30ac3184ad215/Cloud/en-US/e27575933e6c4f12ba34d59e990c8907.html" target="_blank" rel="noopener noreferrer">What's New Section</A>" for serverless. Does this have future? Do I smell a new 'Deprecated soon' flag coming up?</LI><BR /> </UL><BR /> <H2 id="toc-hId--660445971"></H2><BR /> <H2 id="toc-hId--856959476">Recommendation</H2><BR /> Serverless is a nice service and opportunity on the BTP, providing microservice capabilities as easy as possible. Saving money included. But as soon as your requirements are involving something like a HANA database connection, you're out. So try to know your requirements first (I know, this is tough in times where we do agile-requirements) and set yourself a limit of coding-lines and complexity for a FaaS. Think about the usage / hits for your endpoint. Will this getting called twice a day? 1000 times? 500k times?<BR /> <BR /> Size, complexity, hits per day. These are the 3 dimensions you need to know before starting with serverless (from my point of view).<BR /> <BR /> <EM>I'd like to tell you my limits I set for my decision matrix:</EM><BR /> <BR /> <EM>Size</EM>: 500 lines of code (of course, 50mb with all modules :D)<BR /> <BR /> <EM>Complexity</EM>: maximum 2/5 (that means for me, doing some request-promise calls, checking and formatting, transformation of in/out objects)<BR /> <BR /> <EM>Hits per day</EM>: 5000 (equals 0.1 capacity unit)<BR /> <BR /> Check the <A href="https://www.sap.com/products/business-technology-platform/estimator-tool.html" target="_blank" rel="noopener noreferrer">Cloud estimator</A> tool to see, what 1 capacity unit does cost for you.<BR /> <BR /> &nbsp;<BR /> <H2 id="toc-hId--1053472981">Conclusion</H2><BR /> Serverless is the great entrance to the world of kubernetes and serverless hosted apps. It's not the solution for every application but it's an easy approach for nodeJS microservices and it's worth it, spending some time and energy into it. Thinking about productive scenarios and the real usage in customer projects, it completely depends on the use cases and the size. These kind of limitations existing for this service are following the feeling, that the service could be deprecated soon and the successor will be <A href="https://blogs.sap.com/2020/05/12/get-a-fully-managed-runtime-based-on-kyma-and-kubernetes/" target="_blank" rel="noopener noreferrer">Kyma</A>.<BR /> <BR /> &nbsp;<BR /> <BR /> <EM>All screenshots and pictures made, designed and captured by myself.</EM> 2021-03-30T14:01:58+02:00 https://community.sap.com/t5/enterprise-resource-planning-blogs-by-members/practical-guide-to-clean-core-custom-development-for-s4-hana/ba-p/13520293 Practical Guide to Clean Core Custom development for S4 HANA 2021-06-04T14:16:11+02:00 former_member186078 https://community.sap.com/t5/user/viewprofilepage/user-id/186078 <H1 id="toc-hId-830134748"><A name="_Toc61269740" target="_blank"></A><STRONG><U>Objective</U></STRONG></H1><BR /> Objective of this blog is to help understand the need for buzz word "Clean Core", how to approach it and review the technical options available.<BR /> <H1 id="toc-hId-633621243"><A name="_Toc61269740" target="_blank"></A><STRONG><U>Why CLEAN CORE?</U></STRONG></H1><BR /> &nbsp;<BR /> <BR /> In this digital world, organizations have many challenges for a sustainable growth with heavy competition, budget constraints and many others. Bi-Model IT practice helped some of them to pivot their business model and enrich even during COVID times. SAP is a vast ERP solution available with many industry specific modules. In addition to the out-of-the-box standard processes available, many customers have developed their own secret sauce by building custom objects inside the system with ABAP development. So, with the Brownfield projects, where Customers are planning to migrate from ECC to S4 HANA, there are many challenges to overcome from the Business value perspective as well from Technical. Some of them are like their custom code is tightly coupled up with standard SAP, increased complexity with continuous changes to the solutions, maintainability, extensibility, and user friendliness. In addition, it is important that IT executives and Business Leaders think about the long-term strategy, rather than considering a system upgrade. To overcome the custom code mess, the buzz word CLEAN CORE, heard several times in many conferences and meetings will help address the pain points.<BR /> <BR /> &nbsp;<BR /> <BR /> CLEAN CORE is nothing but decoupling and implementing the custom code secret sauce solution with minimal dependencies with S4/ECC solution.&nbsp; It gives opportunity to simplify the SAP upgrade processes in future, reduces upgrade timelines, enables easier extensibility, simplifies maintainability and deployment process following the best practices. In addition, gives a new opportunity for the customers to re-evaluate and re-think about the existing process like:<BR /> <UL><BR /> <LI>Whether it can sustain for the existing needs and solve business pain points</LI><BR /> <LI>Can this process provide us the flexibility to operate in the modern digital economy?</LI><BR /> <LI>Can any part of the process be replaced by Software-as-a-service products?</LI><BR /> <LI>What additional benefits could be gained if we open the doors to new technologies like AI, Machine Learning?</LI><BR /> <LI>Where would you like to see your organization 10 years from now?</LI><BR /> </UL><BR /> &nbsp;<BR /> <H1 id="toc-hId-437107738"><A name="_Toc61269741" target="_blank"></A><STRONG><U>CLEAN CORE methodology</U></STRONG></H1><BR /> &nbsp;<BR /> <BR /> Achieving pure CLEAN CORE is a hard challenge for any enterprise which has many custom-code enabled business processes. The objective of this blogs helps to brainstorm different aspects and setup foundation with different methodologies that are potentially available.<BR /> <UL><BR /> <LI>Define Drivers</LI><BR /> <LI>Analyze current state</LI><BR /> <LI>Identify suitable implementation options</LI><BR /> <LI>Define roadmap</LI><BR /> </UL><BR /> We will discuss about these steps in detail in further sections of the blog<BR /> <H2 id="toc-hId-369676952"><A name="_Toc61269742" target="_blank"></A><STRONG>Define Drivers</STRONG></H2><BR /> Customer priority is the biggest driver behind the scenes for enabling the clean core. Identifying customer priorities is the first step which kicks off the discussion between multiple user personas/actors like IT Executives, Architects, Business users and developers.&nbsp; We could broadly classify the priorities into 6 groups.<BR /> <BR /> &nbsp;<BR /> <OL><BR /> <LI>Cost of ownership<BR /> <OL><BR /> <LI>Licensing costs</LI><BR /> <LI>Hardware costs</LI><BR /> <LI>Scalability</LI><BR /> </OL><BR /> </LI><BR /> <LI>Cost of maintenance<BR /> <OL><BR /> <LI>Defect leakage</LI><BR /> <LI>Separate support team for issues, SLO, too many issues</LI><BR /> <LI>Upgrades</LI><BR /> </OL><BR /> </LI><BR /> <LI>Architecture Goals<BR /> <OL><BR /> <LI>Need to break down monoliths into microservice architecture</LI><BR /> <LI>CI/CD pipeline need to be implemented</LI><BR /> <LI>Alignment with AOM model for continuous delivery of new features</LI><BR /> <LI>S/4 HANA simplification</LI><BR /> </OL><BR /> </LI><BR /> <LI>Business Needs<BR /> <OL><BR /> <LI>Business pain points</LI><BR /> <LI>UX issues</LI><BR /> <LI>Technology issues like faster response time/access</LI><BR /> <LI>Insufficient or missing functionality in our current process</LI><BR /> </OL><BR /> </LI><BR /> <LI>Team needs<BR /> <OL><BR /> <LI>Current team’s skill set does not align</LI><BR /> <LI>Product too big for team to maintain</LI><BR /> <LI>Team should be able to maintain all aspects of the solution</LI><BR /> </OL><BR /> </LI><BR /> <LI>Timeline<BR /> <OL><BR /> <LI>Timeline restrictions for continuous delivery</LI><BR /> <LI>S/4 HANA upgrade timeline alignment - there might be couple of years in your roadmap to get into S/4</LI><BR /> </OL><BR /> </LI><BR /> </OL><BR /> Once the sequence of the priority for this initiative is identified, it sets a path to think about the implementation strategies and brainstorm about technology options available.<BR /> <H2 id="toc-hId-173163447">&nbsp;<A name="_Toc61269743" target="_blank"></A><STRONG>Analyze Current State</STRONG></H2><BR /> It is very important to understand end-to-end current business process and its touch points. Gather as much information as you can about the custom code and its integration touch points with standard SAP process as well as external systems/business process. Understand the current usage of the objects; we might have 100's of custom objects developed, but after scanning through we might have realized only 10 programs/tables are very frequently used in production while the rest of them infrequently used. Understand more about type of usage as well, like whether it used as an API by external system or executed as a batch process or a user initiating the process, volume of data, frequency of changes to the program/process, etc. All this information is very useful in further process steps.<BR /> <BR /> &nbsp;<BR /> <H2 id="toc-hId--23350058"><A name="_Toc61269744" target="_blank"></A><STRONG>Identify Suitable Implementation options</STRONG></H2><BR /> We would not want to discuss about whether its ASAP methodology, AGILE Practice or any other. Instead, we would like to mention what strategies could be adopted and what technology options are available to deal with a CLEAN CORE project.<BR /> <BR /> &nbsp;<BR /> <BR /> &nbsp;<BR /> <H3 id="toc-hId--90780844"><A name="_Toc61269745" target="_blank"></A><STRONG>CLEAN CORE implementation strategies</STRONG></H3><BR /> &nbsp;<BR /> <BR /> We could summarize the strategies available to achieve CLEAN CORE goal based on the state of the existing custom code on how it is developed.<BR /> <BR /> &nbsp;<BR /> <BR /> <EM><U>Lift and Shift</U></EM><BR /> <BR /> This is the best strategy to adopt if the current custom code is already defined in a good shape. It requires minimal migration effort to move to target architecture and boom, the code starts workings.<BR /> <BR /> &nbsp;<BR /> <BR /> <EM><U>Improve and Move</U></EM><BR /> <BR /> In this strategy, we improve the current code base and make it isolated by defining clear boundaries. Get it ready for service-based architecture and migrate incrementally.<BR /> <BR /> &nbsp;<BR /> <BR /> <EM><U>Rip and Replace Incrementally</U></EM><BR /> <BR /> This is slightly different from Improve and Move strategy. Here, we redesign part of the function or a specific feature as a new microservice and replace it in the current setup. Then move on the next feature.<BR /> <BR /> &nbsp;<BR /> <BR /> <EM><U>Redesign and Replace</U></EM><BR /> <BR /> This is more about re-evaluating the existing functionality, identifying pain-points. Once done, we collect all the new features we would like, redesign feature by feature and completely replace with existing functions by the end.<BR /> <BR /> &nbsp;<BR /> <BR /> <STRONG>Common mistakes to avoid:</STRONG><BR /> <UL><BR /> <LI>Do not consider thinking about migration of one specific custom object like a report program or&nbsp; table. Instead think about the process the object is dealing with.</LI><BR /> </UL><BR /> &nbsp;<BR /> <H3 id="toc-hId--287294349"><A name="_Toc61269746" target="_blank"></A><STRONG>Technology Options/Tools</STRONG></H3><BR /> &nbsp;<BR /> <BR /> Undoubtedly there are several platforms/tools available to achieve the CLEAN CORE goal.&nbsp; After experiencing some of them, we could be broadly classify into 4 different flavors.<BR /> <BR /> &nbsp;<BR /> <OL><BR /> <LI>S/4 HANA Standard Functionality<BR /> <UL><BR /> <LI>Look whether we have out-of-the-box functionality released by SAP for any of the custom process</LI><BR /> <LI>In-app extensibility which enables creation of S/4 HANA extensions. It allows key users to create fields, business logic, CBOs, and more.</LI><BR /> <LI>Here is the quick help <A href="https://help.sap.com/viewer/77cd6a531be5454ab16ccd8bb63c183f/PROD/en-US" target="_blank" rel="noopener noreferrer">https://help.sap.com/viewer/77cd6a531be5454ab16ccd8bb63c183f/PROD/en-US</A> for all the SAP applications which supports In-app extensibility</LI><BR /> </UL><BR /> </LI><BR /> <LI>Modular Monolith<BR /> <UL><BR /> <LI>Apply simplification changes on S/4 HANA code. Simplification analysis can be identified in multiple ways based on the version of the current system like SAP_BASIS 7.52, S/4HANA 1809, etc.<BR /> <UL><BR /> <LI>Remote code analysis can be done with ABAP Test cockpit</LI><BR /> <LI>We could download the simplification database to the current system and perform analysis</LI><BR /> </UL><BR /> </LI><BR /> </UL><BR /> </LI><BR /> </OL><BR /> <UL><BR /> <LI style="list-style-type: none"><BR /> <UL><BR /> <LI>SAP Fiori Custom Code migration app available in SAP Cloud Platform ABAP environment</LI><BR /> <LI></LI><BR /> </UL><BR /> </LI><BR /> </UL><BR /> <UL><BR /> <LI style="list-style-type: none"><BR /> <UL><BR /> <LI>Isolate custom code from standard business functions, define clear boundaries</LI><BR /> <LI>Refactor code, add unit tests and integration tests</LI><BR /> <LI>Implement CI/CD pipeline for ABAP, Services and Fiori application</LI><BR /> </UL><BR /> </LI><BR /> </UL><BR /> <OL start="3"><BR /> <LI>S/4 HANA Side by side extension<BR /> <UL><BR /> <LI>Restful ABAP programming(RAP) model using ABAP on cloud platform - <A href="https://help.sap.com/viewer/923180ddb98240829d935862025004d6/Cloud/en-US/289477a81eec4d4e84c0302fb6835035.html#:~:text=The%20ABAP%20RESTful%20Application%20Programming,Environment%20or%20Application%20Server%20ABAP" target="_blank" rel="noopener noreferrer">https://help.sap.com/viewer/923180ddb98240829d935862025004d6/Cloud/en-US/289477a81eec4d4e84c0302fb6835035.html#:~:text=The%20ABAP%20RESTful%20Application%20Programming,Environment%20or%20Application%20Server%20ABAP</A>.</LI><BR /> </UL><BR /> </LI><BR /> </OL><BR /> <UL><BR /> <LI style="list-style-type: none"><BR /> <UL><BR /> <LI>Cloud Application Programming(CAP) Application model using Java/Node.JS - <A href="https://cap.cloud.sap/docs/" target="_blank" rel="nofollow noopener noreferrer">https://cap.cloud.sap/docs/</A></LI><BR /> <LI>SAP Cloud Platform services like Enterprise messaging / Extension factory, Workflows, etc. - <A href="https://www.youtube.com/watch?v=8aQt9H5Yr-Y" target="_blank" rel="nofollow noopener noreferrer">SAP Cloud Platform in the Garage Virtual Event | Event-Driven Architecture</A></LI><BR /> <LI>SAP Cloud Platform Kyma runtime service, Kubernetes framework based on containers - <A href="https://community.sap.com/media/devtoberfest/project-kyma-jamie-cawley-sap-cloud-platform-kyma-runtime-introduction" target="_blank">https://community.sap.com/media/devtoberfest/project-kyma-jamie-cawley-sap-cloud-platform-kyma-runtime-introduction</A></LI><BR /> </UL><BR /> </LI><BR /> </UL><BR /> 4. Cloud Native Microservices<BR /> <UL><BR /> <LI style="list-style-type: none"><BR /> <UL><BR /> <LI>Choice of Cloud provider and its services<BR /> <UL><BR /> <LI>AWS like SQS, SNS, ECS, EKS,</LI><BR /> <LI>Google GKE, CGP services</LI><BR /> <LI>Microsoft Azure like Azure Storage queues, logic apps, functions</LI><BR /> </UL><BR /> </LI><BR /> <LI>Cloud Independent microservice<BR /> <UL><BR /> <LI>Docker</LI><BR /> <LI>Kubernetes</LI><BR /> <LI>Service Mesh</LI><BR /> </UL><BR /> </LI><BR /> </UL><BR /> </LI><BR /> </UL><BR /> <UL><BR /> <LI style="list-style-type: none"><BR /> <UL><BR /> <LI>Language and Database based on use case and team skillset<BR /> <UL><BR /> <LI>Java</LI><BR /> <LI>Node.js</LI><BR /> <LI>Python</LI><BR /> </UL><BR /> </LI><BR /> </UL><BR /> </LI><BR /> </UL><BR /> <H2 id="toc-hId--612890573"></H2><BR /> <H2 id="toc-hId--809404078"><A name="_Toc61269747" target="_blank"></A><STRONG>Define Roadmap</STRONG></H2><BR /> &nbsp;<BR /> <BR /> By this time, we have identified our Customer priorities, have gone through the current business process, have seen different implementation strategies and available Technology options. Now, comes the important task on how to organize and lay out the roadmap for successful implementation. We could follow these simple steps:<BR /> <UL><BR /> <LI>Use most common user-friendly tool Microsoft excel and define a decision matrix table for each process.</LI><BR /> <LI>Lay down all the factors like Usage frequency, Number of users accessing the application, what could be expected growth, what type of processing (like Batch, Real time), Security, Data, Network, Implementation and maintenance costs, monitoring, UX significance, DevOps practice, Hardware requirements, monitoring capabilities, exception handling processes, etc.</LI><BR /> <LI>Setup a pointing system against each platform</LI><BR /> <LI>Discuss Pros and Cons of each</LI><BR /> <LI>Finally, pick the best choice based on drivers defined (customer priorities) and setup implementation strategy.</LI><BR /> <LI>Here is a sample matrix</LI><BR /> <LI><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2021/06/Sample-Matrix.png" /></LI><BR /> </UL><BR /> &nbsp;<BR /> <BR /> Hope you have got some insight about how to start approaching the clean core methodology by this time.&nbsp; I would like to thank my friend <a href="https://community.sap.com/t5/user/viewprofilepage/user-id/1668">@Austin</a> who helped me in writing this blog.<BR /> <BR /> &nbsp; 2021-06-04T14:16:11+02:00 https://community.sap.com/t5/technology-blogs-by-sap/how-to-extend-sap-s-4hana-business-address-services-or-any-other-sap-s/ba-p/13493350 How to Extend SAP S/4HANA Business Address Services (or any other SAP S/4HANA application) with Serverless Functions on Kyma Part-II 2021-09-23T09:07:03+02:00 former_member760197 https://community.sap.com/t5/user/viewprofilepage/user-id/760197 <P style="overflow: hidden;margin-bottom: 0px">In this blog post you will learn…</P><BR /> &nbsp;<BR /> <BR /> &nbsp;<BR /> <H3 id="toc-hId-1066225889"><STRONG>Overview:</STRONG></H3><BR /> <UL><BR /> <LI>We will learn about how we will create serverless function in Kyma Runtime and how they are deployed (i.e. how URLs are created to get which can be used to run serverless functions) .</LI><BR /> <LI>We will also learn about how to use Google APIs to get Geocodes of any inputted address .</LI><BR /> <LI>To Know what is serverless function and need of serverless function refer to<A href="https://blogs.sap.com/2021/09/21/how-to-extend-sap-s-4hana-business-address-services-or-any-other-sap-s-4hana-application-with-serverless-functions-on-kyma-part-i/" target="_blank" rel="noopener noreferrer"> previous blog post</A> of this blog series</LI><BR /> </UL><BR /> <H3 id="toc-hId-869712384"><STRONG>Prerequisites/Skills:</STRONG></H3><BR /> <OL><BR /> <LI>Access to SAP BTP Cockpit<BR /> You need access to a productive account of SAP BTP Cockpit<BR /> <EM>Note:</EM><BR /> <EM>This service is available in Trial version of SAP BTP Cockpit</EM></LI><BR /> <LI>Node.js/JavaScript<BR /> Functions are written in JavaScript for Node.js runtime.<BR /> As such, some knowledge is helpful, however, most of the tutorials can be followed without any knowledge.</LI><BR /> <LI>ABAP.</LI><BR /> <LI><BR /> <DIV>Kyma Environment Setup explained in <A title="https://blogs.sap.com/2021/09/17/how-to-extend-s-%e2%80%a6-on-kyma-part-i/" href="https://blogs.sap.com/2021/09/23/how-to-extend-sap-s-4hana-business-address-services-or-any-other-sap-s-4hana-application-with-serverless-functions-on-kyma-part-ii/" target="_blank" rel="noreferrer noopener">Part-I</A> of this Blog Series</DIV></LI><BR /> </OL><BR /> <H3 id="toc-hId-673198879"><STRONG>Implementation Steps:</STRONG></H3><BR /> After successfully setting up the Kyma Runtime Environment as described in the steps above, we now must define the Kyma Namespace. This is where all our functions will be defined. The steps below are to set up your Kyma Namespace and get started with the Kyma environment.<BR /> <BR /> 1. Open Your Subaccount in SAP BTP Cockpit.<BR /> <BR /> 2. Click on Instances and Subscription.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2021/08/p11.png" /></P><BR /> <P style="overflow: hidden;margin-bottom: 0px">3. Click on Environments.<IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2021/08/p12.png" /></P><BR /> &nbsp;<BR /> <P style="overflow: hidden;margin-bottom: 0px">4. Click on the Actions button in your Kyma environment and navigate to ‘Go to&nbsp; Dashboard’.<IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2021/08/p14.png" /></P><BR /> 5. On the Dashboard click on ‘Select Namespace’ and choose your namespace.<BR /> <BR /> &nbsp;<BR /> <H3 id="toc-hId-476685374"><STRONG>Creating Serverless Function</STRONG></H3><BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2021/08/p15.png" /></P><BR /> <BR /> <UL><BR /> <LI>Click on ‘Functions’ on left hand pane and then click on ‘Create Function’ to create a new function.</LI><BR /> <LI>Enter name of your choice and press Enter. You will see the screen shown below.</LI><BR /> <LI>There are two sections under code tab:<BR /> <UL><BR /> <LI>First section will contain our source code to call the Google API.</LI><BR /> <LI>Second section will contain dependencies (if any).<IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2021/08/p16.png" /></LI><BR /> </UL><BR /> </LI><BR /> </UL><BR /> <UL><BR /> <LI>We are now going to add code in Source section<IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2021/08/p17.png" /></LI><BR /> </UL><BR /> &nbsp;<BR /> <PRE class="language-javascript"><CODE>const https = require('https');<BR /> <BR /> const key = {Enter Your Key Here}<BR /> <BR /> const generateGeoCode = (address) =&gt; {<BR /> <BR /> let data = '';<BR /> <BR /> return new Promise((resolve,reject) =&gt; {<BR /> <BR /> https.get(`https://maps.googleapis.com/maps/api/geocode/json?address=${address}&amp;key=${key}`,<BR /> <BR /> (response)=&gt;{<BR /> <BR /> response.on('data',(chunks)=&gt;{<BR /> <BR /> data+=chunks;<BR /> <BR /> })<BR /> <BR /> response.on('end',()=&gt;<BR /> <BR /> {<BR /> <BR /> // console.log('check123',data);<BR /> <BR /> // response = data;<BR /> <BR /> // return data;<BR /> <BR /> resolve(data);<BR /> <BR /> })<BR /> <BR /> response.on('error',(error)=&gt;{<BR /> <BR /> console.log(error)<BR /> <BR /> reject(error);})<BR /> <BR /> });<BR /> <BR /> // console.log("google",response);<BR /> <BR /> })<BR /> <BR /> }<BR /> <BR /> <BR /> <BR /> <BR /> module.exports = {<BR /> <BR /> main: async function (event, context) {<BR /> <BR /> console.log('event',event.extensions.request.query.address);<BR /> <BR /> address = event.extensions.request.query.address;<BR /> <BR /> const output = await generateGeoCode(address);<BR /> <BR /> let {results} = JSON.parse(output);<BR /> <BR /> console.log('add',results[0].geometry.location.lat);<BR /> <BR /> let final = '';<BR /> <BR /> final +=`${results[0].geometry.location.lat}, ${results[0].geometry.location.lng}`<BR /> <BR /> return final;<BR /> <BR /> //console.log('f',f);<BR /> <BR /> }}<BR /> <BR /> <BR /> </CODE></PRE><BR /> In the above Picture you can see that there is a variable key that has been purposely left blank. Here you need to get your credentials from Google Cloud Platform before entering them. you can get them from <A href="https://developers.google.com/maps/documentation/geocoding/overview" target="_blank" rel="nofollow noopener noreferrer">Here</A><BR /> <BR /> &nbsp;<BR /> <OL start="4"><BR /> <LI>Here we can see that our code is dependent on HTTP module to run so we are going to put that in our dependency:</LI><BR /> </OL><BR /> <PRE class="language-javascript"><CODE>{<BR /> <BR /> "name": "geocode-api",<BR /> <BR /> "version": "1.0.0",<BR /> <BR /> "description": "geocode api to get latitude and longitude",<BR /> <BR /> "dependencies": {<BR /> <BR /> "https": "^1.0.0"<BR /> <BR /> },<BR /> <BR /> "license": "ISC"<BR /> <BR /> }</CODE></PRE><BR /> &nbsp;<BR /> <BR /> This Completes first part of our function. Now it’s time to create the URL to send request to API.<BR /> <BR /> &nbsp;<BR /> <H3 id="toc-hId-280171869"><STRONG>Creation of URL for Function to place request to API:</STRONG></H3><BR /> &nbsp;<BR /> <UL><BR /> <LI>Click on Configuration tab next to Code tab and click on ‘Expose Function’.<IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2021/08/p18.png" /></LI><BR /> </UL><BR /> &nbsp;<BR /> <UL><BR /> <LI>Enter API Rule Name and Host Name and press Enter. This will generate the URL.<IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2021/08/p19.png" /></LI><BR /> </UL><BR /> &nbsp;<BR /> <UL><BR /> <LI>You can run the URL above in your browser and see the output.<IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2021/08/p20.png" /></LI><BR /> </UL><BR /> <H3 id="toc-hId-83658364"><STRONG>Summary:</STRONG></H3><BR /> In this blog post we saw about<BR /> <UL><BR /> <LI>How to create serverless function in Kyma.</LI><BR /> <LI>How to use Google APIs to find Geocodes using address send by user.</LI><BR /> <LI>And How to deploy the serverless function and generate API URL which can be used to send get request to server.</LI><BR /> </UL><BR /> <H3 id="toc-hId--112855141"><STRONG>Next Steps:&nbsp;</STRONG></H3><BR /> We will be seeing how to<A href="https://blogs.sap.com/2021/09/27/how-to-extend-sap-s-4hana-business-address-services-or-any-other-sap-s-4hana-application-with-serverless-functions-on-kyma-part-iii/" target="_blank" rel="noopener noreferrer"> Integrate the Kyma serverless function in any SAP S/4HANA applications</A><BR /> <BR /> For any queries and doubts please comment in comment section I will be more then happy to help you, also you can follow my profile to get updated of upcoming blog posts. 2021-09-23T09:07:03+02:00 https://community.sap.com/t5/technology-blogs-by-sap/how-to-extend-sap-s-4hana-business-address-services-or-any-other-sap-s/ba-p/13509781 How to Extend SAP S/4HANA Business Address Services (or any other SAP S/4HANA application) with Serverless Functions on Kyma Part-III 2021-09-27T10:31:38+02:00 shilpi_sen06 https://community.sap.com/t5/user/viewprofilepage/user-id/762068 <STRONG>Introduction</STRONG><BR /> <BR /> This blog post explains how a Serverless Function developed in Kyma Runtime can be consumed in the SAP S/4HANA system for the extensibility of SAP S/4HANA applications. Specifically, this blog post covers the extensibility of Business Address Services and is in continuation of Blog Series of the same title(mentioned under Prerequisites).<BR /> <BR /> <STRONG>Prerequisites/Skills</STRONG><BR /> <OL><BR /> <LI>ABAP</LI><BR /> <LI>Kyma Environment Setup explained in <A href="https://blogs.sap.com/2021/09/21/how-to-extend-sap-s-4hana-business-address-services-or-any-other-sap-s-4hana-application-with-serverless-functions-on-kyma-part-i/" target="_blank" rel="noopener noreferrer">Part-I</A> of this Blog Series</LI><BR /> <LI>Kyma Serverless Function Implementation explained in <A href="https://blogs.sap.com/2021/09/23/how-to-extend-sap-s-4hana-business-address-services-or-any-other-sap-s-4hana-application-with-serverless-functions-on-kyma-part-ii/" target="_blank" rel="noopener noreferrer">Part-II</A> of this Blog Series</LI><BR /> </OL><BR /> &nbsp;<BR /> <BR /> In our example, we will be implementing the geocode functionality with the Business Partner (BP) transaction. Once our serverless function returns the geocodes, we will be updating a Custom Z table.<BR /> <UL><BR /> <LI>Since it is a customer modification, we can make use of the BADIs available. ADDRESS_UPDATE is the BADI that is used to trigger updates on Address Changes. We have implemented this BADI in SE18 as ZADDRESS_UPD_SRV_POC. The implementing class name is given as ZCL_IM_ADDRESS_UPD_SRV_POC</LI><BR /> </UL><BR /> &nbsp;<BR /> <UL><BR /> <LI style="overflow: hidden"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2021/08/P1-20.png" height="268" width="555" /></LI><BR /> <LI>Based on the type of address created i.e. Organization, Person, or Workplace, add the logic in methods ADDRESS1_SAVED, ADDRESS2_SAVED, and ADDRESS3_SAVED&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; respectively. Next, we must compile the complete URL which will be a combination of:<BR /> <UL><BR /> <LI>URL generated by Kyma runtime</LI><BR /> <LI>Search parameters from BP transaction which will be components of address based on which Geocode will be found. For our PoC, we have considered House Number, Street, City, Region, Postal Code, and Country</LI><BR /> </UL><BR /> </LI><BR /> </UL><BR /> &nbsp;<BR /> <OL><BR /> <LI style="list-style-type: none"></LI><BR /> </OL><BR /> <PRE class="language-abap"><CODE> DATA(url) = 'https://get-geocodes.fdc4fe9.kyma.shoot.live.k8s-hana.ondemand.com/?address='.<BR /> LOOP AT im_t_xadrc ASSIGNING FIELD-SYMBOL(&lt;fs_xadrc&gt;).<BR /> <BR /> IF &lt;fs_xadrc&gt;-house_num1 IS NOT INITIAL.<BR /> full_address = &lt;fs_xadrc&gt;-house_num1.<BR /> ENDIF.<BR /> IF &lt;fs_xadrc&gt;-street IS NOT INITIAL.<BR /> CONCATENATE full_address &lt;fs_xadrc&gt;-street INTO full_address SEPARATED BY space.<BR /> ENDIF.<BR /> IF &lt;fs_xadrc&gt;-city1 IS NOT INITIAL.<BR /> CONCATENATE full_address &lt;fs_xadrc&gt;-city1 INTO full_address SEPARATED BY space.<BR /> ENDIF.<BR /> IF &lt;fs_xadrc&gt;-region IS NOT INITIAL.<BR /> CONCATENATE full_address &lt;fs_xadrc&gt;-region INTO full_address SEPARATED BY space.<BR /> ENDIF.<BR /> IF &lt;fs_xadrc&gt;-post_code1 IS NOT INITIAL.<BR /> CONCATENATE full_address &lt;fs_xadrc&gt;-post_code1 INTO full_address SEPARATED BY space.<BR /> ENDIF.<BR /> IF &lt;fs_xadrc&gt;-country IS NOT INITIAL.<BR /> CONCATENATE full_address &lt;fs_xadrc&gt;-country INTO full_address SEPARATED BY space.<BR /> ENDIF.<BR /> REPLACE '#' WITH space INTO full_address.<BR /> SHIFT full_address LEFT DELETING LEADING space.<BR /> CONDENSE full_address.<BR /> CONCATENATE url full_address INTO DATA(final_url).<BR /> ENDLOOP.</CODE></PRE><BR /> &nbsp;<BR /> <UL><BR /> <LI>Next, an HTTP client for the generated URL must be created. This is done by calling the method CREATE_FROM_URL of class CL_HTTP_CLIENT. This HTTP client is used to send the request to Kyma Serverless Runtime and receive in response the Geocodes of the provided search parameters.</LI><BR /> </UL><BR /> &nbsp;<BR /> <PRE class="language-abap"><CODE>"create HTTP client by url<BR /> CALL METHOD cl_http_client=&gt;create_by_url<BR /> EXPORTING<BR /> url = final_url<BR /> IMPORTING<BR /> client = lo_http_client<BR /> EXCEPTIONS<BR /> argument_not_found = 1<BR /> plugin_not_active = 2<BR /> internal_error = 3<BR /> OTHERS = 4.<BR /> <BR /> IF sy-subrc &lt;&gt; 0.<BR /> "error handling<BR /> ENDIF.<BR /> <BR /> *** Send the request<BR /> lo_http_client-&gt;send(<BR /> EXCEPTIONS<BR /> http_communication_failure = 1<BR /> http_invalid_state = 2 ).<BR /> <BR /> *** Receive the respose<BR /> lo_http_client-&gt;receive(<BR /> EXCEPTIONS<BR /> http_communication_failure = 1<BR /> http_invalid_state = 2<BR /> http_processing_failed = 3 ).</CODE></PRE><BR /> &nbsp;<BR /> <UL><BR /> <LI>Finally, we read the result from the HTTP response and update our custom table with the&nbsp; &nbsp; &nbsp; &nbsp; Geocode.</LI><BR /> </UL><BR /> <PRE class="language-abap"><CODE>*** Read the result<BR /> lv_result = lo_http_client-&gt;response-&gt;get_cdata( ).<BR /> IF lv_result NP 'Internal Server Error'.<BR /> ls_geocode-mandt = sy-mandt.<BR /> ls_geocode-addrnumber = im_address_number.<BR /> SPLIT lv_result AT ',' INTO ls_geocode-latitude ls_geocode-longitude.<BR /> <BR /> MODIFY zaddress_geocode FROM ls_geocode.<BR /> ENDIF.</CODE></PRE><BR /> &nbsp;<BR /> <UL><BR /> <LI>The Custom table structure is as below:</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/2021/08/P2-5.png" /></P><BR /> &nbsp;<BR /> <UL><BR /> <LI>Next, in BP transaction we must create an Organization BP with the values below for address fields which in turn will be considered for the final URL generation:</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/2021/08/P3-2.png" /></P><BR /> &nbsp;<BR /> <UL><BR /> <LI>The address number of the BP above is:</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/2021/08/P4-3.png" /></P><BR /> &nbsp;<BR /> <UL><BR /> <LI>On Save of the Business Partner, the custom table ZADDRESS_GEOCODE is updated:</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/2021/08/P5-4.png" /></P><BR /> &nbsp;<BR /> <BR /> <EM>Note: We did not enhance the BP transaction to display these coordinates, but such enhancements can be taken up if required for the project.</EM><BR /> <BR /> <STRONG>Summary</STRONG><BR /> <BR /> In this blog post, we have seen how a Serverless Function developed in Kyma Runtime can be consumed in the SAP S/4HANA system for the extensibility of Business Address Services or any other SAP S/4HANA applications. 2021-09-27T10:31:38+02:00 https://community.sap.com/t5/technology-blogs-by-sap/sap-btp-serverless-runtime-to-be-discontinued-and-replaced-by-sap-btp-kyma/ba-p/13505309 SAP BTP, Serverless Runtime to be discontinued and replaced by SAP BTP, Kyma Runtime and SAP Integration Suite 2021-10-18T15:27:56+02:00 KStrothmann https://community.sap.com/t5/user/viewprofilepage/user-id/7039 Serverless computing is a truly cloud-native paradigm. Servers and other computing resources are completely hidden away from the developer and the end user. There are servers in serverless, but these are operated by the cloud provider, which means you can almost forget about most tedious maintenance and operations activities. Nicer still is the fact that your cloud provider automatically scales the load for you. You don’t need to worry about peak loads on your side as this is taken care of.<BR /> <H3 id="toc-hId-1086602787">Function-as-a-Service</H3><BR /> Function-as-a-Service (FaaS) refers to an event-driven atomic piece of code that runs in stateless ephemeral containers created and maintained by a third party – typically a cloud provider. From a technology standpoint, FaaS is a combination of code, configuration, and dependencies executed on a compute service in an isolated container. Resource allocation is done in a serverless environment. The resources required to run code are dynamically allocated by the cloud provider.<IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2021/10/Faas-Small-1.png" /><BR /> <BR /> As a result, developers are responsible for neither capacity planning nor the optimal allocation of resources. In practical terms, Function-as-a-Service allows adding event-driven, serverless functionalities that are completely decoupled from existing application landscapes.<BR /> <H3 id="toc-hId-890089282">SAP BTP's Function-as-a-Service Offerings until now</H3><BR /> SAP’s Business Technology Platform until now has offered two Function-as-a-Service options with slightly different scope and feature sets.<BR /> <BR /> <IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2021/10/SRT-and-Kyma-Tiles.png" /><BR /> <BR /> &nbsp;<BR /> <BR /> <STRONG>SAP BTP, Serverless Runtime</STRONG> has been one of SAP’s Function-as-a-Service offerings to enable rapid development in serverless, event-driven environments specifically targeted at extensions in SAP landscapes. SAP BTP, Serverless Runtime is a fully managed cloud service for building, running, and managing stateless application functions.<BR /> <BR /> <STRONG>SAP BTP, Kyma Runtime</STRONG> has been SAP’s second FaaS offering, allowing customers to build extensions by using both microservices and serverless functions. SAP BTP, Kyma runtime is a fully managed Kubernetes runtime based on the open-source project "Kyma". This cloud-native solution allows developers to extend SAP solutions with serverless functions and combine them with containerized microservices. The offered functionality ensures smooth consumption of SAP and non-SAP applications , running workloads in a highly scalable environment, and building event- and API-base extensions.<BR /> <BR /> In short, SAP BTP, Kyma Runtime offers several technical capabilities and benefits:<BR /> <UL><BR /> <LI>Mesh Serverless Functions, Microservices or custom docker images in one runtime</LI><BR /> <LI>Upskill your developers quickly due to open standards</LI><BR /> <LI>Get a fully managed Kubernetes Runtime</LI><BR /> <LI>Leverage the built-in capabilities of Kyma:<BR /> <UL><BR /> <LI>API Microgateway</LI><BR /> <LI>Event bus</LI><BR /> <LI>Service mesh</LI><BR /> </UL><BR /> </LI><BR /> </UL><BR /> These technical capabilities optimize development and give you tangible business benefits:<BR /> <UL><BR /> <LI>Reduction of both the TCO and time-to-market</LI><BR /> <LI>Managed runtime that fits the needs and skillset of your work force for cloud-native solutions</LI><BR /> <LI>Aligned with SAP operational and release processes and standards</LI><BR /> <LI>Best services/tooling from hyper-scalers, combined with open standards + SAP specific value add on top</LI><BR /> </UL><BR /> Customers so far have had the choice between these two great environments to develop their functions-as-a-service. Over time though, it has shown that SAP BTP, Kyma Runtime has proven the more beneficial and more well-rounded runtime for customers, offering more options and benefitting from the traction of its open-source community.<BR /> <H3 id="toc-hId-693575777">OData Provisioning</H3><BR /> OData Provisioning exposes business data and business logic as OData services on SAP Business Technology Platform, thereby enabling customers to run user-centric applications on SAP Cloud. In the Multi-Cloud/Cloud Foundry environment context, OData Provisioning has been available as a part of the SAP BTP, Serverless Runtime.<BR /> <BR /> SAP’s Business Technology Platform until now has offered OData provisioning with slightly different scope and feature sets:<BR /> <UL><BR /> <LI><STRONG>SAP BTP, OData Provisioning</STRONG> (On the NEO environment only) to expose business data and business logic developed on the SAP Business Suite as OData services on the SAP BTP without any additional development effort.</LI><BR /> <LI><STRONG>SAP BTP, Serverless Runtime</STRONG> (On the multi-cloud /CF environment only) included OData Provisioning to expose business data and business logic developed on the SAP Business Suite as OData services on the SAP BTP without any additional development effort.</LI><BR /> <LI><STRONG>SAP Integration Suite</STRONG> is the enterprise-grade integration platform as a service offered by SAP. The Integration Suite is an open IPaaS and consists of a modular set of integration services that work together to support a comprehensive variety of end-to-end integration scenarios.</LI><BR /> </UL><BR /> In particular, SAP Integration Suite supports:<BR /> <UL><BR /> <LI>The integration of SAP and non-SAP applications in the cloud and on premise (A2A)</LI><BR /> <LI>Integration with business partners (B2B) and government agencies (B2G).</LI><BR /> <LI>The design and runtime governance of APIs, including API-based integration.</LI><BR /> <LI>Exposing business data and business logic as OData services on SAP Business Technology Platform</LI><BR /> <LI>Extensions of business processes with workflows, including human interaction steps and business rules; as well as the integration of IoT devices and equipment.</LI><BR /> </UL><BR /> Customers so far have had the choice between the different services for provisioning of OData services. With SAP Integration Suite enabling and end-to-end API based integrations, customers will have the added value of not just provisioning of OData services but to also manage the lifecycle of the service.<BR /> <BR /> <IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2021/10/Transition-1.jpg" /><BR /> <H3 id="toc-hId-497062272">SAP BTP, Serverless Runtime to be replaced by SAP BTP, Kyma Runtime and SAP Integration Suite</H3><BR /> It is due to this that SAP has decided to<STRONG> discontinue SAP BTP, Serverless Runtime </STRONG>and to instead<STRONG> increase the focus on and efforts for SAP BTP, Kyma runtime and SAP Integration suite </STRONG>for the respective capabilities.<BR /> <BR /> Please note this however<STRONG> does not have any impact on the OData Provisioning service on the NEO environment.</STRONG><BR /> <H3 id="toc-hId-300548767">The way forward</H3><BR /> For all existing customers who already use the SAP BTP, Serverless Runtime, <STRONG>we are looking forward to engaging with you to help make the transition as smooth and non-disruptive as possible</STRONG>. 2021-10-18T15:27:56+02:00 https://community.sap.com/t5/technology-blogs-by-sap/hp-enterprise-interactive-digital-assistant-powered-by-sap-conversational/ba-p/13506805 HP Enterprise - Interactive Digital Assistant powered by SAP Conversational AI 2021-12-15T16:29:22+01:00 rohit_dwivedi https://community.sap.com/t5/user/viewprofilepage/user-id/337467 <H2 id="toc-hId-957554660"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2021/11/Picture1-19.png" /></H2><BR /> &nbsp;<BR /> <H2 id="toc-hId-761041155"><STRONG>Artificial Intelligence is the new Electricity!</STRONG></H2><BR /> Artificial Intelligence is everywhere! Just as electricity revolutionized lives 100 years ago, today AI is completely changing our lives. Companies are investing millions in intelligent systems for situation assessment, prediction analysis, learning-based recognition, conversational interfaces, and recommendation engines. Among these intelligent systems, conversational interfaces have become essential in allowing businesses to communicate with customers 24/7. For example, having a Chatbot in place, business becomes far more interactive, natural, and convenient for consumers which, in turn, can improve customer satisfaction.<BR /> <BR /> In order to empower the Intelligent Enterprise, SAP Conversational AI provides all the tools necessary to create chatbots and conversational applications by providing an end-to-end Bot Building Platform covering different stages of development such as Training | Build | Connect | Monitor.<BR /> <H2 id="toc-hId-564527650"><STRONG>Customer Background </STRONG></H2><BR /> <STRONG>Hewett Packard Enterprise's vision</STRONG> is to leverage SAP Intelligent Technologies and leverage the <A href="https://community.sap.com/topics/industry-cloud?" target="_blank">SAP Industry Cloud</A> application capabilities for the Hi-Tech industry to improve their customer experience, gain efficiency, and deliver next-generation business outcomes by following three principles:<BR /> <OL><BR /> <LI><STRONG>Sustainable Foundation for Business Execution</STRONG> – SAP Business Technology Platform. Best-in-class implementation of business processes on a stable, resilient, and scalable platform by keeping the core clean.</LI><BR /> <LI><STRONG>Insight- to-Action driven applications </STRONG>– SAP Conversational AI. Create Chatbots for context awareness, real-time detection, and predictive insights to make informed and quick decisions.</LI><BR /> <LI><STRONG>Process optimization through Intelligent Technologies –</STRONG> SAP Intelligent Robotic Process Automation + Machine Learning + SAP Process Automation. Digital assistance, artificial intelligence, and robotic process automation eliminate more than half of manual tasks.</LI><BR /> </OL><BR /> The goal of the project is to empower HPE’s Partners/Resellers by retrieving time-critical order details from their transactional systems. The chatbot was designed, developed, and deployed within 4 weeks. The SAP Conversational AI's initiative started with a few immediate value-driven discussions to :<BR /> <UL><BR /> <LI>Capture time critical order information based on the events from SAP S/4HANA</LI><BR /> <LI>Providing real-time order status</LI><BR /> <LI>Quickly display packing list for orders</LI><BR /> <LI>Serial number of the ordered item</LI><BR /> <LI>Shipment &amp; delivery information</LI><BR /> <LI>Export order information</LI><BR /> </UL><BR /> The chatbot links complex skills, advanced memory management, and tactically utilizes the SAP Business Technology Platform (SAP BTP) to provide focused conversations and helps:<BR /> <UL><BR /> <LI>Retrieving search results through fuzzy search capabilities</LI><BR /> <LI>Subscribing and unsubscribing to receive alerts for status changes to an order</LI><BR /> <LI>Emailing detailed reports for both search results and a single order</LI><BR /> <LI>Providing cross-platform support – Browser or Mobile devices</LI><BR /> </UL><BR /> <H2 id="toc-hId-368014145"><STRONG>Highlights</STRONG></H2><BR /> The core of the chatbot is equipped with built-In intelligence and embedded machine learning. Resiliency is born from the fact that it is driven by intents and entities, which result in more natural and interactive conversations leading to a greater user experience. The outcome: greater customer satisfaction to drive a greater adoption rate.<BR /> <BR /> <STRONG>Agile Collaboration</STRONG><BR /> <UL><BR /> <LI>Adopted design thinking to blueprint one-bot to many-channels</LI><BR /> <LI>Remote collaboration to build a holistic solution</LI><BR /> <LI>Crowdsource expressions to derive meaningful interactions with robust intents</LI><BR /> <LI>Discovery of necessary entities to enrich the conversation</LI><BR /> <LI>Sample dialogues of human-to-human interactions to inform conversation workflows</LI><BR /> </UL><BR /> <STRONG>BTP Extensions:</STRONG><BR /> <UL><BR /> <LI>The chatbot is personalized with Built-In Intelligence and Advanced Memory Management through Handlebars concepts</LI><BR /> <LI>Custom scripting to display the necessary information predicted by the information the chatbot retrieves</LI><BR /> <LI>Economize screen real estate especially when interacting with SAP Conversational AI through mobile devices</LI><BR /> </UL><BR /> <STRONG>SAP MaxAttention Engagement: </STRONG><BR /> <UL><BR /> <LI>SAP MaxAttention is the trusted partner by HPE in their continuous innovation journey</LI><BR /> <LI>The team from SAP MaxAttention and HPE used fact-based Industry exploration methodology with SAP MaxAttention services to enable and empower the customer</LI><BR /> <LI>Understood the key requirements for HPE’s use cases with the industry best practices and supported the build of the pilot for production roll-out.</LI><BR /> <LI>A successful pilot was delivered in under 4 weeks and supported scaling and industrializing of the industry-specific use-case and driving Innovation in their business processes.</LI><BR /> </UL><BR /> <STRONG>Business Value:</STRONG><BR /> <BR /> The conversational chatbot illustrates the following values of the SAP Conversational AI platform with one bot that is successfully deployed to multiple channels. Please check out the <STRONG><EM>customer’s video</EM></STRONG> <EM><STRONG>testimonial</STRONG></EM> below.<BR /> <UL><BR /> <LI>Lower operating and maintenance cost</LI><BR /> <LI>Faster ROI as a single bot that is flexible to work with different channels like MS Teams</LI><BR /> <LI>Advanced skills and extensions to handle complex conversation scenarios lead to intelligent interactions.</LI><BR /> <LI>Flexible bot constructed to minimize development overhead, maximize the SAP CAI platform, and strategically leverage SAP Business Technology Platform to make it the best-in-breed for chatbots.</LI><BR /> </UL><BR /> &nbsp;<BR /> <BR /> <IFRAME width="560" height="315" src="https://www.youtube.com/embed/zX-ZPm67DR0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen=""></IFRAME><BR /> <BR /> <STRONG>Key Team Members</STRONG><BR /> <BR /> <STRONG>HPE Representative: </STRONG>Arun Navaneethan (Sr. Director, Global IT)<BR /> <BR /> <STRONG>SAP Contacts:</STRONG><EM> &nbsp;</EM><SPAN class="mention-scrubbed">kiran.kola</SPAN><A href="mailto:kiran.kola@sap.com" target="_blank" rel="nofollow noopener noreferrer">,&nbsp;</A><SPAN class="mention-scrubbed">rohit_dwivedi</SPAN>&nbsp;Balaji Gaddam, Thomas Walther<BR /> <BR /> <STRONG>SAP Communications</STRONG>: Maria Jenkinson, Mirna Chaanine<BR /> <BR /> <STRONG> Customer Video Testimonial: <A href="https://www.sap.com/services/premium-engagement/maxattention.html?video=80d02ed8-017e-0010-bca6-c68f7e60039b" target="_blank" rel="noopener noreferrer">sap.com</A>&nbsp;</STRONG><BR /> <BR /> <STRONG>&nbsp;</STRONG> 2021-12-15T16:29:22+01:00 https://community.sap.com/t5/technology-blogs-by-sap/mta-deployment-a-starter/ba-p/13517215 MTA deployment, a starter 2021-12-26T20:51:01+01:00 former_member466339 https://community.sap.com/t5/user/viewprofilepage/user-id/466339 <H2 id="toc-hId-958502237"><STRONG>INTRODUCTION</STRONG></H2><BR /> This blog post is aimed for developers who are very new to SAP BTP which requires a deployment descriptor (MTA or Manifest)&nbsp; to deploy applications.<BR /> <BR /> It is always challenging to deploy an MTA or manifest based application be it NodeJS, GO or Java. Additionally we face a lot of challenges and jargons which slows our development.<BR /> <BR /> Though creating MTA might feel overwhelming at first, it has a lot of advantages to offer. The deployment is one touch most of the time and creates an ecosystem where different components from a single application can collaborate together. Helps us create more resources without writing manual commands or collective shell scripts for every resource we consume.&nbsp; So the entire file is reusable<BR /> <BR /> &nbsp;<BR /> <H2 id="toc-hId-761988732"><STRONG>INSTALLATION OF CLOUD MTA BUILD TOOL</STRONG></H2><BR /> We can install the cloud MTA build tool using any of the methods below in the <A href="https://sap.github.io/cloud-mta-build-tool/download/" target="_blank" rel="nofollow noopener noreferrer">link</A><BR /> <BR /> You have to consider the following limits for the MTA artifacts, which can be handled by the&nbsp;<SPAN class="ph pname">Cloud Foundry</SPAN>&nbsp;deploy service:<BR /> <UL id="loiod04fc0e2ad894545aebfd7126384307c__ul_inf_cwh_1cb" class="ul"><BR /> <LI class="li">Maximum size of the MTA archive: 4 GB</LI><BR /> <LI class="li">Maximum size of MTA module content: 1 GB</LI><BR /> <LI class="li">Maximum size of MTA resource content: 1 GB</LI><BR /> <LI class="li">Maximum size of MTA descriptors (<SAMP class="ph codeph">mtad.yaml</SAMP>&nbsp;and&nbsp;<SAMP class="ph codeph">MANIFEST.MF</SAMP><span class="lia-unicode-emoji" title=":disappointed_face:">😞</span> 1 MB</LI><BR /> </UL><BR /> &nbsp;<BR /> <H2 id="toc-hId-565475227"><STRONG>MTA DEPLOYMENT TERMINOLOGIES</STRONG></H2><BR /> The different terminologies used in MTA deployments are<BR /> <BR /> <STRONG>Multitarget application (MTA)</STRONG><BR /> <BR /> An application comprised of multiple software modules, which are created with different technologies and deployed to different runtimes.<BR /> <BR /> <STRONG>Development descriptor</STRONG> -<BR /> <BR /> A YAML file named mta.yaml that contains a list of all entities, such as modules, resources, and properties that belong to an application or are used by it at runtime, and the dependencies between them. It is automatically generated when an MTA project is created or modified, or when a module is added or removed. The developer needs to edit the descriptor manually to define resources, properties, and dependencies, as well as fill in missing information.<BR /> <BR /> <STRONG>Deployment descriptor</STRONG><BR /> <BR /> A YAML file named mtad.yaml that contains a list of all entities which is created from the WEB IDE or from Multitarget Application Archive Builder tool or manually. This file is similar to Development Descriptor but is used from the MTA Deployer.<BR /> <BR /> <STRONG>Module</STRONG><BR /> <BR /> A self-contained application of a certain type, which is developed, packaged, and deployed.<BR /> <BR /> <STRONG>Module Type</STRONG><BR /> <BR /> A type that defines the structure and the development technology of a module. You can see a list of the module types at Modules.<BR /> <BR /> <STRONG>Resource</STRONG><BR /> <BR /> Any resource, such as an external service that is required by a module at runtime but not provided by the module itself.<BR /> <BR /> <STRONG>Property</STRONG><BR /> <BR /> A property (key-value pair) of an application, module, or resource, that is used during deployment or at runtime.<BR /> <BR /> <STRONG>Parameter</STRONG><BR /> <BR /> A reserved variable belonging to a module or resource, whose value is used during deployment or at runtime.<BR /> <BR /> <STRONG>Dependency</STRONG><BR /> <BR /> A relationship between a module and another module, resource, or property, such as provides and requires.<BR /> <BR /> <EM><STRONG>provides:</STRONG></EM> indicates the properties or parameters that are provided by a module or resource to other modules.<BR /> <BR /> <STRONG><EM>requires</EM></STRONG>: indicates other modules or resources that are required by a module in order to run.<BR /> <BR /> <STRONG>MTA archive (MTAR)</STRONG><BR /> <BR /> Archive containing a deployment descriptor, the module and resource binaries, and configuration files. The archive follows the JAR file specification.<BR /> <BR /> &nbsp;<BR /> <H2 id="toc-hId-368961722"><STRONG>Example</STRONG></H2><BR /> Consider a nodeJS app having dependency to a hdi-container in a subaccount.&nbsp; This can be modelled like this<BR /> <BR /> &nbsp;<BR /> <PRE class="pre codeblock prettyprint prettyprinted" data-v-2d71f788=""><SPAN class="pln">_schema</SPAN><SPAN class="pun">-</SPAN><SPAN class="pln">version</SPAN><SPAN class="pun">:</SPAN> <SPAN class="str">"3.1.0"</SPAN><SPAN class="pln"><BR /> ID</SPAN><SPAN class="pun">:</SPAN><SPAN class="pln"> simple</SPAN><SPAN class="pun">-</SPAN><SPAN class="pln">mta<BR /> version</SPAN><SPAN class="pun">:</SPAN> <SPAN class="lit">1.0</SPAN><SPAN class="pun">.</SPAN><SPAN class="lit">0</SPAN><SPAN class="pln"><BR /> <BR /> modules</SPAN><SPAN class="pun">:</SPAN><BR /> <SPAN class="pun">-</SPAN><SPAN class="pln"> name</SPAN><SPAN class="pun">:</SPAN><SPAN class="pln"> anatz<BR /> type</SPAN><SPAN class="pun">:</SPAN><SPAN class="pln"> javascript</SPAN><SPAN class="pun">.</SPAN><SPAN class="pln">nodejs<BR /> requires</SPAN><SPAN class="pun">:</SPAN><BR /> <SPAN class="pun">-</SPAN><SPAN class="pln"> name</SPAN><SPAN class="pun">:</SPAN><SPAN class="pln"> hdi</SPAN><SPAN class="pun">-</SPAN><SPAN class="pln">service<BR /> <BR /> resources</SPAN><SPAN class="pun">:</SPAN><BR /> <SPAN class="pun">-</SPAN><SPAN class="pln"> name</SPAN><SPAN class="pun">:</SPAN><SPAN class="pln"> hdi</SPAN><SPAN class="pun">-</SPAN><SPAN class="pln">service<BR /> type</SPAN><SPAN class="pun">:</SPAN><SPAN class="pln"> org</SPAN><SPAN class="pun">.</SPAN><SPAN class="pln">cloudfoundry</SPAN><SPAN class="pun">.</SPAN><SPAN class="pln">managed</SPAN><SPAN class="pun">-</SPAN><SPAN class="pln">service<BR /> parameters</SPAN><SPAN class="pun">:</SPAN><SPAN class="pln"><BR /> service</SPAN><SPAN class="pun">:</SPAN><SPAN class="pln"> hana<BR /> service</SPAN><SPAN class="pun">-</SPAN><SPAN class="pln">plan</SPAN><SPAN class="pun">:</SPAN><SPAN class="pln"> hdi</SPAN><SPAN class="pun">-</SPAN><SPAN class="pln">shared</SPAN></PRE><BR /> The sample file contains a nodejs module named anatz which ready to be deployed. You can also specify the path of the module by specifying the path property. Also few modules such as the launchpad do not contain the path property, as it takes the already created modules and configures them to deploy.<BR /> <BR /> A requires property is specified which allows the module to be deployed only if the required dependencies are satisfied. The required dependencies can come from other modules or from the resources that will be created as services in SAP BTP. like databases or event meshes<BR /> <BR /> &nbsp;<BR /> <BR /> Additionally we can also provide parameters such as memory and route to the module. This enables us to control all the modules in one place before deployment<BR /> <BR /> &nbsp;<BR /> <PRE class="pre codeblock prettyprint prettyprinted" data-v-2d71f788=""><SPAN class="pln">_schema</SPAN><SPAN class="pun">-</SPAN><SPAN class="pln">version</SPAN><SPAN class="pun">:</SPAN> <SPAN class="lit">3.1</SPAN><SPAN class="pun">.</SPAN><SPAN class="lit">0</SPAN><SPAN class="pln"><BR /> ID</SPAN><SPAN class="pun">:</SPAN><SPAN class="pln"> anatz</SPAN><SPAN class="pun">-</SPAN><SPAN class="pln">keep</SPAN><SPAN class="pun">-</SPAN><SPAN class="pln">existing<BR /> version</SPAN><SPAN class="pun">:</SPAN> <SPAN class="lit">4.0</SPAN><SPAN class="pun">.</SPAN><SPAN class="lit">0</SPAN><SPAN class="pln"><BR /> <BR /> modules</SPAN><SPAN class="pun">:</SPAN><BR /> <SPAN class="pun">-</SPAN><SPAN class="pln"> name</SPAN><SPAN class="pun">:</SPAN><SPAN class="pln"> anatz<BR /> type</SPAN><SPAN class="pun">:</SPAN><SPAN class="pln"> staticfile<BR /> path</SPAN><SPAN class="pun">:</SPAN><SPAN class="pln"> hello</SPAN><SPAN class="pun">-</SPAN><SPAN class="pln">world</SPAN><SPAN class="pun">.</SPAN><SPAN class="pln">zip<BR /> parameters</SPAN><SPAN class="pun">:</SPAN><SPAN class="pln"><BR /> memory</SPAN><SPAN class="pun">:</SPAN> <SPAN class="lit">64M</SPAN><SPAN class="pln"><BR /> route</SPAN><SPAN class="pun">:</SPAN> <SPAN class="kwd">new</SPAN><SPAN class="pun">-</SPAN><SPAN class="pln">custom</SPAN><SPAN class="pun">-</SPAN><SPAN class="pln">route</SPAN><SPAN class="pun">-</SPAN><SPAN class="pln">$</SPAN><SPAN class="pun">{</SPAN><SPAN class="pln">space</SPAN><SPAN class="pun">}</SPAN><SPAN class="pln"><BR /> keep</SPAN><SPAN class="pun">-</SPAN><SPAN class="pln">existing</SPAN><SPAN class="pun">:</SPAN><SPAN class="pln"><BR /> env</SPAN><SPAN class="pun">:</SPAN> <SPAN class="kwd">true</SPAN><SPAN class="pln"><BR /> service</SPAN><SPAN class="pun">-</SPAN><SPAN class="pln">bindings</SPAN><SPAN class="pun">:</SPAN> <SPAN class="kwd">true</SPAN><SPAN class="pln"><BR /> routes</SPAN><SPAN class="pun">:</SPAN> <SPAN class="kwd">true</SPAN></PRE><BR /> &nbsp;<BR /> <BR /> Sometime we would like to generate our files before starting the build. This can be done by running a shell script or individual commands like mvn clean install or npm install. All these can be speified under Build parameters.<BR /> <DIV><BR /> <BLOCKQUOTE><BR /> <DIV><BR /> <PRE class="language-java"><CODE>build-parameters:<BR /> before-all:<BR /> - builder: custom<BR /> commands:<BR /> - npm install --production</CODE></PRE><BR /> </DIV></BLOCKQUOTE><BR /> </DIV><BR /> <DIV></DIV><BR /> <DIV></DIV><BR /> <DIV>Commands can also be run specific to modules.</DIV><BR /> <DIV></DIV><BR /> <DIV></DIV><BR /> <DIV>Resources can also contain parameters which takes care of special hardcoded values such as url's or references such to files.</DIV><BR /> <DIV></DIV><BR /> <DIV></DIV><BR /> <DIV>So before we plan an MTA deployment</DIV><BR /> <UL><BR /> <LI>It is advisable to look into the manifest.yaml file (If you have already) make note of modules and dependencies before starting to create one here.</LI><BR /> <LI></LI><BR /> <LI>Once you have the module files in place start creating the modules, if needed add a provide property to the module if it requires to be addressed by the upcoming modules by that name</LI><BR /> </UL><BR /> <DIV></DIV><BR /> <H2 id="toc-hId-172448217">CONCLUSION</H2><BR /> <DIV></DIV><BR /> <DIV>Finally do an MTA build using the command <STRONG>mbt build</STRONG> on the module. resolve any errors shown. The final MTAR file will be generated in mta_archive as an .mtar file</DIV><BR /> <DIV></DIV><BR /> <DIV>You can deploy the mtar file to cloud foundry by&nbsp; using the command&nbsp; <STRONG>cf deploy filename.mtar</STRONG></DIV><BR /> If deployment is successful you will receive no process failed message at the end of deployment.<BR /> <BR /> &nbsp;<BR /> <BR /> For more information on MTA's checkout the help <A href="https://help.sap.com/products/BTP/65de2977205c403bbc107264b8eccf4b/d04fc0e2ad894545aebfd7126384307c.html?locale=en-US" target="_blank" rel="noopener noreferrer">portal</A><BR /> <BR /> &nbsp;<BR /> <BR /> &nbsp;<BR /> <BR /> &nbsp;<BR /> <BR /> &nbsp;<BR /> <BR /> &nbsp; 2021-12-26T20:51:01+01:00 https://community.sap.com/t5/technology-blogs-by-sap/sap-btp-serverless-runtime-to-sap-btp-kyma-runtime-migration-examples/ba-p/13524666 SAP BTP Serverless Runtime to SAP BTP Kyma Runtime Migration Examples 2022-08-17T20:14:14+02:00 former_member723140 https://community.sap.com/t5/user/viewprofilepage/user-id/723140 SAP BTP, serverless runtime has been discontinued and replaced by SAP BTP, Kyma runtime. Read more about this in the <A href="https://blogs.sap.com/2021/10/18/sap-btp-serverless-runtime-to-be-discontinued-and-replaced-by-sap-btp-kyma-runtime-and-sap-integration-suite/" target="_blank" rel="noopener noreferrer">blog post</A> by <SPAN class="mention-scrubbed">karsten.strothmann</SPAN>.<BR /> <P class="c-mrkdwn__pre" data-stringify-type="pre">Because of the sunset of the previous SAP BTP, serverless runtime offering, SAP BTP users will look into SAP BTP, Kyma runtime as an alternative to host their functions.</P><BR /> <P class="c-mrkdwn__pre" data-stringify-type="pre">Hi, my name is Krzysztof and I' am working on the Kyma project. In this blog post, I want to help you get started with SAP BTP, Kyma runtime and point you to some useful code samples that will help you migrate common FaaS scenarios from SAP BTP, serverless runtime into SAP BTP, Kyma runtime.</P><BR /> <BR /> <H1 class="c-mrkdwn__pre" data-stringify-type="pre" id="toc-hId-830257666">SAP BTP, Kyma runtime - more than meets the eye</H1><BR /> <P class="c-mrkdwn__pre" data-stringify-type="pre">SAP BTP, Kyma runtime offers fully managed Kubernetes where you can mix the BTP, serverless runtime functions, microservices, or custom docker images in one runtime. Additionally, it offers built-in capabilities to get you up to speed with your cloud-native application development, such as API gateway, event bus, or service mesh.</P><BR /> <BR /> <H2 id="toc-hId-762826880">Get Started</H2><BR /> The best way to get started with SAP BTP, Kyma runtime functions is to create one.<BR /> <P class="c-mrkdwn__pre" data-stringify-type="pre">First, you need to <A href="https://help.sap.com/products/BTP/65de2977205c403bbc107264b8eccf4b/09dd313bf6644250a14f8f38c3d644c0.html?locale=en-US" target="_blank" rel="noopener noreferrer">create a Kyma instance</A> (if you don't have one already), and then simply follow our <A href="https://help.sap.com/products/BTP/65de2977205c403bbc107264b8eccf4b/fe4ba5b46f794037a4aee13df9df2d3c.html?locale=en-US" target="_blank" rel="noopener noreferrer">tutorial</A> to create a function. Visit the Kyma project website for more <A href="https://help.sap.com/products/BTP/65de2977205c403bbc107264b8eccf4b/fe4ba5b46f794037a4aee13df9df2d3c.html?locale=en-US" target="_blank" rel="noopener noreferrer">tutorials</A>.</P><BR /> <BR /> <H1 id="toc-hId-437230656">Migration Examples</H1><BR /> <P class="c-mrkdwn__pre" data-stringify-type="pre">To help you with the transition from SAP BTP, serverless runtime to SAP BTP, Kyma runtime, we have prepared a few <A href="https://github.com/SAP-samples/kyma-runtime-extension-samples/tree/main/faas-runtime-to-kyma-migration" target="_blank" rel="nofollow noopener noreferrer">examples</A> to demonstrate how to migrate the most common scenarios.</P><BR /> <P class="c-mrkdwn__pre" data-stringify-type="pre">You can learn how to expose Kyma function via HTTPS to the outside world using API Gateway, how to subscribe your function to events from SAP BTP Event Mesh, or how to use Kubernetes Secrets and ConfigMaps to inject environment variables to your function.</P><BR /> Those scenarios are based on a selection of the original SAP BTP, serverless runtime <A href="https://github.com/SAP-archive/cloud-function-nodejs-samples/tree/master/examples" target="_blank" rel="nofollow noopener noreferrer">code samples</A><BR /> <H1 id="toc-hId-240717151">Conclusion</H1><BR /> The migration examples show how to use SAP BTP, Kyma runtime features (serverless, API gateway, and eventing) to model the same scenarios that were possible with the discontinued SAP BTP, serverless runtime.<BR /> <BR /> I hope they will help you get started with the SAP BTP, Kyma runtime. Please share your feedback in the comments section. You can also get in touch with our team via <A href="https://kyma-community.slack.com/archives/CD0K2SA7K" target="_blank" rel="nofollow noopener noreferrer">Slack</A>.<BR /> <BR /> &nbsp; 2022-08-17T20:14:14+02:00 https://community.sap.com/t5/technology-blogs-by-members/sap-inside-track-2023-bengaluru-my-experience-as-a-speaker/ba-p/13566630 SAP Inside Track 2023 # Bengaluru–My experience as a Speaker 2023-04-05T02:20:19+02:00 ShaikAzmathulla https://community.sap.com/t5/user/viewprofilepage/user-id/130494 Greetings, Community friends!<BR /> <BR /> Wishing you all a wonderful day!<BR /> <BR /> I’m very excited to share that I have taken part in&nbsp;<STRONG>SAP Inside Track Bengaluru</STRONG>&nbsp;on 4th&nbsp;March 2023, at SAP Labs, as a <STRONG>Speaker</STRONG> on&nbsp;“<STRONG>SAP Integration Suite implementation from Customer Perspective</STRONG><STRONG>” </STRONG>topic<STRONG>.</STRONG> It was an excellent experience. It was like a&nbsp;<STRONG>mini-SAP TechEd</STRONG><STRONG>.</STRONG> More than 1000 professionals and enthusiasts from different organizations participated in the largest SIT to date.<BR /> <BR /> <IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/sitBLR-2023-sponsor-4.png" /><BR /> <BR /> This blog will describe my experience at SIT Bangalore 2023. It has registration, keynote, Key take aways from my session and recognitions.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><STRONG>Registration: </STRONG></P><BR /> Registration was well organized by the volunteering team. They guided us to the sessions and hospitality that would interest us throughout the day. I would like to extend my special thanks to all the sponsors.<BR /> <BR /> <STRONG>Keynote: </STRONG><BR /> <BR /> The event kickstarted with a keynote session by&nbsp;<A href="https://www.linkedin.com/in/sindhugangadharan/" target="_blank" rel="nofollow noopener noreferrer">Sindhu Gangadharan</A>, MD and SVP of&nbsp;<A href="https://www.linkedin.com/company/saplabsindia/mycompany/" target="_blank" rel="nofollow noopener noreferrer">SAP Labs India</A>, The interaction with her is always fascinating, and this time she highlighted the importance of community and future SIT events. Thanks for always supporting to community events.<BR /> <BR /> <STRONG><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/image.png" /></STRONG><BR /> <BR /> <STRONG>&nbsp;</STRONG><BR /> <P style="overflow: hidden;margin-bottom: 0px"><B>Key take aways from my session</B><STRONG>: </STRONG></P><BR /> <BR /> <UL><BR /> <LI><STRONG>SAP Integration Suite – Customer Perspective Introduction&nbsp;</STRONG></LI><BR /> </UL><BR /> SAP Integration Suite is a cloud-based platform that enables customers to integrate their various systems, applications, and data sources. It provides integration services that help businesses connect and manage data and processes across different systems, both within and outside the enterprise. I have explained about customer challenges, business automation via Integration suite and top10 reasons to choose integration suite.<BR /> <UL><BR /> <LI><STRONG>Use cases discussion and demos</STRONG><STRONG>. </STRONG></LI><BR /> </UL><BR /> <STRONG>&nbsp;</STRONG><STRONG>First Demo: SF integration with Cloud to on premise </STRONG>– In this demo I have created <STRONG>SIT-BLR</STRONG> as an <STRONG>employee</STRONG> and replicated it to <STRONG>SAP S/4</STRONG> on premise. I have explained the end-to-end scenario including the configuration. Specifically, I have explained on standard integration which helped us in seem less integration in replicating the data. In addition to standard interfaces, I have taken a walkthrough of custom interfaces like FBP to SAP. In this interface we have used almost all key functions in I flow. Almost 9 groove scripts have been used to fulfil the requirement.<BR /> <BR /> <STRONG>Second demo: DCS integration with cloud to on premise –</STRONG>SAP Digital Compliance is a cloud-based solution that helps businesses manage the tax compliance obligations. SAP S/4HANA On-Premises system configured with SAP Digital Compliance via Cloud connector and client certificates. The configuration steps are explained in the end-to-end demo.<BR /> <BR /> Please find the following link to my presentation and demos.<BR /> <BR /> <A href="https://drive.google.com/drive/folders/1r8m2ZQdnNANErsFYV6p4nZ2-MSykdzrs" target="_blank" rel="nofollow noopener noreferrer">https://drive.google.com/drive/folders/1r8m2ZQdnNANErsFYV6p4nZ2-MSykdzrs</A><BR /> <BR /> <IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/Img-2.png" /><BR /> <BR /> &nbsp;<BR /> <BR /> Please find the link below to view the presentations from the other tracks sessions.<BR /> <BR /> <A href="https://drive.google.com/drive/folders/14ol_h2q3LanEpWZr3FUJy49VcWJ6tkR5" target="_blank" rel="nofollow noopener noreferrer">https://drive.google.com/drive/folders/14ol_h2q3LanEpWZr3FUJy49VcWJ6tkR5</A><BR /> <BR /> <STRONG>Recognition</STRONG>: Certificates were distributed at the end of the event, and I carry with me wonderful memories.<BR /> <BR /> <IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/IMG_20230401_202230__01.jpg" /><BR /> <BR /> My sincere thanks to <A href="https://www.linkedin.com/in/abhishekchatterjeee/" target="_blank" rel="nofollow noopener noreferrer">Abhishek Chatterjee</A>&nbsp;, <A href="https://www.linkedin.com/in/maheshpalavalli/" target="_blank" rel="nofollow noopener noreferrer">Mahesh Palavalli</A> , <SPAN class="mention-scrubbed">syambabu.allu</SPAN> and <A href="https://www.linkedin.com/feed/hashtag/?keywords=sapcommunity&amp;highlightedUpdateUrns=urn%3Ali%3Aactivity%3A6983874272008056832" target="_blank" rel="nofollow noopener noreferrer">#sapcommunity</A>&nbsp;for great opportunity given to me on sharing my possible best knowledge on <STRONG>Integration Suite</STRONG> spend on the #<STRONG>sitblr&nbsp;stage</STRONG>, it encourages me to participate in many more events and gain knowledge.<BR /> <P style="overflow: hidden;margin-bottom: 0px"><IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/04/IMG_20230304_174945.jpg" height="386" width="515" /></P><BR /> In closing, I would like to express my gratitude to the organizers and volunteers.<BR /> <BR /> <A href="https://www.linkedin.com/in/makrao/" target="_blank" rel="nofollow noopener noreferrer">Mohammed AK Rao</A>,&nbsp;<A href="https://www.linkedin.com/in/peeyush-chaurasia-529145236/" target="_blank" rel="nofollow noopener noreferrer">Peeyush Chaurasia</A>, <A href="https://www.linkedin.com/in/pavankumarpvn/" target="_blank" rel="nofollow noopener noreferrer">Pavan Kumar PVN</A>,&nbsp;<A href="https://www.linkedin.com/in/pushpendra-yadav-a76b1042/" target="_blank" rel="nofollow noopener noreferrer">Pushpendra Yadav</A>, <A href="https://www.linkedin.com/in/priti-dhingra-7029374/" target="_blank" rel="nofollow noopener noreferrer">Priti Dhingra</A>,&nbsp;<A href="https://www.linkedin.com/in/gopal-anand/" target="_blank" rel="nofollow noopener noreferrer">Gopal Anand</A>&nbsp;,<A href="https://www.linkedin.com/in/ahsan-farooqui-2680aa58/" target="_blank" rel="nofollow noopener noreferrer">Ahsan Farooqui</A>,&nbsp;,&nbsp;<A href="https://www.linkedin.com/in/kavya-krishnan-983374158/" target="_blank" rel="nofollow noopener noreferrer">Kavya Krishnan</A>,&nbsp;,&nbsp;<A href="https://www.linkedin.com/in/anjitha-k-a-13762a1a0/" target="_blank" rel="nofollow noopener noreferrer">Anjitha K A</A>,&nbsp;<A href="https://www.linkedin.com/in/megha-panjwani-496239b2/" target="_blank" rel="nofollow noopener noreferrer">Megha Panjwani</A>,&nbsp;<A href="https://www.linkedin.com/in/swati-maste-69a467210/" target="_blank" rel="nofollow noopener noreferrer">Swati Maste</A>,&nbsp;<A href="https://www.linkedin.com/in/chinmayi-shetty-3490411b7/" target="_blank" rel="nofollow noopener noreferrer">Chinmayi Shetty</A>,&nbsp;<A href="https://www.linkedin.com/in/srinivasa-raghavan-s-628709208/" target="_blank" rel="nofollow noopener noreferrer">Srinivasa Raghavan S</A><BR /> <BR /> Best Regards,<BR /> <BR /> Azmath.<BR /> <BR /> SME – SAP &amp; Non-SAP Integrations, Certified Integration Blackbelt.<BR /> <BR /> References about SIT:,&nbsp;<A href="https://blogs.sap.com/2023/01/15/sap-inside-track-bengaluru-02-2023-register-now/" target="_blank" rel="noopener noreferrer">SIT 2023</A>, &nbsp;<A href="https://groups.community.sap.com/t5/welcome-corner-blog-posts/sap-inside-track-what-is-it-about/ba-p/129189" target="_blank" rel="noopener noreferrer">About SIT</A>.<BR /> <BR /> &nbsp;<BR /> <P style="overflow: hidden;margin-bottom: 0px"></P> 2023-04-05T02:20:19+02:00 https://community.sap.com/t5/technology-blogs-by-members/benefits-of-keeping-the-core-clean-with-sap-btp/ba-p/13551754 Benefits of Keeping the Core Clean with SAP BTP 2023-07-03T17:12:28+02:00 Reza https://community.sap.com/t5/user/viewprofilepage/user-id/12465 <H1 id="toc-hId-832939784">Introduction:</H1><BR /> In the world of enterprise software, maintaining a clean and optimized core system is vital for organizations to adapt and thrive in an ever-evolving business landscape. SAP Business Technology Platform (BTP) offers a powerful solution by enabling businesses to keep their core clean while leveraging cloud-based services and innovation capabilities. In this blog post, we will explore what "keeping the core clean" means in the context of SAP BTP and why it is essential for unlocking agility and innovation.<BR /> <H2 id="toc-hId-765508998"><EM><SPAN style="color: #cc99ff">What Does "Keeping the Core Clean" Mean? </SPAN></EM></H2><BR /> Keeping the core clean refers to the practice of minimizing customization and modifications to the core ERP system, such as SAP S/4HANA, and leveraging cloud-based services provided by SAP BTP for additional functionalities, extensions, and innovation. It involves adopting a modular and decoupled approach where the core system focuses on essential business processes and data integrity, while non-core functions are handled through integration with SAP BTP services.<BR /> <H2 id="toc-hId-568995493">Benefits of Keeping the Core Clean with SAP BTP:</H2><BR /> <OL><BR /> <LI>Enhanced Agility: By minimizing modifications to the core system, organizations can upgrade their ERP system more easily and frequently, benefiting from the latest innovations and bug fixes offered by SAP. This results in faster time-to-market for new features and capabilities.</LI><BR /> <LI>Reduced Complexity: Keeping the core system clean helps to reduce the complexity of managing and maintaining customizations. It allows businesses to leverage pre-built integration scenarios, extensions, and applications available on SAP BTP, eliminating the need for extensive custom development within the core system.</LI><BR /> <LI>Scalable and Future-Proof Architecture: SAP BTP provides a scalable cloud platform with a wide range of services, such as SAP Cloud Platform Integration, API Management, and Workflow, which can be seamlessly integrated with the core system. This enables organizations to meet evolving business needs without compromising system performance or stability.</LI><BR /> <LI>Innovation Enablement: By utilizing SAP BTP, businesses can tap into a rich ecosystem of ready-to-use applications, industry-specific solutions, and partner offerings. They can leverage these innovations to extend the functionality of their core system and drive digital transformation initiatives without impacting the stability of their core processes.</LI><BR /> </OL><BR /> <H2 id="toc-hId-372481988">Examples of Keeping the Core Clean with SAP BTP:</H2><BR /> <OL><BR /> <LI>Customer Experience: Organizations can use SAP BTP services, such as SAP Commerce Cloud or SAP Marketing Cloud, to enhance customer engagement and deliver personalized experiences without heavily customizing the core ERP system.</LI><BR /> <LI>Integration and Connectivity: SAP BTP offers robust integration capabilities, allowing organizations to connect their core system with external systems, suppliers, and customers. This enables seamless data exchange and process automation while keeping the core system lightweight and efficient.</LI><BR /> <LI>Advanced Analytics: Leveraging SAP Analytics Cloud or SAP Data Warehouse Cloud on SAP BTP, organizations can perform advanced analytics and reporting on data from multiple sources, providing valuable insights without burdening the core ERP system.</LI><BR /> </OL><BR /> <H1 id="toc-hId-46885764">Conclusion:</H1><BR /> Keeping the core clean with SAP BTP is a strategic approach that empowers organizations to maintain a stable, scalable, and future-proof core system while leveraging cloud-based services for agility and innovation. By adopting this approach, businesses can reduce complexity, accelerate innovation, and drive digital transformation without compromising the integrity of their core processes. Embrace SAP BTP as your strategic technology platform and unlock the full potential of a clean core for enhanced business agility and continuous innovation. 2023-07-03T17:12:28+02:00 https://community.sap.com/t5/technology-blogs-by-sap/unleashing-limitless-innovation-with-sap-blue-the-internal-gig-platform/ba-p/13560395 Unleashing limitless Innovation with SAP Blue - The Internal Gig Platform 2023-07-18T21:13:30+02:00 athira_kannan https://community.sap.com/t5/user/viewprofilepage/user-id/288735 Crowdsourcing platforms have gained popularity as an effective means for organizations to tap into a global community of problem solvers. From simple tasks to complex scientific challenges, these platforms cater to diverse needs and audiences. However, what happens when a gig platform is brought within an organization? In the era of digital transformation, it is necessary for organizations to adapt to new ways of working and innovating. SAP Blue2.0, a revolutionary internal gig work platform, went live on June 14th, 2023, serving as a catalyst for innovation at SAP Labs India.<BR /> <BR /> <STRONG>Platform Features and Benefits:</STRONG><BR /> <BR /> Built on the renowned SAP BTP (Business Technology Platform) and leveraging cutting-edge technologies such as React, SAP Blue is a digital marketplace that empowers employees to discover, apply for, and work on a wide range of projects across different departments and business units. While the earlier version of SAP Blue saw initial success, it had lost momentum over time due to a lack of knowledge among the employees and outdated user experience. The revamped platform offers an intuitive user interface and introduces new features like feedback and testimonials to enhance the overall user experience.<BR /> <BR /> SAP Blue is not limited to developers or product development teams. It encompasses various areas, including strategy, marketing, communications, UX/UI, and more. By tapping into SAP Blue, employees have the opportunity to work on short-term projects, fostering collaboration, agility, and professional development. The platform encourages individuals to expand their horizons by engaging in projects that requires technologies like UI5, machine learning, and artificial intelligence. It serves as a powerful tool for both experts and enthusiastic learners, promoting a sense of ownership and driving professional growth while adapting to changing business needs.<BR /> <BR /> Additionally, SAP Blue provides a platform for Lines of Business (LoBs) to obtain cost-effective solutions for their problem statements. Rather than seeking external hires, leaders can present these challenges as stretch assignments within the platform, maximizing efficiency and effectiveness.<BR /> <BR /> &nbsp;<BR /> <P style="overflow: hidden;margin-bottom: 0px">Testimonials and the journey:</P><BR /> The journey of SAP Blue began in November 2022, with contributions from both new and seasoned team members.<BR /> <BLOCKQUOTE>“<STRONG><EM>We knew we have to upgrade the user experience for the people. Ideation started November 2022. After multiple check points, design thinking sessions and scope finalization, within in 6 months, we revamped the whole platform. We soft launched it in dkom earlier this year and we had over 600+ unique enagements.14th of June we went live. And we already have 1.2K users &amp; 23 + live projects, including some from the SAP Labs India management.” – </EM></STRONG>Akshay Sureshchand, Program Head - SAP BLUE<BR /> <BR /> <STRONG><EM>“With the world venturing into unexplored territory filled with limitless opportunities that can be unleashed by technology, there exists tremendous untapped potential in harnessing bottom-up innovation. SAP Blue exemplifies the extensive engineering elasticity in product development that an organization can achieve by integrating diverse talents from within. It allows us to access the collective wisdom and ingenuity of a diverse group, presenting a distinct and effective approach to fostering innovation.” </EM></STRONG>- Mohammed Anzy S, Chief Operating Officer, SAP Labs India</BLOCKQUOTE><BR /> &nbsp;<BR /> <BLOCKQUOTE><STRONG><EM>“We’d like to refer SAP Blue as our in-house gig platform where colleagues can take up projects and interests beyond their daily scope of work to expand their horizons, discover new skills, get inspired by new possibilities, challenge their boundaries, network with like-minded people, and get a deeper understanding of SAP strategy through varied perspectives.”</EM></STRONG>- Sindhu Gangadharan, SVP &amp; MD, SAP Labs India and Head, SAP User Enablement</BLOCKQUOTE><BR /> By embracing SAP Blue, organizations can foster innovation, agility, and employee engagement, unlocking their true potential. This internal gig work platform offers a gateway to endless possibilities, enabling individuals to drive their professional growth and contribute to changing business needs. With SAP Blue, SAP Labs India is embarking on a journey of collaboration and unleash a future with limitless innovation.<BR /> <BR /> <IMG class="migrated-image" src="https://community.sap.com/legacyfs/online/storage/blog_attachments/2023/07/DSC07793-min-scaled.jpg" /> 2023-07-18T21:13:30+02:00