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.
Porgrammatically 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'];