Before we can run our facade, we need to add three more things: a factory for the component’s we’ve created, a container, and the code that will run it all. The process of implementing these pieces is the same as the one described in Data Microservice, so this time around we’ll just list the code:
Create three factories in the pip_facades_sample_python/build/ folder:
One factory for the facade in a file named FacadeFactory.py, containing the following code:
/src/build/FacadeFactory.ts
import { Factory } from 'pip-services4-components-node';
import { Descriptor } from 'pip-services4-components-node';
import { FacadeServiceV1 } from '../services/version1/FacadeServiceV1';
import { FacadeServiceV2 } from '../services/version2/FacadeServiceV2';
export class FacadeFactory extends Factory {
public static FacadeServiceV1Descriptor = new Descriptor("pip-facades-example", "service", "http", "*", "1.0");
public constructor() {
super();
this.registerAsType(FacadeFactory.FacadeServiceV1Descriptor, FacadeServiceV1);
}
}
/build/FacadeFactory.go
package build
import (
service1 "github.com/pip-services-samples/pip-samples-facade-go/services/version1"
cbuild "github.com/pip-services4/pip-services4-go/pip-services4-components-go/build"
cref "github.com/pip-services4/pip-services4-go/pip-services4-components-go/refer"
)
type FacadeFactory struct {
cbuild.Factory
FacadeServiceV1Descriptor *cref.Descriptor
}
func NewFacadeFactory() *FacadeFactory {
c := FacadeFactory{
Factory: *cbuild.NewFactory(),
}
c.FacadeServiceV1Descriptor = cref.NewDescriptor("pip-facades-example", "controller", "http", "*", "1.0")
c.RegisterType(c.FacadeServiceV1Descriptor, service1.NewFacadeServiceV1)
return &c
}
/pip_facades_sample_python/build/FacadeFactory.py
# -*- coding: utf-8 -*-
from pip_services4_components.refer.Descriptor import Descriptor
from pip_services4_components.build.Factory import Factory
from pip_facades_sample_python.controllers.version1.FacadeControllerV1 import FacadeControllerV1
from pip_facades_sample_python.controllers.version2.FacadeControllerV2 import FacadeControllerV2
class FacadeFactory(Factory):
FacadeControllerV1Descriptor = Descriptor('pip-facades-example', 'controller', 'http', '*', '1.0')
FacadeControllerV2Descriptor = Descriptor('pip-facades-example', 'controller', 'http', '*', '2.0')
def __init__(self):
super(FacadeFactory, self).__init__()
self.register_as_type(FacadeFactory.FacadeControllerV1Descriptor, FacadeControllerV1)
self.register_as_type(FacadeFactory.FacadeControllerV2Descriptor, FacadeControllerV2)
And last but not least, a factory for the clients that the facade depends on in a file named ClientFacadeFactory.py:
/src/build/ClientFacadeFactory.ts
import { Factory } from 'pip-services4-components-node';
import { Descriptor } from 'pip-services4-components-node';
import { SettingsNullClientV1 } from '../clients/version1/SettingsNullClientV1';
import { AccountsMemoryClientV1 } from '../clients/version1/AccountsMemoryClientV1';
import { PasswordsNullClientV1 } from '../clients/version1/PasswordsNullClientV1';
import { RolesMemoryClientV1 } from '../clients/version1/RolesMemoryClientV1';
import { SessionsMemoryClientV1 } from '../clients/version1/SessionsMemoryClientV1';
import { EmailSettingsMemoryClientV1 } from '../clients/version1/EmailSettingsMemoryClientV1';
import { SitesMemoryClientV1 } from '../clients/version1/SitesMemoryClientV1';
import { InvitationsNullClientV1 } from '../clients/version1/InvitationsNullClientV1';
import { BeaconsMemoryClientV1 } from '../clients/version1/BeaconsMemoryClientV1'
export class ClientFacadeFactory extends Factory {
public static SettingsNullClientV1Descriptor = new Descriptor("pip-services-settings", "client", "null", "*", "1.0");
public static AccountsMemoryClientV1Descriptor = new Descriptor("pip-services-accounts", "client", "memory", "*", "1.0");
public static PasswordNullClientV1Descriptor = new Descriptor("pip-services-passwords", "client", "null", "*", "1.0");
public static RolesMemoryClientV1Descriptor = new Descriptor("pip-services-roles", "client", "memory", "*", "1.0");
public static SessionsMemoryClientV1Descriptor = new Descriptor("pip-services-sessions", "client", "memory", "*", "1.0");
public static EmailSettingsMemoryClientV1Descriptor = new Descriptor("pip-services-emailsettings", "client", "memory", "*", "1.0");
public static SitesMemoryClientV1Descriptor = new Descriptor("pip-services-sites", "client", "memory", "*", "1.0");
public static InvitationsNullClientV1Descriptor = new Descriptor("pip-services-invitations", "client", "null", "*", "1.0");
public static BeaconsMemoryClientV1Descriptor = new Descriptor("beacons", "client", "memory", "*", "1.0");
public constructor() {
super();
this.registerAsType(ClientFacadeFactory.SettingsNullClientV1Descriptor, SettingsNullClientV1);
this.registerAsType(ClientFacadeFactory.AccountsMemoryClientV1Descriptor, AccountsMemoryClientV1);
this.registerAsType(ClientFacadeFactory.PasswordNullClientV1Descriptor, PasswordsNullClientV1);
this.registerAsType(ClientFacadeFactory.RolesMemoryClientV1Descriptor, RolesMemoryClientV1);
this.registerAsType(ClientFacadeFactory.SessionsMemoryClientV1Descriptor, SessionsMemoryClientV1);
this.registerAsType(ClientFacadeFactory.EmailSettingsMemoryClientV1Descriptor, EmailSettingsMemoryClientV1);
this.registerAsType(ClientFacadeFactory.SitesMemoryClientV1Descriptor, SitesMemoryClientV1);
this.registerAsType(ClientFacadeFactory.InvitationsNullClientV1Descriptor, InvitationsNullClientV1);
this.registerAsType(ClientFacadeFactory.BeaconsMemoryClientV1Descriptor, BeaconsMemoryClientV1);
}
}
package build
import (
bbuild "github.com/pip-services-samples/client-beacons-gox/build"
accbuild "github.com/pip-services-users/pip-clients-accounts-go/build"
passbuild "github.com/pip-services-users/pip-clients-passwords-go/build"
rolebuild "github.com/pip-services-users/pip-clients-roles-go/build"
sessbuild "github.com/pip-services-users/pip-clients-sessions-go/build"
cbuild "github.com/pip-services4/pip-services4-go/pip-services4-components-go/build"
)
type ClientFacadeFactory struct {
cbuild.CompositeFactory
}
func NewClientFacadeFactory() *ClientFacadeFactory {
c := &ClientFacadeFactory{
CompositeFactory: *cbuild.NewCompositeFactory(),
}
c.Add(accbuild.NewAccountsClientFactory())
c.Add(sessbuild.NewSessionsClientFactory())
c.Add(passbuild.NewPasswordsClientFactory())
c.Add(rolebuild.NewRolesClientFactory())
c.Add(bbuild.NewBeaconsClientFactory())
return c
}
/pip_facades_sample_python/build/ClientFacadeFactory.py
# -*- coding: utf-8 -*-
from pip_services4_components.refer import Descriptor
from pip_services4_components.build import Factory
from pip_facades_sample_python.clients.version1.AccountsMemoryClientV1 import AccountsMemoryClientV1
from pip_facades_sample_python.clients.version1.BeaconsMemoryClientV1 import BeaconsMemoryClientV1
from pip_facades_sample_python.clients.version1.EmailSettingsMemoryClientV1 import EmailSettingsMemoryClientV1
from pip_facades_sample_python.clients.version1.InvitationsNullClientV1 import InvitationsNullClientV1
from pip_facades_sample_python.clients.version1.PasswordsNullClientV1 import PasswordsNullClientV1
from pip_facades_sample_python.clients.version1.RolesMemoryClientV1 import RolesMemoryClientV1
from pip_facades_sample_python.clients.version1.SessionsMemoryClientV1 import SessionsMemoryClientV1
from pip_facades_sample_python.clients.version1.SettingsNullClientV1 import SettingsNullClientV1
from pip_facades_sample_python.clients.version1.SitesMemoryClientV1 import SitesMemoryClientV1
class ClientFacadeFactory(Factory):
SettingsNullClientV1Descriptor = Descriptor("pip-services-settings", "client", "null", "*", "1.0")
AccountsMemoryClientV1Descriptor = Descriptor("pip-services-accounts", "client", "memory", "*", "1.0")
PasswordNullClientV1Descriptor = Descriptor("pip-services-passwords", "client", "null", "*", "1.0")
RolesMemoryClientV1Descriptor = Descriptor("pip-services-roles", "client", "memory", "*", "1.0")
SessionsMemoryClientV1Descriptor = Descriptor("pip-services-sessions", "client", "memory", "*", "1.0")
EmailSettingsMemoryClientV1Descriptor = Descriptor("pip-services-emailsettings", "client", "memory", "*", "1.0")
SitesMemoryClientV1Descriptor = Descriptor("pip-services-sites", "client", "memory", "*", "1.0")
InvitationsNullClientV1Descriptor = Descriptor("pip-services-invitations", "client", "null", "*", "1.0")
BeaconsMemoryClientV1Descriptor = Descriptor("beacons", "client", "memory", "*", "1.0")
def __init__(self):
super(ClientFacadeFactory, self).__init__()
self.register_as_type(ClientFacadeFactory.SettingsNullClientV1Descriptor, SettingsNullClientV1)
self.register_as_type(ClientFacadeFactory.AccountsMemoryClientV1Descriptor, AccountsMemoryClientV1)
self.register_as_type(ClientFacadeFactory.PasswordNullClientV1Descriptor, PasswordsNullClientV1)
self.register_as_type(ClientFacadeFactory.RolesMemoryClientV1Descriptor, RolesMemoryClientV1)
self.register_as_type(ClientFacadeFactory.SessionsMemoryClientV1Descriptor, SessionsMemoryClientV1)
self.register_as_type(ClientFacadeFactory.EmailSettingsMemoryClientV1Descriptor, EmailSettingsMemoryClientV1)
self.register_as_type(ClientFacadeFactory.SitesMemoryClientV1Descriptor, SitesMemoryClientV1)
self.register_as_type(ClientFacadeFactory.InvitationsNullClientV1Descriptor, InvitationsNullClientV1)
self.register_as_type(ClientFacadeFactory.BeaconsMemoryClientV1Descriptor, BeaconsMemoryClientV1)
The container that we want to run our facade in should be implemented in a file named FacadeProcess.py and placed in the /container folder:
/src/container/FacadeProcess.ts
import { ProcessContainer } from 'pip-services4-container-node';
import { DefaultHttpFactory } from 'pip-services4-http-node';
import { ClientFacadeFactory } from '../build/ClientFacadeFactory';
import { FacadeFactory } from '../build/FacadeFactory';
export class FacadeProcess extends ProcessContainer {
public constructor() {
super("pip-facades-example", "Example Pip.Services facade");
this._factories.add(new ClientFacadeFactory);
this._factories.add(new FacadeFactory);
this._factories.add(new DefaultHttpFactory);
}
}
/container/FacadeProcess.go
package container
import (
ffactory "github.com/pip-services-samples/pip-samples-facade-go/build"
cproc "github.com/pip-services4/pip-services4-go/pip-services4-container-go/container"
httpbuild "github.com/pip-services4/pip-services4-go/pip-services4-http-go/build"
mbuild "github.com/pip-services4/pip-services4-go/pip-services4-mongodb-go/build"
)
type FacadeProcess struct {
*cproc.ProcessContainer
}
func NewFacadeProcess() *FacadeProcess {
c := FacadeProcess{}
c.ProcessContainer = cproc.NewProcessContainer("pip-facades-example", "Public facade for pip-vault 2.0")
c.AddFactory(ffactory.NewClientFacadeFactory())
c.AddFactory(ffactory.NewFacadeFactory())
c.AddFactory(httpbuild.NewDefaultHttpFactory())
c.AddFactory(mbuild.NewDefaultMongoDbFactory())
return &c
}
/pip_facades_sample_python/container/FacadeProcess.py
# -*- coding: utf-8 -*-
from pip_services4_container.container import ProcessContainer
from pip_services4_http.build.DefaultRpcFactory import DefaultRpcFactory
from ..build.ClientFacadeFactory import ClientFacadeFactory
from ..build.FacadeFactory import FacadeFactory
class FacadeProcess(ProcessContainer):
def __init__(self):
super(FacadeProcess, self).__init__("pip-facades-example", "Example Pip.Services facade")
self._factories.add(ClientFacadeFactory())
self._factories.add(FacadeFactory())
self._factories.add(DefaultRpcFactory())
For us to be able to run the container, create a run.js file in the /bin folder with the following code:
/bin/main.js
let FacadeProcess = require('../obj/src/container/FacadeProcess').FacadeProcess;
try {
new FacadeProcess().run(process.argv);
} catch (ex) {
console.error(ex);
}
package main
import (
"context"
"os"
cont "github.com/pip-services-samples/pip-samples-facade-go/container"
)
func main() {
proc := cont.NewFacadeProcess()
proc.SetConfigPath("./config/config.yml")
proc.Run(context.Background(), os.Args)
}
/bin/main.py
# -*- coding: utf-8 -*-
import os
import sys
# add parent directory to path
sys.path.append(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
from pip_facades_sample_python.container.FacadeProcess import FacadeProcess
try:
FacadeProcess().run()
except Exception as ex:
sys.stderr.write(str(ex))
Our facade will need to be configured before running, so create a config-distributed.yml file in the /config folder of the project with the following:
/config/config.yml
---
# Container info
- descriptor: "pip-services:container-info:default:default:*"
name: "pip-facades-example"
description: "Example Pip.Services facade on Dart"
# Console logger
- descriptor: "pip-services:logger:console:default:*"
level: trace
# Log counters
- descriptor: "pip-services:counters:log:default:*"
# Mongodb connection
- descriptor: "pip-services:connection:mongodb:default:*"
connection:
uri: {{{MONGO_SERVICE_URI}}}
host: {{{MONGO_SERVICE_HOST}}}{{#unless MONGO_SERVICE_HOST}}localhost{{/unless}}
port: {{MONGO_SERVICE_PORT}}{{#unless MONGO_SERVICE_PORT}}27017{{/unless}}
database: {{MONGO_DB}}{{#unless MONGO_DB}}app{{/unless}}
credential:
username: {{MONGO_USER}}
password: {{MONGO_PASS}}
# Accounts components
# - descriptor: "pip-services-accounts:persistence:mongodb:default:*"
# - descriptor: "pip-services-accounts:controller:default:default:*"
# - descriptor: "pip-services-accounts:client:null:default:1.0"
- descriptor: "pip-services-accounts:client:memory:default:1.0"
# Roles components
# - descriptor: "pip-services-roles:persistence:mongodb:default:*"
# - descriptor: "pip-services-roles:controller:default:default:*"
# - descriptor: "pip-services-roles:client:memory:default:*"
- descriptor: "pip-services-roles:client:null:default:*"
# Passwords components
# - descriptor: "pip-services-passwords:persistence:mongodb:default:*"
# - descriptor: "pip-services-passwords:controller:default:default:*"
# - descriptor: "pip-services-passwords:client:memory:default:*"
- descriptor: "pip-services-passwords:client:null:default:*"
# Session components
# - descriptor: "pip-services-sessions:persistence:mongodb:default:*"
# - descriptor: "pip-services-sessions:controller:default:default:*"
# - descriptor: "pip-services-sessions:client:null:default:*"
- descriptor: "pip-services-sessions:client:memory:default:*"
# Beacons components
- descriptor: "beacons:persistence:mongodb:default:*"
- descriptor: "beacons:controller:default:default:*"
- descriptor: "beacons:client:direct:default:*"
# Main facade service
- descriptor: "pip-services:endpoint:http:default:*"
root_path: ""
connection:
protocol: "http"
host: "0.0.0.0"
port: 8080
# Facade API V1
- descriptor: "pip-facades-example:service:http:default:1.0"
# Hearbeat service
- descriptor: "pip-services:heartbeat-service:http:default:1.0"
# Status service
- descriptor: "pip-services:status-service:http:default:1.0"
For demonstration purposes, we’ll be running our system in a distributed mode, with all of its components running in their own, individual containers. The configuration above is designed specifically for this type of distributed deployment.
The process of running a service in a Docker container is described in detail in the Microservice Dockerization tutorial.
To run our system using Docker Compose, create a docker-compose.yml file with the following:
/docker/docker-compose.yml
version: '3.3'
services:
app:
image: ${IMAGE}
environment:
- MAGIC_CODE=magic
- MONGO_SERVICE_URI=
- MONGO_SERVICE_HOST=mongo
- MONGO_SERVICE_PORT=27017
- MONGO_DB=app
ports:
- "8080:8080"
links:
- mongo
- accounts
- role
- passwords
- sessions
- beacons
command: node /app/bin/run.js -c /app/config/config-distributed.yml
mongo:
image: mongo:latest
ports:
- "27017:27017"
accounts:
image: pipdevs/pip-services-accounts-node:latest
environment:
- MONGO_SERVICE_HOST=mongo
- MONGO_SERVICE_PORT=27017
- MONGO_DB=accounts
links:
- mongo
ports:
- "8082:8080"
role:
image: pipdevs/pip-services-roles-node:latest
environment:
- MONGO_SERVICE_HOST=mongo
- MONGO_SERVICE_PORT=27017
- MONGO_DB=roles
links:
- mongo
ports:
- "8083:8080"
passwords:
image: pipdevs/pip-services-passwords-node:1.0.1-12-rc
environment:
- MONGO_SERVICE_HOST=mongo
- MONGO_SERVICE_PORT=27017
- MONGO_DB=passwd
links:
- mongo
ports:
- "8084:8080"
sessions:
image: pipdevs/pip-services-sessions-node:1.0.1-19-rc
environment:
- MONGO_SERVICE_HOST=mongo
- MONGO_SERVICE_PORT=27017
- MONGO_DB=sessions
links:
- mongo
ports:
- "8085:8080"
beacons:
image: pipdevs/pip-services-beacons-node:1.0
environment:
- MONGO_SERVICE_HOST=mongo
- MONGO_SERVICE_PORT=27017
- MONGO_DB=beacons
links:
- mongo
ports:
- "8086:8080"
Build and run the facade using the respective scripts (described in the Microservice Dockerization we mentioned above) tutorial, which can be found in this example project’s repository (facade-sample-*).
To build the facade’s image and load the rest of the services' images, run the “package” script using the command below:
.\package.ps1
Once the build process successfully finishes, run the entire system with all of its microservices in Docker Compose using the “run” script. This can be done with the following command:
.\run.ps1
When running the facade, you should see something like this in the console:
app_1 | [pip-facades-example:DEBUG:2021-06-17T22:03:56.128800] Opened REST service at http://0.0.0.0:8080
app_1 | [pip-facades-example:INFO:2021-06-17T22:03:56.180451] Container pip-facades-example started.
app_1 | [pip-facades-example:INFO:2021-06-17T22:03:56.180451] Press Control-C to stop the microservice...
Now we’re ready to move on to manually testing our facade. In Step 9 - Manually testing the facade - we’ll show you how this can be done.