Step 8. Running the facade

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
}

Not available

/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)

Not available

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
}

Not available

/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)

Not available

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
}

Not available

/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())

Not available

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)
}

Not available

/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))

Not available

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.

Step 9 - Manually testing the facade