SAP API Management & HANA XS - Part IV

Sandro Montemezzani - 01.04.2019

Überblick

In diesem Teil der Blog-Serie erweitern wir das Szenario um eine API-Schnittstelle zu den Daten. Hierzu verwenden wir das API-Management auf der SAP Cloud Platform.

Wir erstellen zunächst eine neue API im API Portal, wie auf dem Bild zu sehen ist.

Die API wird einen API-Key zum Zugriff benötigen, welcher als Header APIKey mitgeliefert wird.

API Designer

Die Endpunkte zur API definieren wir mit dem API Designer von SAP. Hierzu kann auf der Seite zur neu angelegten API auf "Edit in API Designer" geklickt werden.

Im API-Designer werden die Endpunkte im YAML Format nach OpenAPI Spezifikation definiert. Mehr Informationen zur OpenAPI Spezifikation gibt es hier.

swagger: '2.0'
info:
  version: '1'
  title: Company Data
  description: '<p>Company Data</p>'
host: 'pXXXXXXXXXXtrial-trial.apim1.hanatrial.ondemand.com:443'
basePath: /companydata/v1
produces:
  - application/json
consumes:
  - application/xml
schemes:
  - https
paths:
  /companies:
    get:
      parameters:
        - name: APIKey
          in: header
          description: the API key that is provided by the developer portal
          type: string
          required: true
      description: lists all companies in the database
      responses:
        '200':
          description: Success
          schema:
            type: array
            items:
              type: object
              properties:
                id:
                  type: integer
                key:
                  type: string
                long_name:
                  type: string
                short_name:
                  type: string
  ...

Folgende Endpunkte werden für unser Szenario benötigt:

  • /companies - Listet alle Companies in der Datenbank
  • /companies/{CompanyId} - Gibt eine bestimmte Company zurück
  • /entities - Listet alle Entities in der Datenbank, optional gefiltert mit einem type Parameter
  • /entities/{entityId} - Gibt eine bestimmte Entity zurückWiederverwendung von Services
  • /entities/{entityId}/hours - Listet die Öffnungszeiten dieser Entity zwischen from und until Parametern
  • /entities/{entityId}/hours/{weekOfYear} - Listet die Öffnungszeiten für die zB zwanzigste Kalenderwoche

API Policies

Die Policies der API sollen zum einen sicherstellen, dass der API-Aufruf zusammen mit einem gültigen API-Key getätigt wurde. Darüber hinaus sollen sie den API-Aufruf in einen gültigen OData-Query umwandeln und die für die Datenbank benötigten Credentials einfügen.

Für die APIKey-Validierung können wir die vorgefertigte Policy "Verify API Key" zum Incoming-Request-Stream des Proxy-Endpoint-Preflows einfügen:

<VerifyAPIKey async="true" continueOnError="false" enabled="true" xmlns="http://www.sap.com/apimgmt">
  <APIKey ref="request.header.APIKey" />
</VerifyAPIKey>

Für die Backend-Credentials fügen wir zunächst eine "Assign Message" Policy zum Incoming-Request-Stream des Target-Endpoint-Postflows hinzu, und fügen die entsprechenden Daten für den COMPANYDATAUSER_READONLY Nutzer ein:

<AssignMessage async="false" continueOnError="false" enabled="true" xmlns="http://www.sap.com/apimgmt">
  <AssignVariable>
    <Name>backend_username</Name>
    <Value>COMPANYDATAUSER_READONLY</Value>
  </AssignVariable>
  <AssignVariable>
    <Name>backend_password</Name>
    <Value>*********</Value>
  </AssignVariable>
  <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
  <AssignTo createNew="false" type="request"></AssignTo>
</AssignMessage>

gefolgt von einer "Basic Authentication"-Policy:

<BasicAuthentication async="true" continueOnError="false" enabled="true" xmlns="http://www.sap.com/apimgmt">
  <Operation>Encode</Operation>
  <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
  <User ref='backend_username'></User>
  <Password ref='backend_password'></Password>
  <AssignTo createNew="false">request.header.Authorization</AssignTo>
</BasicAuthentication>

Im Proxy-Endpoint wurden einige Conditional-Flows automatisch generiert. Diese replizieren wir für den Target-Endpoint. Dies ist nötig da einige interne Variablen beim Sprung vom Proxy-Endpoint auf den Target-Endpoint zurückgesetzt werden.

In diese Conditional-Flows fügen wir nun Policies zum extrahieren der Variablen ein und gegebenenfalls zum umschreiben der URL für einen gültigen OData-Call. Für das Beispiel /companies/{CompanyId} sähe das folgendermaßen aus:

Zunächst fügen wir eine "Extract Variables"-Policy auf den Incoming-Request-Stream ein mit:

<ExtractVariables async="true" continueOnError="false" enabled="true" xmlns="http://www.sap.com/apimgmt">
  <URIPath>
    <Pattern ignoreCase="true">/companies/{CompanyId}</Pattern>
    <Pattern ignoreCase="true">/companies/{CompanyId}/</Pattern>
  </URIPath>
  <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
</ExtractVariables>

gefolgt von einer Javascript-Policy:

<Javascript async="false" continueOnError="false" enabled="true" timeLimit="200" xmlns="http://www.sap.com/apimgmt">
  <ResourceURL>jsc://set_target_company_id.js</ResourceURL>
</Javascript>

mit der dazugehörigen Script-Datei set_target_company_id.js:

var target_schemehostport = "https://hanapXXXXXXXXXXtrial.hanatrial.ondemand.com";
var target_basepath = context.getVariable("target.basepath");

var company_id = context.getVariable("CompanyId");

var target_base = target_schemehostport + target_basepath;
var target_url = target_base + "/companies(" + decodeURI(company_id) + ")";

context.setVariable("target.url", encodeURI(target_url));

API Testen

Bevor die API getestet werden, muss sie noch Veröffentlicht werden. Im API-Portal muss ein Produkt erstellt werden, welches diese API beinhaltet. Den API-Key erhält man durch erstellen einer Applikation im Developer Portal, welche dieses Produkt abonniert.

Nun kann die API mit folgendem Befehl getestet werden:

$ curl -sH "APIKey: *********" https://pXXXXXXXXXXtrialtrial.apim1.hanatrial.ondemand.com/p2000572343trial/companydata/v1/companies/0 |xmllint --format -
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<entry xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom" xml:base="https://hanapXXXXXXXXXXtrial.hanatrial.ondemand.com:443/companydata/CompanyData.xsodata/">
  <id>https://hanapXXXXXXXXXXtrial.hanatrial.ondemand.com:443/companydata/CompanyData.xsodata/companies(0)</id>
  <title type="text"/>
  <author>
    <name/>
  </author>
  <link rel="edit" title="companies" href="companies(0)"/>
  <category term="companydata.companiesType" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"/>
  <content type="application/xml">
    <m:properties>
      <d:id m:type="Edm.Int32">0</d:id>
      <d:key m:type="Edm.String">SMTH</d:key>
      <d:long_name m:type="Edm.String">Smith Craftings LLC</d:long_name>
      <d:short_name m:type="Edm.String">SmithCraft</d:short_name>
    </m:properties>
  </content>
</entry>

Schlusswort

Das war die Blog-Serie zu einem vollständigen API-Management Szenario in der SAP HANA XS. Die Daten können nun von außen aus über die API-Schnittstelle zugegriffen werden. Ein nächster Schritt wäre zum Beispiel, diese Daten über ein SAPUI5-Interface abrufbar zu machen.

Zurück zur Übersicht