Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
svenhuberti
Product and Topic Expert
Product and Topic Expert
When I started coding, I was writing ASP pages that I hosted on IIS. It was amazing: from static HTML pages to dynamic applications running in a browser! After that I moved to Java POJOs and ended my coding career with JSFs... That time seems far away, and since then a LOT has been happening (including me stopping the coding).

Today, we are talking about agile development, sprints, continuous integration. etc., which have changed the organizational way of working. But this change would not have been possible without new technologies and concepts such as micro services, NodeJS, Bootstrap, RESTful APIs, PaaS, Maven, Git, etc..

So when I decided to create a little REST API implementation, needless to say I had to get my stuff together first. Obviously, because I am acquainted with middleware and especially API management, I wanted to start designing my API first. To do so, I decided to use OpenAPI (natively supported by SAP API Management) as description language. The opensource tools available around OpenAPI easily lets you generate server stubs; in SAP API Management, I can choose between NodeJS, Jax-RS or Spring. I decided to go for NodeJS, in order to deploy my API in the SAP Cloud Platform based on Cloud Foundry. Indeed, from there, you can use a Cloud Foundry Service Broker to simply and efficiently protect your API through SAP API Management, as described by Shruthi here.

As you can see, SAP supports the full lifecycle of an API, from the design to the monitoring, implementation and runtime included.

In this blog, I will focus especially on designing, implementing and securing the API in order to get you started with your own API.

 

To start with, here is a quick overview of the parts we'll cover (in red).
As an API Developer, we'll use the SAP API Management API Designer to generate the OpenAPI defintion of our API. Then we'll generate NodeJS server stubs for it, adapt them to our environment, and deploy the application on the SAP Cloud Platform Cloud Foundry PaaS. Eventually, we'll protect that API with an API proxy from SAP API Management.



In this blog, I am assuming that you are familiar with SAP API Management and the SAP Cloud Platform to seom extend.

Let's get started...


Design your API with OpenAPI (f.k.a. Swagger)


First of all, let's open the API Designer. This is done through SAP API Management (which you can use from SAP Cloud Platform trial). Click on "Develop" in the menu, and click on the "Create in API Designer" button under the "API" tab.



In the API Designer, you can create or import an OpenAPI file or convert OData or RAML into OpenAPI.

Because the focus of this blog is not on OpenAPI, let's keep things simple. Copy the API defintion from below into your editor.
swagger: "2.0"
info:
version: "1.0.0"
title: "PartnerBanking Information API"
x-targetEndpoint: "https://trial.apim1.hanatrial.ondemand.com"
host: "trial.apim1.hanatrial.ondemand.com:443"
basePath: "/v1/PartnerBankingInformation"
schemes:
- "http"
- "https"
consumes:
- "application/json"
produces:
- "application/json"
paths:
/partnerBankingInformation:
get:
description: "\nReturns all the banking information of the partner specified\
\ through its name or ID\n\nExample of use:\n\n/partnerBankingInformation?apikey=123&partnerId=123456\n"
operationId: "getPartnerBankingInformation"
parameters:
- name: "apiKey"
in: "query"
description: "The API key provided by the Developer Portal upon API subscription"
required: true
type: "string"
- name: "partnerName"
in: "query"
description: "The name of the partner"
required: false
type: "string"
- name: "partnerId"
in: "query"
description: "The partner id number"
required: false
type: "string"
responses:
200:
description: "Success"
schema:
$ref: "#/definitions/partnerBankingInformation"
default:
description: "Error"
schema:
$ref: "#/definitions/ErrorResponse"
x-swagger-router-controller: "Default"
post:
description: "Creates a partner banking information."
operationId: "postPartnerBankingInformation"
parameters:
- name: "apiKey"
in: "query"
description: "The API key provided by the Developer Portal upon API subscription"
required: true
type: "string"
- name: "partnerID"
in: "query"
description: "The partner id number"
required: true
type: "string"
- name: "partnerName"
in: "query"
description: "The partner name"
required: true
type: "string"
- name: "partnerPhoneNumber"
in: "query"
description: "The partner phone number"
required: true
type: "string"
- name: "partnerEmail"
in: "query"
description: "The partner email"
required: true
type: "string"
- name: "partnerAddress"
in: "query"
description: "The partner address"
required: true
type: "string"
- name: "partnerIBAN"
in: "query"
description: "The partner IBAN"
required: true
type: "string"
responses:
200:
description: "Success"
schema:
$ref: "#/definitions/partnerBankingInformation"
default:
description: "Error"
schema:
$ref: "#/definitions/ErrorResponse"
x-swagger-router-controller: "Default"
put:
description: "Updates a partner banking information."
operationId: "putPartnerBankingInformation"
parameters:
- name: "apiKey"
in: "query"
description: "The API key provided by the Developer Portal upon API subscription"
required: true
type: "string"
- name: "partnerID"
in: "query"
description: "The partner id number"
required: true
type: "string"
- name: "partnerName"
in: "query"
description: "The partner name"
required: true
type: "string"
- name: "partnerPhoneNumber"
in: "query"
description: "The partner phone number"
required: true
type: "string"
- name: "partnerEmail"
in: "query"
description: "The partner email"
required: true
type: "string"
- name: "partnerAddress"
in: "query"
description: "The partner address"
required: true
type: "string"
- name: "partnerIBAN"
in: "query"
description: "The partner IBAN"
required: true
type: "string"
responses:
200:
description: "Success"
schema:
$ref: "#/definitions/partnerBankingInformation"
default:
description: "Error"
schema:
$ref: "#/definitions/ErrorResponse"
x-swagger-router-controller: "Default"
x-swagger-router-controller: "PartnerBankingInformation"
definitions:
partnerBankingInformation:
properties:
partnerId:
type: "string"
description: "Identifier of the partner"
partnerName:
type: "string"
description: "Name of the partner"
partnerPhoneNumber:
type: "string"
description: "Phone number of the partner"
partnerEmail:
type: "string"
description: "Email of the partner"
partnerAddress:
type: "string"
description: "Full address including street, number, ZIP code and city name"
partnerIBAN:
type: "string"
description: "IBAN of partner"
ErrorResponse:
required:
- "message"
properties:
message:
type: "string"

As you can see from the defintion file, it represents an API for getting and setting Partner Banking Information (GET/POST/PUT). Note that the API could have been simplified by passing the payload as body instead of params, but again: that is not the focus here. 😉

Here is the result in the API Designer:



Since this definition file is fine for our use case, we will not make any change to it at this point in time. However, feel free to play around with it in order to understand OpenAPI and the API Designer better.

Now that the API defintion is fine, let's generate the NodeJS stubs from the API Designer.

To do so, simply click on "Generate Server / NodeJS".



Change the name of the application to something meaningful like "PartnerBankingInformation" and click on "Generate Project".



The project is now being generated for you, packaged in a ZIP file and provided as download through your browser.



Take that file and unzip it in your work directory.


Adapt your API


Within your work directory, you will now find the NodeJS project files that were generated for you.



Within these files, we'll do a couple of changes. We will adapt the package.json file and the index.js file. Note that the controllers/DefaultService.js file contains the actual implementation of the operations defined in the Swagger defintion. This is what you may want to change when implementing your own business logic.

Also note that we are still refining the generation of the files mentioned above, hence the adjustments on package.json and index.js may not be necesary in the future.

 

Package.json


The package.json file is basically describing your application so that NodeJS knows metadata (version, application name, ...) and dependencies to properly deploy the app.

Here we need to add one thing: the Cloud Foundry dependency.

Edit your package.json file to match the following one:
{
"name": "partnerbanking-information-api",
"version": "1.0.0",
"description": "No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)",
"main": "index.js",
"scripts": {
"prestart": "npm install",
"start": "node index.js"
},
"keywords": [
"swagger"
],
"license": "Unlicense",
"private": true,
"dependencies": {
"cfenv": "^1.0.0",
"connect": "^3.2.0",
"js-yaml": "^3.3.0",
"swagger-tools": "0.10.1"
}
}

Note that we added the "cfenv" dependency in the dependencies section.
"cfenv": "^1.0.0",

 

index.js


Within the index.js file, which is called whenever our application is started, we need to make sure to bind the application to the right port.

For now, the port is hard-coded but we want this to be working in the Cloud Foundry environment as well.



So lets change the server port to something more dynamic:

Change the line #8 "var serverPort = 443" with the following code snippet:
//var serverPort = 443;

//Modified
var cfenv = require("cfenv");
var appEnv = cfenv.getAppEnv();
var serverPort = appEnv.port || 443;

As you can see, we are now getting variables from CF and hence we assign the CF port to our application. By default we still use 443.

 

Test your application


If you have been curious, you may have looked at the DefaultService.js file already. If not, here is what it looks like:



So you can see that if you were to call the API now, the call would be routed to the getPartnerBankingInformation method, sending you back some JSON example data.

In a real-life scenario, this is where you would implement your own business logic, which is out-of-scope for this blog.

In the part 2 of my blog, I will explain how to upload the application to your SAP Cloud Platform cloud foundry environment, and then protect it by using SAP API Management.

 
1 Comment