Unit 14: Implement Integration Service
In this course you will learn how to implement services in integration namespaces and how to call the Rest API of another microservice using your local IDE.
Outlineâ
After implementing the domain namespace, we continue with coding within the integration namespace.
As explained in Unit 9: Design Service Integration, you can add an API dependency and define integration services that use this dependency to call operation from the referenced Rest API.
Furthermore, integration services can have an input and an output entity and are able to throw business errors.
The code generation provides a class with one function for each integration service that we can immediately use, so we can dive straight into writing our business logic.
In general, the implementation of an integration service may contain the following pieces:
- Retrieve the service input and map it to the request body of the referenced API operation.
- Execute the API operation. If something goes wrong or a condition is not met, throw a business error.
- Retrieve the response body of the API operation and map it to the output entity of the integration service.
- Return or assign the service output.
Contrary to the design of our Orders service, we will first go through the integration namespace before the API namespace in the implementation phase. Reason is that we will use the integration service in the API operation we will implement in an upcoming course.
But in general you are free to go through the implememtation in any order you prefer. Because the IBM DevOps Solution Workbench has already generated the classes and method signatures of commands, services etc, it will not restrict your coding in any way if you use them before you provided their implementation code.
Prerequisitesâ
- You have successfully completed Unit 10: Set up Project for Implementation.
- You have successfully completed Unit 9: Design Service Integration.
If you rather want to use this course as a starting point of your training, you can use a different asset where all courses for designing and the courses for implementing the domain namespace are already completed.
In this case - depending on the chosen implementation language - use either asset "Order_Java_Code_0.2" or "Order_TypeScript_Code_0.2" to create a new project and to continue your training.
You can look up how to create a new project from the Order assets in the Preparation section in the Course Introduction.
Exerciseâ
Estimated time: 10 minutes
Exercise goal: After completing this course you are able to use integration services for processing calls of API operations of other microservices.
Supported languages: Java and TypeScript
In this exercise we will implement the integration service PostMail.
It is responsible for sending a confirmation email via postMail API operation of the integrated Rest API in the SEMAIL service when a new customer order is created.
In general, we are able to modify the behavior of the API operation inside our integration service for our whole Order service.
But for our purposes, we will only forward the properties of the integration service input from to the request body of the called API operation.
Step 1: Implement the integration serviceâ
The functionality of our integration service will include the following parts:
- Use the input of our integration service to create a request body for the API method we want to call
- Call the operation
postMailof the SEMAIL service
- Java
- TypeScript
-
Open the file
/src/main/java/<package-name>/integration/email/service/PostMail.java.
You will see an auto-generated stub in which you can start your implementation.<package-name>: The package name of the Java project (e.g.com.knowis.orderjfinal)@Service("email_PostMail")
public class PostMail extends PostMailBase {
private static final Logger log = LoggerFactory.getLogger(PostMail.class);
public PostMail(IntegrationEntityBuilder entityBuilder) {
super(entityBuilder);
}
@NewSpan
@Override
public void execute(PostMailInput postMailInput) {
log.info("PostMail.execute()");
// TODO: Add your service implementation logic
}
} -
To reuse the Rest API of the SEMAIL service, we have to create a private field for a class called
EmailsApiEmail. Additionally we have to add a constructor parameter that is then assigned to the private field.private final EmailsApiEmail apiEmail;
public PostMail(
IntegrationEntityBuilder entityBuilder,
EmailsApiEmail apiEmail
) {
super(entityBuilder);
this.apiEmail = apiEmail;
}Please use the auto-import function of your IDE to import the missing classes (and repeat this for the following steps). If you are not very familiar with imports, go back to Course 11 - Step 3: Import missing Classes for detailed information on class imports. Furthermore, you are free to compare your current imports with the recommended list of imports at the end of this section. Therefore, click here.
-
After injecting the field, we will extend the
executemethod in the following steps. First, we will use the input of our integration service to create a request body for an API operation of the SEMAIL service.// Step 1: Create the request body for the API operation of the integrated service SEMAIL as an integration schema
EmailMessage emailMessage = new EmailMessage()
.messageFormat(EmailMessage.MessageFormatEnum.valueOf(postMailInput.getMessageFormat().name()))
.sender(postMailInput.getSender())
.addToItem(new EmailAddress().address(postMailInput.getTo()))
.subject(postMailInput.getSubject())
.message(postMailInput.getMessage());
if(postMailInput.getCc() != null) {
emailMessage.addCcItem(new EmailAddress().address(postMailInput.getCc()));
} -
Then we will execute the
postMailAPI operation with the request body. In case of an error, we will log its message.try {
// Step 2: Execute the API operation of the integrated service
this.apiEmail.postEmail(emailMessage, null);
} catch (Exception e) {
log.error("Failed to send email!", e);
}
The provided list supports you to compare your current imports with the recommended list, especially if your IDE complains about errors in the code at this stage of the course.
List of Imports - File PostMail.java
// Fundamental 1: Generated classes based on design
import com.knowis.orderjfinal.sdk.integration.email.email.model.EmailAddress;
import com.knowis.orderjfinal.sdk.integration.email.email.model.EmailMessage;
import com.knowis.orderjfinal.sdk.integration.email.email.provider.EmailsApiEmail;
import com.knowis.orderjfinal.sdk.integration.email.service.PostMailBase;
import com.knowis.orderjfinal.sdk.integration.facade.IntegrationEntityBuilder;
// Fundamental 3: Built-in Java classes
import io.micrometer.tracing.annotation.NewSpan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
The package name of the provided code is com.knowis.orderjfinal. All occurrences of this phrase have to be replaced with the package name of your project.
-
Open the file
/src-impl/integration/email/services/PostMail.ts.
You will see an auto-generated stub with a methodexecutein which we will provide the implementation of the domain service.export default class extends services.email_PostMail {
public async execute(): Promise<void> {
const log = this.util.log;
log.debug('email_PostMail.execute()');
}
} -
First, we will use the input of our integration service to create a request body for an API operation of the SEMAIL service.
// Step 1: Create the request body for the API operation of the integrated service SEMAIL as an integration schema
const emailMessage: integrationSchema.emailSchema.EmailMessage = {
to: [{ address: this.input.to }],
cc: this.input.cc ? [{ address: this.input.cc }] : null,
subject: this.input.subject,
message: this.input.message,
messageFormat: this.input.messageFormat,
sender: this.input.sender
}Please use the auto-import function of your IDE to import the missing classes (and repeat this for the following steps). If you are not very familiar with imports, go back to Course 11 - Step 3: Import missing Classes for detailed information on class imports. Furthermore, you are free to compare your current imports with the recommended list of imports at the end of this section. Therefore, click here.
-
Then we will execute the
postMailAPI operation with the request body. In case of an error, we will log its message.// Step 2: Execute the API operation of the integrated service
try {
await this.apis.email.postEmail(emailMessage);
} catch(e) {
log.error('Error in PostMail', e);
throw e;
}this.apis.email: provides access to the API dependency in Integration namespaceemail
The provided list supports you to compare your current imports with the recommended list, especially if your IDE complains about errors in the code at this stage of the course.
List of Imports - File PostMail.ts
// Fundamental 1: Generated classes based on design
import { EmailAddress } from 'solution-framework/dist/sdk/v1/namespace/integration/email/model/email-address';
// Fundamental 2: Generated classes reflecting the capabilities of the Workbench
import { services, integrationSchema } from 'solution-framework';
You have successfully implemented an integration service method to call an API endpoint from another microservice! In combination with the design in the Solution Designer, you are able to make use of integration services to call and process API operations of other microservices.
What's Next?â
In the next course you will learn how to implement an API operation that creates a new order.