API dependencies

Introduction

The main purpose of an API dependency is to easily call an external REST API. It consists of the two steps:

Creating an API dependency is not required to call a REST API. It is just a convenience functionality that you can use to make implementation easier. You can use the native capabilities to make HTTP calls too. Even if you create an API dependency you don't have to use all the capabilities. You can upload an API specification to get all the defined operations generated in the SDK or only use a DEV binding to store your own key/value pairs outside the implementation code and replace these values later for different deployment targets with API bindings.

Tip:

If you want to integrate an API that is provided by another project that has also been deployed with IBM Industry Solutions Workbench, you can instead use the Local Lookup function.

Solution Designer will create methods for each operation available in the API specification. These methods can be used while implementing integration services. The uploaded API specification will be placed inside the Git repository of the service project and is available to the developer while implementation.

Create an API dependency

There are two methods to create an API Dependency:

  1. Uploading API specification file. By uploading an API specification either as OpenAPI 3 file (.yaml) or as Swagger 2.0 file (.json).

  2. Importing API specification from an existing service project. Choosing an API from an existing service project.

    Note: Only Domain Service Projects are available to import from.

Uploading specification file

To create an API dependency in Solution Designer, open an integration namespace of your service project and click on the "Dependency" tab and then click on "Add API dependency" button. Kindly fill in the required information as described below:

PropertyDescription
NameThis is the name of the API dependency. It is unique within an Integration Namespace. Please note that only the characters A-Za-z (without special characters), digits and the special character "_" are permitted for naming API dependency! Furthermore, names may not begin with a digit and the first character must be lowercase. This field is mandatory.
API specificationThis is the specification of the API that is being integrated and it has two options: 1. "Upload specification file" for uploading specification file it shows an upload button when selected. The expected formats are JSON and YAML. The uploaded specification is later shown on the instance page of the API dependency. Please notice, that SWAGGER specifications will always be converted to a OpenAPI 3 specification while uploading the file. In all cases the file will have the suffix .yaml. This field has two values 2. "Choose from existing project" to import API dependency from another existing project, it also takes you through wizard steps to select API Namespace to import. This field is optional.
DEV bindingA binding always consists of a JSON string that may also include a URL (as specified in OpenAPI 3). This field is optional.
Local lookupBy using this option no additional binding information is necessary. The URL of the dependency will be changed dynamically depending on the deployment namespace. Also, the JSON Web Token (JWT) will be forwarded and used to call the API dependency. This field is optional.

After creating an API dependency, you will be able to view all the details of the API dependency in the sidebar's API dependency details card. In case an API specification has been added to the API dependency, the General tab will show the API spec in a colored graphical view. You can switch to the detailed swagger view by clicking on the script button (left of trash button). You can use the search bar to filter by methods, tags and description.

Warning:

From IBM Industry Solutions Workbench 3.1, a user will only be able to have one API dependency for an integration namespace. For every new API dependency, a new Integration namespace has to be created.

Warning:

User's using IBM Industry Solutions Workbench 3.0 and prior, only the first API Dependency for the integration namespace will be shown in the General tab and a warning message will be popped up on the right side (above the Integration namespace details section). For seamless use, please follow the migrations steps to migrate the old API dependencies into new Integration Namespaces.

Import from another service project

To create an API dependency based on another existing project, first you need to make sure that the modeled API you want to import is already committed to your repository then follow the following steps:

  1. Fill in the 'Main Data' step and select "Choose from existing project" in "API Specification" field and click on button "Next".
  2. In "Select Service Project" step you can see and select service project you want to import the API specification from. Note: Only Domain Service Projects are available to select.
  3. In the step "Select API" you can see and select one of the modeled APIs of the choosen service project. Note: If the choosen service project contains only one modeled API, this is selected automatically and you will be guided to the next step.
  4. The last step is "View API" step, and it displays the operations available of the selected API. And finally click on "Create" button to add the API as dependency to your Integration Namespace.

Edit an API dependency

You can edit the master data of an API dependency by using the Update API dependency button. The name of the API dependency cannot be changed. When editing the master data of an API dependency, you can update the Name, API specification, DEV binding and Local lookup.

Delete an API dependency

You can delete the API dependency by clicking on the trash button (left of Update API dependency button) in the General tab.

You will need to confirm the action before the selected API dependency is permanently deleted.

Configuring API Dependencies

To call an API Dependency some additional configurations (API bindings) are needed. Those API bindings are normaly externalized and managed per stage via Configuration Management. For development purposes IBM Industry Solutions Workbench allows to work with a development configuration, a so called DEV Binding or, for the interaction between service deployments that have been built with IBM Industry Solutions Workbench, to use a so called Local Look Up.

DEV binding

DEV bindings are optional specifications created per API dependency. This means that the DEV binding only lives as a part of the API dependency and shares its life-cycle. It is assigned a unique name internally and will not receive an identifier within Solution Designer.

You can use DEV bindings to append important information about the API you want to integrate and store it inside the integration namespace. This may be URLs, certificates, token, credentials or anything else that you want to have at hand when implementing your requests to another REST API. These bindings only consist of key/value pairs in JSON notation.

Note:

Please be aware, that everybody with read access to your project can see this information! Furthermore, the DEV binding will also be stored in the Git repository that holds this service project.

Usage of DEV bindings

There are two different scenarios to provide binding information, either

  • for a single-deployed microservice
  • for a component of an application composition project
Usage in single-deployed microservices

In case you work on a service project that should get deployed directly to a deployment target (e.g. for testing purposes) you can use the DEV binding if this microservice should call an external API. Here you could provide info like the URL of this external API or a required API token to access this API.

The DEV binding will be applied to all deployments of this service project on deployment targets that have enabled the usage of DEV bindings. For deployment targets that don't allow their usage, you will have to provide an API binding with identical content. With API bindings you can provide individual values for each provided key to match the requirements of each deployment target.

If a service project has a DEV binding and also an API binding for a deployment target, the API binding will have precedence over the DEV binding on that particular deployment target.

Warning:

If you need to provide sensitive or confidential data, we recommend using an API binding instead. While DEV bindings get stored in the Git repository, API bindings get stored as OpenShift secrets.

Usage for components in application projects

In case you work on a service project that should get released to the Component Repository (in order to use it as component) and you need to provide binding information, you have to use the DEV binding.

Note:

The information provided will be published to the resulting Helm chart when you release the project. This process only uses the provided keys and ignores all values! So we recommend providing only the required keys in the DEV binding and leaving their values empty.

When someone adds this component to their application project(s), a new API binding will be generated for each deployment of the application and each binding will provide input fields to enter the values for each of the binding keys. This allows you to enter individual values for different applications and also for each deployment target. See API bindings for more details on API binding component configuration in application projects.

Local lookup

Can be used for API dependencies between microservices that also have been developed with IBM Industry Solutions Workbench and allows calling these dependencies without the need to provide additional binding information. This makes it easy and convenient to call operations provided by external APIs since the URL of the dependency will be changed dynamically and the JWT will be automatically forwarded.

Example

Example implementation:

You have a service project with an integration namespace called "Customer Need Registration". This integration namespace's acronym is cnr. Inside this namespace you have created an integration service called "AcceptOffer" and this service should call another API. To do so, you also created an API dependency with the name cnrdependency inside this integration namespace and uploaded a valid OpenAPI 3 or Swagger 2.0 file.

This API provides the operation "acceptOffer" (amongst others) that will be called in this example.

Now to implement this service you can do the following inside the implementation file of this service ( e.g., src-impl/integration/cnr/services/AcceptOffer.ts):

import { services } from 'solution-framework';

export default class extends services.cnr_AcceptOffer {

  public async execute(): Promise<void> {
    const log = this.util.log;
    log.debug('cnr_AcceptOffer.execute()');

    // Get the values for the request parameters from the input
    const {customerNeed_id, customer_ID, finPropId} = this.input;

    // Use the created API operations
    const response = await this.apis.cnrdependency.acceptOffer({customerNeed_id: customerNeed_id},{customerID_query: customer_ID,finPropId: finPropId});

...
Warning:

Whenever you are querying external services, you should make sure, that all communication to such services are encrypted and all TLS-encrypted protocols including HTTPS use version 1.2+. The connection to the target service should be authenticated (certificate validation should be enabled)!

Implementing with DEV bindings

Example of a binding:

{
  "url": "https://example.com",
  "k5_propagate_security_token": true
}

Entering this key/value pair into the DEV binding section of an API dependency will provide the value of url in the solution framework (SDK) when implementing. They will be accessible by typing this.apiBindings.<integration namespace acronym>. inside an implementation file of an integration namespace.

Example implementation:

You have a service project with an integration namespace called "Customer Need Registration". The integration namespace's acronym is "cnr". Inside this namespace you have created an integration service called "AcceptOffer" and this service should call another API. You also created an API dependency with the name "cnrdependency" inside this integration namespace and added the information to the DEV binding as stated in the example above.

Now to implement this service you can do the following inside the implementation file of this service ( e.g., src-impl/integration/cnr/services/AcceptOffer.ts):

import { services } from 'solution-framework';

export default class extends services.cnr_AcceptOffer {

  public async execute(): Promise<void> {
    const log = this.util.log;
    log.debug('cnr_AcceptOffer.execute()');

    // Retrieve the API binding information (async call)
    const binding = await this.apiBindings.getcnrdependency();

    // Built-in parameters (url, ca_cert, k5_propagate_security_token) can be retrieved like this
    const url = binding.url;

    // the value of url will be 'https://example.com'

    ...

This will work for the following pre-defined parameters:

  • url - Used to pass the URL of the API to the SDK and can be overwritten with stage-dependent values by adding API bindings for the different stages.
  • k5_propagate_security_token - If set to true, the JSON Web Token (JWT) used in your service project will be forwarded to call the API dependency.
  • ca_cert - By using this option no additional binding information is necessary. The URL of the dependency will be changed dynamically depending on the deployment namespace. Also, the JSON Web Token (JWT) will be forwarded and used to call the API dependency. This option should only be used for API dependencies that have been designed and implemented with IBM Industry Solutions Workbench and are deployed within the same projects/namespaces.
Warning:

The line length of the certificates must comply with the standard for PEM messages, with each line containing exactly 64 printable characters except the last line and 64 or fewer printable characters in the last line.

If you want to use your own custom parameters, you just have to add them to your DEV binding in the same manner.

{
  "my-custom-key": "A32k-9IFKl123",
  "another-key": 123456
}

The only difference is the way to call them:

...

    // Retrieve the API binding information (async call)
    const binding = await this.apiBindings.getCnrdependency();

    // Now call the binding parameter 'my-custom-key' like this
    const mycustomkey = binding['my-custom-key'];

...
Warning:

The PEM contents need to be given as single line json values with line breaks encoded with \n. It is necessary to give the full certificate chain from the root, optionally the leaf certificate can be omitted. In case of error due to dev binding, please make sure the ca_cert is created properly.

Tip:

You can find detailed information on how to test and debug your project involving these bindings. See Testing and debugging for TypeScript projects or Develop Java locally for Java projects.