Course 4: Implement API Operations
In this course you will learn about the implementation of API Operation in Domain Service projects, both for the TypeScript and Java Spring Boot stack.
Exercise
Estimated time: 30 minutes
Supported languages: TypeScript and Java
Precondition:
In this exercise, you will implement an API Operation within your Orders project.
Please note that the links to the workbench tools in this tutorial only apply to the IBM Education Environment we provide. If you are using a different environment, e.g. your own installation, you will need to navigate directly to the required tools.
Introduction
In this use case we want to retrieve all orders for a customer. To do this, a GET Operation has to be implemented which can return the list of all orders for a customer.
Open your imported Orders project
The following steps will take your Orders project which you have imported in Course Domain Service Development as a base.
- Open your Workspace in the Solution Designer.
- Find your imported Project and open it by clicking on it.
Discover the API Operation modelled in the -solutionDesigner
We will now discover the API Namespace "ordapi" which is already designed in the Solution Designer. The API namespace consists of the following elements:
-
A Path and an Operation "getOrdersForCustomer"
-
A Parameter that is used to read the customerId
-
A Response that returns the list of orders
Discover the Domain Namespace in the -solutionDesigner
Now, we will discover the Domain Namespace "ord" which already contains items around managing orders:
-
A RootEntity "Order" that holds all details of the order
-
A Domain Service "FindOpenOrdersForCustomer" that returns all open orders of a specific customer
Implement the API Operation
After discovering the API, the operation needs to be implemented so that it returns the expected response. This part is not done within the Solution Designer. Instead we will use the native development tooling on your local machine.
- Ensure that you have setup the necessary prerequisites for local development
- Ensure that you have installed the Solution CLI.
- Therefore follow the "Solution CLI Setup" instructions in your Project in the Solution Designer (see here)
Clone the project
To implement your designed Operation in your IDE (e.g. Visual Studio Code) you have to clone your Project to your local machine.
If you have cloned the project before already, it is enough to perform the command k5 pull
to get the latest changes.
-
Open the section "Implementation" in the "Solution CLI" and follow the instructions of the section in your terminal.
If you choose TypeScript, please ensure that within your IDE you have opened the project directory instead of your workspace directory to ensure that all of the provided features work smoothly.
Implement API Operation
- TypeScript
- Java
- Open the file
/src-impl/api/ordapi/operations/GetOrdersForCustomerApi.ts
You will see that the file contains an auto-generated stub with a more or less empty getOrdersForCustomer()
function that you need to fill with code to implement the actual functionality. The only content of that block is commented out sample code for some often-used functionality aimed at serving as a template for what you might want to do.
/**
* @param request Request.GetOrdersForCustomerRequest
* getOrdersForCustomer logic
*/
getOrdersForCustomer = async (request: Request.GetOrdersForCustomerRequest) => {
// TODO: add your implementation logic
this.util.log.info('start getOrdersForCustomer execution');
// this.response;
}
In the next steps, we will extend the execute function step by step with the code to get all orders for a customer.
- First, extract the customerId from the request path and store it in a variable:
// read customerId from path
const customerIdPathParameter = request.path.customerId;
request.path
: provides type-safe access to the request path that is modeled for the current operation.
- As a next step, create an input entity, fill it with the customerId from the request and trigger the domain service:
// construct input entity for the call to the domain service
const serviceInput = this.factory.entity.ord.FindOpenOrdersForCustomer_Input();
// set customerId from path parameter for the service input
serviceInput.customerId = customerIdPathParameter;
// trigger the domain service to get all open orders for a customer
const orders = await this.services.ord.FindOpenOrdersForCustomer(serviceInput);
this.factory.entity.ord
: provides the creation of instances of each entity, input, output and payload entity in domain namespaceord
.
this.services:
allows to call any service that is modeled within a domain or integration namespace. Returns an entity or a list of entities which can be then mapped to the response of the API operation.
- Loop over orders which have been returned by domain service in order to transform them to Schema "Order" from our API namespace:
// initialize response as an empty list
this.response.body = [];
for (const order of orders) {
// create an empty order schema in "api format"
const apiOrder: Schema.Order = {};
// map properties from domain entity Order to the api schema "Order"
apiOrder.customer_id = order.customerId;
// add api schema "Order" to the response
this.response.body.push(apiOrder);
}
// set response status to 200
this.response.statusCode = 200;
Schema.Order:
provides access to the type for the modeled schemaOrder
.
this.response.body:
provides type-safe access to the response body of the operation. Only schemas that are modelled as response body are allowed to be set here.
this.response.statusCode:
Response status has to be set in each operation. The implementation is restricted to the status codes that are modeled for this operation.
- Open the file
/src/main/java/<solution-acronym>/<package-name>/api/ordapi/CustomerApiOrdapiProvider.java
. (Replace the placeholders with your values)
You will see that the file contains an auto-generated stub with a more or less empty implementation of the class CustomerApiOrdapiProvider
with the function getOrdersForCustomer
that represents our API Operation.
/**
* A stub that provides implementation for the CustomerApiOrdapiDelegate
*/
@Service
@ComponentScan(basePackages = ".msaorderj.knowis.sdk.api.ordapi.api")
public class CustomerApiOrdapiProvider implements CustomerApiOrdapiDelegate {
@Override
public ResponseEntity<List<Order>> getOrdersForCustomer(String customerId) {
//TODO Auto-generated method stub
return getOrdersForCustomerExampleResponse();
}
}
In the next steps, we will extend the implementation of the class step by step with the code to get all orders for a customer.
- Extend the implementation class with the following Inject an instance of the Domain Service
FindOpenOrdersForCustomer
by defining a new constructor for the API-Service.
public class CustomerApiOrdapiProvider implements CustomerApiOrdapiDelegate {
// Define domain service dependency
private FindOpenOrdersForCustomer findOpenOrdersForCustomer;
// Create a constructor with the new dependency
public CustomerApiOrdapiProvider (FindOpenOrdersForCustomer findOpenOrdersForCustomer) {
this.findOpenOrdersForCustomer = findOpenOrdersForCustomer;
}
Please use the auto-import function of your IDE (Eclipse is recommended) to import the missing classes
SpringBoot will provide an instance of the domain service
FindOpenOrdersForCustomer
, that is injected here in the Constructor.
- In the next step, you need to remove the auto-generated lines in the method stub (see highlighted lines) from the
getOrdersForCustomer
method.
@Override
public ResponseEntity<List<Order>> getOrdersForCustomer(String customerId) {
//TODO Auto-generated method stub
return getOrdersForCustomerExampleResponse();
}
- Extend the method
getOrdersForCustomer
with the code to construct an input entity for the domain service, fill it with the customerId and call the domain service:
// construct input for the call to the domain service
FindOpenOrdersForCustomerInputEntity serviceInput = new FindOpenOrdersForCustomerInputEntity();
// set customerId from path parameter for the service input
serviceInput.setCustomerId(customerId);
// call the domain service to receive all the orders if the customer
List<msaorderj.knowis.sdk.domain.ord.entity.Order> orders = findOpenOrdersForCustomer.execute(serviceInput);
Replace
com.knowis
with your chosen project name and package name
- Loop over orders which have been returned by domain service in order to transform them to API Schema "Order" from our API namespace:
// create a new empty list of API schema "Order" to return them as HTTP response
List<Order> apiOrders = new ArrayList<Order>();
// loop over all order entities loaded by the domain service
for (msaorderj.knowis.sdk.domain.ord.entity.Order order : orders) {
// create new API schema "Order"
Order apiOrder = new Order();
// map properties from order entity to API schema "Order"
apiOrder.setCustomerId(order.getCustomerId());
// add API schema to orders list
apiOrders.add(apiOrder);
}
- Next step is to use this body to create a
ResponseEntity
, set the created list as body and define 200 for the status as the call was successfull:
// create a ResponseEntity with the orders list as body and Http status code 200
ResponseEntity<List<Order>> response = new ResponseEntity<>(apiOrders, HttpStatus.OK);
return response;
Push the changes to Git
To make the changes of your implementation visible to others you have to push them to the remote Git repository.
- Go to your terminal and run command
k5 compile
to ensure that you do not have any issues in your code. - Run the command
k5 push -m "Implementation of my Orders Project"
.
You have successfully implemented your Orders Project. You also pushed your changes to your remote Git repository in Gitlab.
Trigger a Pipeline
As a next step we will use the Deploy pipeline to publish the changes and try out the implemented Operation.
Please perform the following steps:
-
Click on CI/CD section in the navigation menu.
-
Open the pipeline section and discover the pipeline.
-
Use the three dot menu on right side of table row and click on the “Run” button.
You have successfully created and triggered pipeline for your project from the Orders template.
Discover the deployed service in the -solutionEnvoy
After the pipeline run has "Succeeded" you can have a look at the deployed Service.
-
Login into the Solution Envoy and search for your deployed service that is listed under its projectAcronym (e. g. k5-msaord).
-
Open the API Specification "ordapi" to discover your modelled API.
-
Now trigger the implemented Operation from swagger UI.
Your Service has been successfully deployed and is ready to use.
Related Links
Please find more information about Implementing API operations: