Onboarding a REST API service with the Plain Java Enabler (PJE)
Onboarding a REST API service with the Plain Java Enabler (PJE)
This article is part of a series of onboarding guides, which outline the process of onboarding REST API services to the Zowe API Mediation Layer (API ML). As a service developer, you can onboard a REST service with the API ML with the Zowe API Mediation Layer using our Plain Java Enabler (PJE). This enabler is built without a dependency on Spring Cloud, Spring Boot, or SpringFramework.
Tip: For more information about onboarding API services with the API ML, see the Onboarding Overview.
Introduction
Zowe API ML is a lightweight API management system based on the following Netflix components:
- Eureka - a discovery service used for services registration and discovery
- Zuul - reverse proxy / API Gateway
- Ribbon - load balancer
The API ML Discovery Service component uses Netflix/Eureka as a REST services registry. Eureka endpoints are used to register a service with the API ML Discovery Service.
The API ML provides onboarding enabler libraries. The libraries are JAR artifacts available through an artifactory. Using these libraries is the recommended approach to onboard a REST service with the API ML.
The PJE library serves the needs of Java developers who are not using either Spring Boot or the Spring Framework. If Spring Boot or the Spring framework are used in the project you would like to onboard, see the Onboarding Overview for the corresponding enablers.
Additionally, this enabler is not intended for use in projects that depend on Spring Cloud Netflix components. Configuration settings in the PJE and Spring Cloud Netflix Eureka Client are different. Using the two configuration settings in combination makes the result state of the discovery registry unpredictable.
Tip: For more information about how to utilize another API ML enablers, see the documentation in the Onboarding Overview.
Onboarding your REST service with API ML
The following steps outline the overall process to onboard a REST service with the API ML using the PJE. Each step is described in further detail in this article.
-
(Optional) Validating the discoverability of your API service by the Discovery Service
-
(Optional) Troubleshooting
Prerequisites
Ensure that the prerequisites from the Onboarding Overview are met.
- The REST API service to onboard is written in Java
- The service is enabled to communicate with API ML Discovery Service over a TLS v1.2 secured connection
Notes:
-
This documentation is valid for API ML version
ZoweApimlVersion 1.3.0
and higher. We recommend that you check the Zowe Artifactory for latest stable versions. -
Following this guide enables REST services to be deployed on a z/OS environment. Deployment to a z/OS environment, however, is not required. As such, you can first develop on a local machine before you deploy on z/OS.
-
The API Mediation Layer provides the sample application using the Plain Java Enabler in the api-layer repository
Configuring your project
Use either Gradle or Maven build automation systems to configure the project with the service to be onboarded. Use the appropriate configuration procedure that corresponds to your build automation system.
Note: You can use either the Zowe Artifactory or an artifactory of your choice. If you decide to build the API ML from source, you are required to publish the enabler artifact to your artifactory. Publish the enabler artifact by using the Gradle tasks provided in the source code.
Gradle build automation system
Use the following procedure to use Gradle as your build automation system.
Follow these steps:
-
Create a
gradle.properties
file in the root of your project if one does not already exist. -
In the
gradle.properties
file, set the URL of the specific artifactory containing the PJE artifact. Provide the corresponding credentials to gain access to the Maven repository.# Repository URL for getting the enabler-java artifact
artifactoryMavenRepo=https://zowe.jfrog.io/zowe/libs-release/ -
Add the following Gradle code block to the
repositories
section of yourbuild.gradle
file:repositories {
...
maven {
url artifactoryMavenRepo
}
} -
In the same
build.gradle
file, add the necessary dependencies for your service. If you use the Java enabler from the Zowe Artifactory, add the following code block to yourbuild.gradle
script. Replace the$zoweApimlVersion
with the proper version of the enabler, for example:1.3.0
:implementation "org.zowe.apiml.sdk:onboarding-enabler-java:$zoweApimlVersion"
implementation "org.zowe.apiml.sdk:common-service-core:$zoweApimlVersion"The published artifact from the Zowe Artifactory also contains the enabler dependencies from other software packages. If you are using an artifactory other than Zowe, add also the following dependencies in your service
build.gradle
script:implementation "com.netflix.eureka:eureka-client:1.10.15"
implementation "org.apache.httpcomponents:httpcore:4.4.14"
implementation "com.fasterxml.jackson.core:jackson-databind:2.11.4"
implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.9.10"
providedCompile "javax.servlet:javax.servlet-api:3.1.0"
compileOnly "org.projectlombok:lombok:1.18.20"Notes:
- You may need to add more dependencies as required by your service implementation.
- The information provided in this file is valid for
ZoweApimlVersion 1.3.0
and higher.
-
In your project home directory, run the
gradle clean build
command to build your project. Alternatively, you can rungradlew
to use the specific gradle version that is working with your project.
Maven build automation system
Use the following procedure if you use Maven as your build automation system.
Follow these steps:
-
Add the following XML tags within the newly created
pom.xml
file:<repositories>
<repository>
<id>libs-release</id>
<name>libs-release</name>
<url>https://zowe.jfrog.io/zowe/libs-release/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>Tip: If you want to use snapshot version, replace
libs-release
withlibs-snapshot
in the repository url and change snapshots->enabled totrue
. -
Add the proper dependencies:
<dependency>
<groupId>org.zowe.apiml.sdk</groupId>
<artifactId>onboarding-enabler-java</artifactId>
<version>$zoweApimlVersion</version>
</dependency>
<dependency>
<groupId>org.zowe.apiml.sdk</groupId>
<artifactId>common-service-core</artifactId>
<version>$zoweApimlVersion</version>
</dependency> -
In the directory of your project, run the
mvn clean package
command to build the project.
Configuring your service
To configure your service, create the configuration file service-configuration.yml
in your service source tree resources directory. The default path for a java application is src/main/resources
. The service-configuration.yml
file is used to set the application properties and eureka metadata. Application properties are for your service runtime. For example, the ssl
section specifies the keystore and trustore. The eureka metadata is used for registration with API Mediation Layer.
Note: To externalize service onboarding configuration, see: Externalizing onboarding configuration.
The following code snippet shows an example of service-configuration.yml
. Some parameters which are specific for your service deployment
are in ${parameterValue}
format. For your service configuration file, provide actual values or externalize your onboarding configuration.
Example:
serviceId: sampleservice
title: Hello API ML
description: Sample API ML REST Service
baseUrl: https://${samplehost}:${sampleport}/${sampleservice}
serviceIpAddress: ${sampleHostIpAddress}
preferIpAddress: false
homePageRelativeUrl: /application/home
statusPageRelativeUrl: /application/info
healthCheckRelativeUrl: /application/health
discoveryServiceUrls:
- https://${discoveryServiceHost1}:${discoveryServicePort1}/eureka
- https://${discoveryServiceHost2}:${discoveryServicePort2}/eureka
routes:
- gatewayUrl: api/v1
serviceUrl: /sampleservice/api/v1
authentication:
scheme: httpBasicPassTicket
applid: ZOWEAPPL
apiInfo:
- apiId: zowe.apiml.sampleservice
version: 1.0.0
gatewayUrl: api/v1
swaggerUrl: http://${sampleServiceSwaggerHost}:${sampleServiceSwaggerPort}/sampleservice/api-doc
doumentationUrl: http://
- apiId: zowe.apiml.sampleservice
version: 2.0.0
gatewayUrl: api/v2
swaggerUrl: http://${sampleServiceSwaggerHost}:${sampleServiceSwaggerPort}/sampleservice/api-doc?group=api-v2
documentationUrl: http://
defaultApi: true
catalog:
tile:
id: sampleservice
title: Hello API ML
description: Sample application to demonstrate exposing a REST API in the ZOWE API ML
version: 1.0.0
ssl:
enabled: true
verifySslCertificatesOfServices: true
protocol: TLSv1.2
keyAlias: localhost
keyPassword: password
keyStore: keystore/localhost.keystore.p12
keyStoreType: PKCS12
keyStorePassword: password
trustStore: keystore/localhost.truststore.p12
trustStoreType: PKCS12
trustStorePassword: password
Optional metadata section
The following snippet presents additional optional metadata that can be added.
Example:
customMetadata:
yourqualifier:
key1: value1
key2: value2
The onboarding configuration parameters are broken down into the following groups:
- REST service identification
- Administrative endpoints
- API info
- API routing information
- API catalog information
- Authentication parameters
- API security
- SAF Keyring configuration
- Eureka Discovery Service
- Custom Metadata
- Connection Timeout
REST service identification
-
serviceId
The
serviceId
uniquely identifies one or more instance of a microservice in the API ML and is used as part of the service URL path in the API ML Gateway address space. Additionally, the API ML Gateway uses theserviceId
for routing to the API service instances. When two API services use the sameserviceId
, the API Gateway considers the services as clones of each other. An incoming API request can be routed to either of them through utilized load balancing mechanism.Important! Ensure that the
serviceId
is set properly with the following considerations:- The same
servicedId
should only be set for multiple API service instances for API scalability. - The
servicedId
value must only contain lowercase alphanumeric characters. - The
servicedId
cannot contain more than 40 characters.
Example:
-
If the
serviceId
issampleservice
, the service URL in the API ML Gateway address space appears as the following path:https://gateway-host:gateway-port/sampleservice/api/v1/...
- The same
-
title
This parameter specifies the human readable name of the API service instance. This value is displayed in the API Catalog when a specific API service instance is selected. This parameter can be externalized and set by the customer system administrator.
Tip: We recommend that service developer provides a default value of the
title
. Use a title that describes the service instance so that the end user knows the specific purpose of the service instance. -
description
This parameter is a short description of the API service. This value is displayed in the API Catalog when a specific API service instance is selected. This parameter can be externalized and set by the customer system administrator.
Tip: Describe the service so that the end user understands the function of the service.
-
baseUrl
This parameter specifies the base URL for the following administrative endpoints:
- homePageRelativeUrl
- statusPageRelativeUrl
- healthCheckRelativeUrl
Use the following format to include your service name in the URL path:
protocol://host:port/servicename
Note: Ensure that the
baseUrl
does not end with a trailing/
. Inclusion of/
causes a malformed URL if any of the above administrative endpoints begin with a/
. It is expected that each administrative endpoint begins with a/
. Warnings will be logged if this recommendation is not followed. -
serviceIpAddress (Optional)
This parameter specifies the service IP address and can be provided by a system administrator in the externalized service configuration. If this parameter is not present in the configuration file or is not set as a service context parameter, it is resolved from the hostname part of the
baseUrl
. -
preferIpAddress (Optional)
Set the value of this parameter to
true
to advertise a service IP address instead of its hostname.
Administrative endpoints
The following snippet presents the format of the administrative endpoint properties:
homePageRelativeUrl:
statusPageRelativeUrl: /application/info
healthCheckRelativeUrl: /application/health
where:
-
homePageRelativeUrl
specifies the relative path to the home page of your service.
Start this path with
/
. If your service has no home page, leave this parameter blank.Examples:
homePageRelativeUrl:
This service has no home pagehomePageRelativeUrl: /
This service has a home page with URL${baseUrl}/
-
statusPageRelativeUrl
specifies the relative path to the status page of your service.
Start this path with
/
.Example:
statusPageRelativeUrl: /application/info
This results in the URL:
${baseUrl}/application/info
-
healthCheckRelativeUrl
specifies the relative path to the health check endpoint of your service.
Start this path with
/
.Example:
healthCheckRelativeUrl: /application/health
This results in the URL:
${baseUrl}/application/health
API info
REST services can provide multiple APIs. Add API info parameters for each API that your service wants to expose on the API ML.
The following snippet presents the information properties of a single API:
apiInfo:
- apiId: zowe.apiml.sampleservice
version: 1.0.0
gatewayUrl: api/v1
swaggerUrl: http://localhost:10021/sampleservice/api-doc
documentationUrl: http://your.service.documentation.url
defaultApi: true
codeSnippet:
- endpoint: /endpoint1
language: java
codeBlock: |
System.out.println("Greeting code snippet");
- endpoint: /endpoint2
language: javascript
codeBlock: |
console.log('hello');
where:
-
apiInfo.apiId
specifies the API identifier that is registered in the API ML installation. The API ID uniquely identifies the API in the API ML. The
apiId
can be used to locate the same APIs that are provided by different service instances. The API developer defines this ID. TheapiId
must be a string of up to 64 characters that uses lowercase alphanumeric characters and a dot:.
. -
apiInfo.version
specifies the api
version
. This parameter is used to correctly retrieve the API documentation according to requested version of the API. -
apiInfo.gatewayUrl
specifies the base path at the API Gateway where the API is available. Ensure that this value is the same path as the
gatewayUrl
value in theroutes
sections that apply to this API. -
apiInfo.swaggerUrl (Optional)
specifies the Http or Https address where the Swagger JSON document is available.
-
apiInfo.documentationUrl (Optional)
specifies the link to the external documentation. A link to the external documentation can be included along with the Swagger documentation.
-
apiInfo.defaultApi (Optional)
specifies that this API is the default one shown in the API Catalog. If no apiInfo fields have
defaultApi
set totrue
, the default API is the one with the highest APIversion
. -
apiInfo.codeSnippet (Optional)
specifies the customized code snippet for a specific endpoint (API operation). The snippet is displayed in the API Catalog under the specified operation, after executing the request using the Try it out functionality. When specifying this configuration, you need to provide the following parameters:
endpoint
The endpoint that represents the API operation of the customized snippetlanguage
The language of the snippetcodeBlock
The content of the snippet to be displayed in the API Catalog
API routing information
The API routing group provides the required routing information used by the API ML Gateway when routing incoming requests to the corresponding REST API service.
A single route can be used to direct REST calls to multiple resources or API endpoints. The route definition provides rules used by the API ML Gateway to rewrite the URL
in the Gateway address space. Currently, the routing information consists of two parameters per route: The gatewayUrl
and serviceUrl
. These two parameters together specify a rule for how the API service endpoints are mapped to the API Gateway endpoints.
The following snippet is an example of the API routing information properties.
Example:
routes:
- gatewayUrl: api
serviceUrl: /sampleservice-api
- gatewayUrl: api/v1
serviceUrl: /sampleservice-api/ver1
- gatewayUrl: api/v1/api-doc
serviceUrl: /sampleservice-api/api-doc
where:
-
routes
specifies the container element for the route.
-
routes.gatewayUrl
The
gatewayUrl
parameter specifies the portion of the gateway URL which is replaced by theserviceUrl
path part. -
routes.serviceUrl
The
serviceUrl
parameter provides a portion of the service instance URL path which replaces thegatewayUrl
part.
Examples:
-
is routed to:
https://gateway:10010/sampleservice/api
https://service:10015/sampleservice-api
- API major version 1:
is routed to:
https://gateway:10010/sampleservice/api/v1
https://service:10015/sampleservice-api/ver1
- APIs docs major version 1:
is routed to:
https://gateway:10010/sampleservice/api/v1/api-doc
https://service:10015/sampleservice-api/api-doc