Integration modelling: Implement Rest Integration
Implement REST Integration Servicesâ
REST integration services are used to integrate an external API with the current project.
The generated methods described on this page can be either triggered by a REST integration service or a domain service.
An external API could be integrated by adding the specification as an API dependency or not.
Make external requests against an API with provided API specificationâ
In case that there is the API specification of the external service provided, utility methods are auto generated that help to easier consume the API.
Below is an example of the implementation of integration against an email
API, which provides a POST method postEmail
for sending mails:
// 1. Accessing types from API dependency where
// - integrationSchema is a grouping for all api dependencies schemas
// - emailSchema is a grouping for schemas in integration namespace with acronym "email"
// - EmailMessage schema we want to get its type
import { services, integrationSchema } from 'solution-framework';
export default class extends services.email_SendMail {
public async execute(): Promise<void> {
const requestBody: integrationSchema.emailSchema.EmailMessage= {
to: [
{
adress: 'some address'
}
],
subject: `Order Confirmation of Order #12345`,
sender: 'some@sender.com',
message: 'Some message',
messageFormat: 'HTML'
};
// 1. Calling api dependency operation and getting response body
const responseBody = (await this.apis.email.postEmail(requestBody)).data;
// 2. Also we have full access to response returned as a result of an underlying axios call
const axiosResponse = await this.apis.email.postEmail(requestBody);
// Getting response body
const responseBody = axiosResponse.data;
// Getting response headers
const headers = axiosResponse.headers;
// Getting response status
const statusCode = axiosResponse.status;
//3. Another variation
const {headers, data, status} = await this.apis.email.postEmail(requestBody);
// further logic on handling response
// ...
};
}
If your API dependency's API binding already contains ca_cert
value, then this ca_cert
value will be implicitly
used to make external API facade operation calls.
Typesafety when making API requestsâ
To easier consume the external APIs, additional interfaces and types are provided in the SDK.
IntegrationSchemaâ
The integrationSchema
interface exists only when at least integration namespace exists. It holds all schemas related to every integration namespace.
// define variable from integration schema
let myIntegrationSchemaVar:integrationSchema.namespaceSchema.schema;
myIntegrationSchemaVar.prop1 = 'prop 1 value'
Requestâ
The request object holds (query, path and body) for every operation inside an API dependency.
import { Request } from 'solution-framework;
// define variable from addDate operation query
let myQueryVar:Request.AddDateQuery;
myQueryVar.prop1 = 'prop 1 value'
// define variable from addDate operation path
let myPathVar:Request.AddDatePath;
myPathVar.prop1 = 'prop 1 value'
// define variable from addDate operation body
let myBodyVar:Request.AddDateBody;
myBodyVar.prop1 = 'prop 1 value'
// define variable from addDate operation request
let myRequestVar:Request.AddDateRequest;
myRequestVar.prop1 = 'prop 1 value'
// _request of type http request
myRequestVar._request
Responseâ
The response object (body, statusCode) for every operation inside an API dependency.
import { Response } from 'solution-framework;
// define variable from addDate operation statusCode type
const myAddDateStatusCode: Response.AddDateStatusCode = 201;
// myAddDateStatusCode variable now accept values from addDate operation statusCode only
// define variable from addDate operation schema type
// schema1 can represent for example schema for response status code 200;
const myAddDateSchema1: Response.AddDateSchema.schema1;
// schema2 can represent for example schema for response status code 404;
const myAddDateSchema2: Response.AddDateSchema.schema2;
// define variable from addDate operation body
// myAddDateBody value can be either myAddDateSchema1 or myAddDateSchema2
const myAddDateBody: Response.AddDateBody;
// define variable from addDate operation response type
const myAddDateResponse: Response.AddDateResponse;
myAddDateResponse.body = myAddDateBody;
myAddDateResponse.statusCode = myAddDateStatusCode;
Schemaâ
The schema object holds all schemas inside an API dependency.
import { Schema } from 'solution-framework;
// define variable from api dependency schema
let mySchemaVar: Schema.Schema1;
mySchemaVar.prop1 = 'prop 1 value';
Make external requests using request utilityâ
When creating external calls to APIs you can retrieve the API binding option and if it contains a ca_cert property, you can use it to construct an SSLConfig object that can be used when making external API calls.
public async execute(): Promise<void> {
// get binding of petstore API
const apiBinding = await this.apiBindings.getPetstore();
// make the request using the custom ca_cert defined in the api binding
await this.util.request.get('www.something.com', {param1: 'val'}, {header1: 'val'}, { ca_cert: bind.ca_cert});
}
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)!
Access API bindingsâ
API bindings are externalized specifications created per API dependency. They can be used to store API-related configuration information, that may be stage-dependent.
API bindings are typically used to store, e.g.
- url
- username
- password
- API-Key
- ... for the 3rd party service you want to access.
Example binding:
{
"url": "http://example.com/dev"
}
DEV-Bindingsâ
Dev-Bindings provide an easy way to specify some default values, which are easily accessible on all non-production stages. They are meant to be used for rapid development to avoid long and extensive configuration outside of the project.
DEV-Binding can be created and speciified inside the Solution. To do so, you go to the Integration Namespace you want ot use for interacting with this API (or create a new namespace) and create an API dependency. There you will find an input field where you can place your information as JSON formatted key/value pairs.
Please be aware, that all information entered into DEV bindings will go into the Git repository! To prevent this, you can instead create an API binding for the same purpose, since they get stored as OpenShift secrets inside the cluster.
Programmatically access the bindingâ
Now that you created an API dependency for this namespace with an API dependency attached to it, you have access to this information while implementing this namespace. After you deployed your solution to a project you can log in to this project with the Solution CLI. The SDK now provides you with the information by calling
// load the bindings
const mybindings = await this.apiBindings.<name-of-the-api-dependency>();
// load binding value
const url = mybindings.url;
inside an implementation file (e.g. of a service) inside that Integration Namespace. This would assign the
value http://example.com/dev
to url
.
Currently, only the following default parameters can be accessed with this syntax:
url
ca_cert
k5_propagate_security_token
If you want to use custom parameters, you can access them as follows:
const myparam = mybindings['myparam'];
Trigger REST Integration Servicesâ
The generated SDK provides functions to easily trigger integration services from other places in the service.
Input and output entityâ
When triggering an integration service, it might be necessary to provide an input entity. The Entity factory can be used to create new input entities, which could be set as input parameter for the service.
If there is an output defined for the integration service, it is returned as a result and can be used for further processing.
Trigger integration serviceâ
The following code shows how to trigger a integration service, for example from another service implementation.
// Initialize service input via factory and assign value to input properties
const input = this.factory.entity.nsacrnm.ServiceIdentifier_Input();
input.property1 = 'Some property value';
// Trigger a domain service
const output = await this.services.nsacrnm.ServiceIdentifier(input);
// Access service output
const val = output.propIdentifier;