Inventory BFF
Develop and deploy the BFF component of the inventory application
Setup
The Inventory BFF’s role in the architecture is to act as an orchestrator between the core business services and the specific digital channel it is focused on supporting. This class article will give you more detail about the architectural pattern and the benefits. Backend for Frontend
The Inventory solution will use GraphQL for its BFF layer, which enables the API to be dynamically controlled from the client using API queries. Follow the steps below to get started.
Setup
To get the initial BFF project created and registered with a pipeline for automated builds follow these steps.
Create a new repository from the Typescript GraphQL Code Pattern
- In order to prevent naming collisions, name the repository 
inventory-management-bff-{your initials}replacing{your initials}with your actual initials. 
- In order to prevent naming collisions, name the repository 
 Clone the new repository to your machine
Run
npm installto install all the package dependenciesGo into the repository directory cloned and execute the following
oc sync dev-{your initials} --devRegister the pipeline register the pipeline
oc pipeline --tektonreplacing
{your initials}with your actual initialsOpen the pipeline to see it running
When the pipeline is completed, run
oc endpoints -n dev-{your initials}. You should see an entry for the app we just pushed. Select the entry and hitEnterto launch the browser, if you are working on your desktop/laptop. Otherwise copy the url and paste it in a new browser tab.
Build the controller for the REST interface
The controller provides the REST interface for our BFF. The Code Pattern uses the typescript-rest
package to simplify the tasks required to create a controller.
- Start the tests in tdd mode by running
 
npm run tdd
- Create the controller test
 
test/controllers/stock-items.controller.spec.tsimport {Application} from 'express';import * as request from 'supertest';import {buildApiServer} from '../helper';describe('stock-item.controller', () => {let app: Application;beforeEach(async () => {
- Create the controller component
 
src/controllers/stock-items.controller.tsimport {GET, Path} from 'typescript-rest';@Path('stock-items')export class StockItemsController {@GETasync listStockItems(): Promise<any[]> {return [];}
- Add the controller to the controllers 
index.ts. (Usingindex.tsis a good way to manage which components are exposed by a component and provide a good way to load the modules that will be injected into other components) 
src/controllers/index.tsexport * from './health.controller';export * from './stock-items.controller';
- Start the service to see it running
 
npm start
    - Click on open link
 
    - To view this application in new tab click top right corner arrow icon
 
To view the running app click on the Eye Icon on the top right and select the port
3000this will open a browser tab and display the running app on that port.
    
Expand our service from the list, click
Try it out, then clickExecutePush the changes we’ve made to the repository
git add .git commit -m "Adds stock items controller"git push
- Open the pipeline to see it running
 
Update the controller to call a service
The pattern recommended for the REST controllers is to let it focus on translating REST protocols into javascript and to put the business logic in a separate service component.
- Add a StockItem model that contains the values needed for the UI
 
src/models/stock-item.model.tsexport class StockItemModel {id: string;name: string;description: string;stock: number;unitPrice: number;picture: string;manufacturer: string;}
- Register the model with the 
index.tsfile in the models directory. Append this to end of the file. 
src/models/index.ts...export * from './stock-item.model';
- Define an abstract class to provide the interface for our API
 
src/services/stock-items.api.tsimport {StockItemModel} from '../models';export abstract class StockItemsApi {async abstract listStockItems(): Promise<StockItemModel[]>;}
- Add the abstract class to the 
index.tsfile in the services directory. Add it to the end of other export statements, do not overwrite the file. 
src/services/index.ts...export * from './stock-items.api';...
- Update the controller test to inject the service into the controller and to return the value from the service
 
test/controllers/stock-items.controller.spec.tsimport {Application} from 'express';import * as request from 'supertest';import {Container} from 'typescript-ioc';import {buildApiServer} from '../helper';import Mock = jest.Mock;import {StockItemsMockService} from '../../src/services';describe('stock-item.controller', () => {
- Update the controller to inject the service and use it
 
src/controllers/stock-items.controller.tsimport {Inject} from 'typescript-ioc';import {GET, Path} from 'typescript-rest';import {HttpError} from 'typescript-rest/dist/server/model/errors';import {StockItemModel} from '../models';import {StockItemsMockService} from '../services';class BadGateway extends HttpError {constructor(message?: string) {
Create a mock service implementation
Now that we have our Controller using our API to get the data, lets create an implementation that will provide mock data for now.
- Add a 
stock-items-mock.serviceto services 
src/services/stock-items-mock.service.tsimport {StockItemsApi} from './stock-items.api';import {StockItemModel} from '../models';export class StockItemsMockService implements StockItemsApi {async listStockItems(): Promise<StockItemModel[]> {return [{id: "1",
- Add the mock service to the 
index.tsfile in the services directory 
src/services/index.ts...export * from './stock-items-mock.service';...
- Start the service
 
npm start
    - Click on open link
 
    - To view this application in new tab click top right corner arrow icon
 
To view the running app click on the Eye Icon on the top right and select the port
3000this will open a browser tab and display the running app on that port.
    
- Push the changes we’ve made to the repository
 
git add .git commit -m "Adds a mock service implementation"git push
- Open the pipeline to see it running
 
Add a GraphQL implementation of Stock Items
The GraphQL Code Pattern supports both REST and GraphQL APIs for accessing backend services. We created a REST controller to expose the results from the service and now we will do the same for GraphQL.
- Create a 
stock-itemsGraphQL schema in theschemasdirectory 
src/schemas/stock-item.schema.tsimport {Field, Float, Int, ObjectType} from 'type-graphql';import {StockItemModel} from '../models';@ObjectType()export class StockItem implements StockItemModel {@Field()id: string;@Field()description: string;
- Add the stock-items schema to the 
index.tsin the schemas directory 
src/schemas/index.tsexport * from './stock-item.schema'
- Add a ‘stock-item’ GraphQL resolver in the 
resolversdirectory 
src/resolvers/stock-item.resolver.tsimport {Query, Resolver} from 'type-graphql';import {Inject} from 'typescript-ioc';import {resolverManager} from './_resolver-manager';import {StockItem} from '../schemas';import {StockItemModel} from '../models';import {StockItemsMockService} from '../services';@Resolver(of => StockItem)
- Add the stock-items resolver to 
index.tsin the resolvers directory 
src/resolvers/index.tsexport * from './stock-item.resolver';
- Start the service
 
npm start
- Verify that the that the resolver is available using the Graph QL browser provided by the Code Pattern
- Open GraphQL Playground: 
http://localhost:3000 - Run the query 
query { stockItems { name } } 
 - Open GraphQL Playground: 
 
    - Click on open link
 
    - To view this application in new tab click top right corner arrow icon
 
To view the running app click on the Eye Icon on the top right and select the port
3000this will open a browser tab and display the running app on that port.
    
- Push the changes we’ve made to the repository
 
git add .git commit -m "Adds a graphql interface"git push
- Open the pipeline to see it running
 
Create a service implementation that calls the microservice
Create a folder
configin following pathsrc/configAdd a
stock-item-service.configfile in the config directory
src/config/stock-item-service.config.tsexport class StockItemServiceConfig {baseUrl: string;}
- Add a 
stock-item-service.config.providerfile in the config directory 
src/config/stock-item-service.config.provider.tsimport {ObjectFactory} from 'typescript-ioc';const baseUrl: string = process.env.SERVICE_URL || 'localhost:9080';export const stockItemConfigFactory: ObjectFactory = () => ({baseUrl,});
The config class separates how the config is loaded from how it is used. In this case the config is simply retrieved from an environment variable but in more complex cases the value(s) can be retrived from external data sources.
- Add the 
stock-item-service.configto an index.ts of the config directory 
src/config/index.tsimport {StockItemServiceConfig} from './stock-item-service.config';import {stockItemConfigFactory} from './stock-item-service.config.provider';import {Container} from 'typescript-ioc';export * from './stock-item-service.config';Container.bind(StockItemServiceConfig).factory(stockItemConfigFactory);
- Create a 
stock-itemsservice in the services directory that uses the config 
src/services/stock-items.service.tsimport {Inject} from 'typescript-ioc';import {get, Response} from 'superagent';import {StockItemsApi} from './stock-items.api';import {StockItemModel} from '../models';import {StockItemServiceConfig} from '../config';import {LoggerApi} from '../logger';class StockItem {
- Add 
stock-item.servicetoindex.tsin the service directory - Add 
StockItemsServiceinstead ofStockItemsMockServicein the following filessrc/resolvers/stock-item.resolver.ts,src/controllers/stock-items.controller.tsandtest/controllers/stock-items.controller.spec.ts 
- Remove 
stock-items-mock.servicefromindex.ts 
src/services/index.tsexport * from './stock-items.service';
- Modify 
connectsToproperty to the values.yaml file of the Helm chart. The value of the property should match the Kubernetes service of the microservice. (For Code Pattern projects, the service name is the same as the name of the application which is that same as the name of the repository.) 
chart/base/values.yaml...connectsTo: inventory-management-svc-{your initials}...
The values.yaml file of the Helm chart defines the variables that can be provided to the
template as input. Now that we’ve added a new variable, we will need to update the appropriate
template file to use our new variable.
- Add a new environment variable named 
SERVICE_URLto the list of existing environment variables in deployment.yaml. (SERVICE_URLis the name we gave the environment variable in ourstock-item-service.configclass as the first step in this section.) The value of this environment variable should come from theconnectsTovalue we defined. You can add| quoteto wrap the value in quotes in case the value is not formatted correctly. 
chart/base/templates/deployment.yaml...env:- name: INGRESS_HOSTvalue: ""- name: PROTOCOLSvalue: ""- name: LOG_LEVELvalue: {{ .Values.logLevel | quote }}- name: SERVICE_URL
deployment.yaml is a templatized Kubernetes yaml file that describes the deployment of our component.
The deployment will create one or more pods based on the pod template defined in the deployment.
Each pod that starts will have the envionment variables that we have defined in the env section
available for the container image to reference.
- Commit and push the changes to git
 
git add .git commit -m "Adds service implementation"git push
- Open the pipeline to see it running