Motivation and Introduction:
Rest Services are very popular and widely used. But Rest is only a programming paradigm and or an architectural approach as such it doesn’t set up any contract how services are offered, and which format the payload will have finally.
To address this contract there are a lot of service descriptions available meanwhile. You can have a look on how many there are at wikipedia. The ones I came accross the last years very frequently are oData and openApi.
SAP Netweaver comes with great support of oData and as both service descriptions have the same paradigm (Rest) underneath the differences between oData and openApi are not that great as one maybe think about.
Although it’s possible to write Restful Services with ABAP with some framework classes of package SREST you won’t have the service infrastructure of SAP Netweaver Gateway at hand and nonfunctional requirements, like technical error logging and tracing capabilities become crucial with distributed applications.
The OASIS group is maintaining a toolset to generate an openApi description from oData service description document.
https://github.com/oasis-tcs/odata-openapi
Here I’d like to dive into that and see how to build a simple java client from such an openApi description which transparently accesses an oData service. That becomes especially interesting with oData v4, as the payload is ‘plain json’ there. So we’ve a good chance to see that working and leverage the SAP Netweaver Gateway features for openApi services built on the ABAP stack.
In order to do that we will:
1. Build and deploy a simple v4 oData service
2. Download and install the toolset to generate the openApi description
3. Generate the openApi description the oData services description
4. Download and build the swagger code generator
5. Generate and install the openapi client from the openApi description
6. Build and run a simple java program which uses the openapi client generated.
Prerequisites:
To follow the steps here the following software need to be available/installed:
◈ Nodejs
◈ Git SCM
◈ JDK (here 1.8)
◈ Apache Maven
◈ SAP Netweaver ABAP 750 SP4
Build and Deploy a simple v4 oData service
Go to Transaction “SEGW” and click “New” button to create a new service
Create the project with the settings shown at the screenshot. Especially choose Project type “OData 4.0 Service” and store as local object.
Expand the node „Data Model“ double click on Entity Types, press the New button on the right pane, enter Entity Type Name „contractType“ and press enter.
1. Expand the node „contractType“, double click on properties
2. Press the New button two times.
3. Set the first properties name to „contractId“, check the checkbox for „Key“, select type kind to „Core Type“ and choose data type „Edm.String“
4. Set the second properties name to „contractName“, select „type kind to „Core Type“ and choose data type „Edm.String“
5. Press „Save“
Double click on entity sets, press the new button on the right pane, set entity set name to „contract“ and entity type name to „contractType“, press enter and save
Press Generate
Leave the class names as provided and save as local object in the next dialogs.
1. Expand the runtime artifacts
2. Double click on „ZCL_ZTEST_SERVICE_V4_DPC_EXT“
3. And double click on „ZCL_ZTEST_SERVICE_V4_DPC_EXT“ on the right pane in order to open the class editor.
Add the following method to ZCL_ZTEST_SERVICE_V4_DPC_EXT
method GET_CONTRACT_SAMPLE_DATA.
clear ET_CONTRACTS.
APPEND INITIAL LINE TO ET_CONTRACTS ASSIGNING FIELD-SYMBOL(<fs_contract>).
<fs_contract>-CONTRACTID = 1.
<fs_contract>-CONTRACTNAME = 'Sample contract 1'.
APPEND INITIAL LINE TO ET_CONTRACTS ASSIGNING <fs_contract>.
<fs_contract>-CONTRACTID = 2.
<fs_contract>-CONTRACTNAME = 'Other contract'.
APPEND INITIAL LINE TO ET_CONTRACTS ASSIGNING <fs_contract>.
<fs_contract>-CONTRACTID = 3.
<fs_contract>-CONTRACTNAME = 'Test contract '.
APPEND INITIAL LINE TO ET_CONTRACTS ASSIGNING <fs_contract>.
<fs_contract>-CONTRACTID = 4.
<fs_contract>-CONTRACTNAME = 'Special contract'.
APPEND INITIAL LINE TO ET_CONTRACTS ASSIGNING <fs_contract>.
<fs_contract>-CONTRACTID = 5.
<fs_contract>-CONTRACTNAME = 'Final contract'.
endmethod.
Redefine the method CONTRACT_READ_LIST as follows:
method CONTRACT_READ_LIST.
**TRY.
*CALL METHOD SUPER->CONTRACT_READ_LIST
* EXPORTING
* IO_REQUEST =
* IO_RESPONSE =
* .
** CATCH /IWBEP/CX_GATEWAY .
**ENDTRY.
GET_CONTRACT_SAMPLE_DATA(
importing
ET_CONTRACTS = data(lt_contracts)
).
IO_RESPONSE->SET_BUSI_DATA( IT_BUSI_DATA = lt_contracts ).
* catch /IWBEP/CX_GATEWAY. "
data:
ls_proc_info type /IWBEP/IF_V4_REQU_BASIC_CREATE=>TY_S_TODO_LIST.
LS_PROC_INFO-PROCESS-BUSI_DATA = abap_true.
IO_RESPONSE->SET_IS_DONE( IS_TODO_LIST = VALUE #( ) ).
endmethod.
Goto Transaction /IWBEP/V4_ADMIN
Click on Register Group
Create a service group with the following settings:
Service Group: ZTEST_SERVICE_V4
Description: Odata V4 Sample Services
Package: $TMP
Click on register
Register the service as shown in the screenshot
Finally you should see the Service we’ve created assigned to the service group we’ve created.
Goto Transaction /IWFND/V4_ADMIN
Click on “Publish Service Groups”
Choose System alias „LOCAL“ and press button „Get Service Groups“
Select the Service Group „ZTEST_SERVICE_V4“ (the group we’ve created) and press „Publish Service Groups“
Leave the settings as they are at the „Publish Service Group“ dialog and click „Ok“. Then create a new transport request an save the settings.
You should see a success message.
Go back to /IWBEP/V4_ADMIN find the service group and select the service and press the button „Service Test“
Choose local gateway system
Now you see the Gateway Client with the metadata url. Press „Execute“ to retrieve the services metadata.
Now we’ve the oData Service description document. Right click in the browser and save it as „odata_v4_service_description.xml“
Additionally we can do some testing. Use the url „/sap/opu/odata4/sap/ztest_service_v4/default/sap/ztest_v4_service/0001/contract“ and Execute
So we see the sample data we’ve provided at the mock data method.
For now, we’ve our oData v4 Test Service and the according service description document. So we can go on to translate the oData Service description to a openApi description.
Download and install the toolset to generate the openApi description
Here we will install the toolset from https://github.com/oasis-tcs/odata-openapi
Open a command window go to a directory of you choice to download/clone the toolset from github:
C:\user\project> git clone https://github.com/oasis-tcs/odata-openapi.git
Cloning into 'odata-openapi'...
remote: Enumerating objects: 206, done.
remote: Counting objects: 100% (206/206), done.
remote: Compressing objects: 100% (82/82), done.
remote: Total 4291 (delta 157), reused 164 (delta 120), pack-reused 4085
Receiving objects: 100% (4291/4291), 6.50 MiB | 28.68 MiB/s, done.
Resolving deltas: 100% (3613/3613), done.
As the toolset is cloned to you local repository change into the odata-openapi subfolder an use npm to install the tool locally:
C:\user\project>cd odata-openapi
C:\user\project\odata-openapi> npm install -g
C:\Users\Administrator\AppData\Roaming\npm\odata-openapi3 -> C:\Users\Administrator\AppData\Roaming\npm\node_modules\oda
ta-openapi\lib\cli.js
+ odata-openapi@0.0.0
added 4 packages from 2 contributors in 1.819s
PS C:\user\project\odata-openapi>
With that we have the toolset installed locally and we can continue and create the openApi specification from the oData Service description.
Generate the openApi description the oData services description
Now give the the oData v4 service description document to the tool odata-openapi3 in order to generate the openApi specification from.
C:\user\project\oDataServiceAsOpenApi> odata-openapi3 --host hostname:port .\odata_v4_service_description.xml
Hint: You can get the hostname from Transaction SICF when searching for service „odata4“ and test the service. You see the host and port at the browser then.
The tool created a file „odata_v4_service_description.openapi3.json“
Open this file in an editor copy the content and go to https://editor.swagger.io/ and paste the files content into the editor pane:
Now we see the v4 oData service described by an openApi description
In order to support at least basic authentication with the java client we will generate apply security settings manually at the openApi specification in the swagger editor. I converted to YAML for convenience.
add the following to the components section:
securitySchemes:
basicAuth: # <-- arbitrary name for the security scheme
type: http
scheme: basic
and the following security constraint at the end of file so it’s used for the whole service:
security:
- basicAuth: [basicAuth] # <-- use the same name here
After the security configuration it’s also necessary to care about the service-root path at the service description. So change the following default …/service-root:
to the actual path of our oData service:
Save the modified openApi specification in order to use it later to generate the java client.
Download and build the swagger code generator
To generate the java client from the openApi specification we will next download and build the swagger code generator tool.
Go to a directory of your choice and clone the repository of the swagger code generator:
git clone https://github.com/swagger-api/swagger-codegen.git
Change into the subfolder swagger-codegen and checkout the version 3.0.9
cd swagger-codegen
git checkout tags/v3.0.9
When checkout is finished start building and packaging with maven
mvn clean package -DskipTests
Building swagger-codegen can take a while, at the you should see a message that the Build was successful. Now we’re ready to generate the java client using the code generator.
Generate and install the openapi client from the openApi description
Although that’s not the best practice we’ll use the generator from its project folder (swagger-codegen) and place the files and output folders there to keep things simple.
To create the java client we create a java-config.json file in the swagger-codegen project folder with the following content:
{
"modelPackage" : "com.sample.test.model",
"apiPackage" : "com.sample.test.api",
"invokerPackage" : "com.sample.test.client",
"groupId" : "com.sample.test",
"artifactId" : "sample-openapi-client",
"fullJavaUtil" : true,
"dateLibrary" : "java8"
}
We also copy the modified openApi specification into that folder. Here I renamed the file to odata-v4-service-description.openapi.yaml
It’s also necessary to create the empty output folder where the java client is generated to:
mkdir java-sample-client
Then we can call the code generator using the following command:
java -jar .\modules\swagger-codegen-cli\target\swagger-codegen-cli.jar
generate -i odata-v4-service-description.openapi.yaml
-l java -c .\java-config.json -o java-sample-client
After that we can see the generated client at the subfolder java-sample-client
To build and install the client to the repository go into this folder and use:
mvn clean install
After that you should see a success message:
As we’ve now created the client and installed it we can now write a program which uses this client to access the oData Rest service running on our abap netweaver.
Build and run a simple java programm which uses the openapi client generated
To create the test program here eclipse with M2Eclipse is used to make usage of maven as simple as possible.
Start eclipse and create a new Project:
Choose Maven project to create a new Maven project.
Check to create a simple project without archetype selection and press next.
Choose your attributes for the artifact and press finish.
Find the pom.xml in the project and add the dependency to the client we generated:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test</groupId>
<artifactId>openapi-test-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>OpenApi Test Client</name>
<description>OpenApi Test Client</description>
<dependencies>
<dependency>
<groupId>com.sample.test</groupId>
<artifactId>sample-openapi-client</artifactId>
<version>LATEST</version>
</dependency>
</dependencies>
</project>
Hint: The group id “com.sample.test” and the artifact-id “sample-openapi-client” are the ones we’ve set at the java-client.json configuration we used to generate the client
Use Maven->Update Project to work with the latest repository status
Next create a class with Test program:
package test;
import com.sample.test.api.ContractApi;
import com.sample.test.client.ApiClient;
import com.sample.test.client.ApiException;
import com.sample.test.model.CollectionOfContractType;
public class SampleClient {
public static void main(String[] args) throws ApiException {
ContractApi api = new ContractApi();
ApiClient apiClient = new ApiClient();
apiClient.setUsername("YOURUSERNAME);
apiClient.setPassword("**********");
api.setApiClient(apiClient);
CollectionOfContractType list =
api.contractGet();
System.out.println(list);
}
}
Replace username and password.
Use maven to build the test program.
Choose the goals “clean package” and run the build.
After successful build run the sample client class as Java Application
Now we can see the mock data we’ve provided in our oData Service retrieved from a java program. The access is transparently. The java client uses openApi standards only and doesn’t need to be aware of the oData implementation behind the scenes.
No comments:
Post a Comment