Direct client

How to use the DirectClient component.

Key takeaways

Direct client A component that calls a controller directly in the same memory space.
Controller Custom component used to define a method that is called by the direct client.
References Component used to store and locate component references.
DependencyResolver Component used to resolve component references.

Introduction

A direct client is a component that calls a controller directly in the same memory space. In general, it is used when multiple microservices are deployed in a single container (monolith system) and communication between them can be done by direct calls. Within Pip.Services, the DirectClient component is used to create it.

This tutorial will help you understand how this class works. First, we will see how to create a simple controller that contains a method that prints “Hello world”. Then, we will learn how to create a direct client that connects to this controller and allows us to use the method previously defined in our controller. Finally, we will run our program and see the results.

The controller

Our controller class is very simple and, for the purpose of this example, has a function named “my_method”, which prints “Hello world”. The following code shows how this class is defined and how to create an instance of it.

import { ConfigParams, IConfigurable, IReferenceable, IReferences } from "pip-services3-commons-nodex";

export async function main() {
    // Instantiation
    let myController = new MyController();
}

export class MyController implements IConfigurable, IReferenceable {
    public configure(config: ConfigParams): void {
    }

    public setReferences(references: IReferences): void {
    }

    public myMethod(): void {
        console.log('Hello world');
    }
}
using PipServices3.Commons.Refer;
using PipServices3.Commons.Config;

class Program
{
    static void Main(string[] args)
    {
        // Instantiation
        var myController = new MyController();
    }
}


class MyController : IConfigurable, IReferenceable
{
    public void Configure(ConfigParams config)
    {
    }

    public void SetReferences(IReferences references)
    {
    }

    public void myMethod()
    {
        Console.WriteLine("Hello world");
    }
}

import (
	"context"
	"fmt"

	cconf "github.com/pip-services3-gox/pip-services3-commons-gox/config"
	cref "github.com/pip-services3-gox/pip-services3-commons-gox/refer"
)

func main() {
    // Instantiation
	myController := &MyController{}
}

type MyController struct {
}

func (c *MyController) Configure(ctx context.Context, config *cconf.ConfigParams) {

}

func (c *MyController) SetReferences(ctx context.Context, references cref.IReferences) {

}

func (c *MyController) MyMethod() {
	fmt.Println("Hello world")
}
import 'package:pip_services3_commons/pip_services3_commons.dart';

void main(List<String> argument) {
  // Instantiation
  var myController = MyController();
}

class MyController implements IConfigurable, IReferenceable {
  void configure(ConfigParams config) {}

  void setReferences(IReferences references) {}

  void myMethod() {
    print('Hello world');
  }
}

# Pre-requisites
from pip_services3_commons.refer import Descriptor, IReferences, IReferenceable
from pip_services3_commons.config import IConfigurable

# Controller
class MyController(IConfigurable, IReferenceable):

    def __init__(self):
        pass

    def configure(self, config):
        pass

    def set_references(self, references: IReferences):
        pass

    def my_method(self):
        print("Hello world")

# Instantiation 
myController = MyController()
Not available

The direct client

Now that we have our controller, we can construct a direct client that communicates with it and calls “my_method”.

To achieve this, we do the following process. First, we create a reference to the controller via two components: References and DependencyResolver. This last class is used to give a name to our controller’s reference and is added in the init() method. Then, in the setReferences() method, we receive a References object, which is used to associate the client to the controller. Lastly, we create a method that invokes “my_method” from the controller. Once our class is defined, we create an instance of it. The following code shows how to do this.

// Pre-requisites
import { ConfigParams, DependencyResolver, Descriptor, IConfigurable, IReferenceable, IReferences } from "pip-services3-commons-nodex";
import { DirectClient } from "pip-services3-rpc-nodex";


// Direct client
export class MyDirectClient extends DirectClient<MyController> {
    _dependencyResolver =  new DependencyResolver();

    public constructor() {
        super();
        this._controller = null
        this._dependencyResolver.put("controller", new Descriptor("pip-services", "controller", "*", "*", "1.0"))
    }

    public setReferences(references: IReferences): void {
        this._dependencyResolver.setReferences(references);
        this._controller = this._dependencyResolver.getOneRequired("controller");
    }
}

// Instantiation
let client = new MyDirectClient();
// Pre-requisites
using PipServices3.Commons.Refer;
using PipServices3.Commons.Config;
using PipServices3.Rpc.Clients;


// Direct client
class MyDirectClient: DirectClient<MyController>
{
    public MyDirectClient()
    {
        _controller = null;
        _dependencyResolver.Put("controller", new Descriptor("pip-services", "controller", "*", "*", "1.0"));
    }

    public void setReferences(IReferences references)
    {
        this._dependencyResolver.SetReferences(references);
        this._controller = _dependencyResolver.GetOneRequired<MyController>("controller");
    }

    public void myMethod()
    {
        _controller.myMethod();
    }
}


// Instantiation
var client = new MyDirectClient();
// Pre-requisites
import (
	"context"
	"fmt"

	cconf "github.com/pip-services3-gox/pip-services3-commons-gox/config"
	cref "github.com/pip-services3-gox/pip-services3-commons-gox/refer"
	rpcclnt "github.com/pip-services3-gox/pip-services3-rpc-gox/clients"
)


// Direct client
type MyDirectClient struct {
	*rpcclnt.DirectClient
	dependencyResolver *cref.DependencyResolver
	controller         *MyController
}

func NewMyDirectClient() *MyDirectClient {
	c := &MyDirectClient{}
    c.dependencyResolver = cref.NewDependencyResolver()
	c.dependencyResolver.Put(context.Background(), "controller", cref.NewDescriptor("pip-services", "controller", "*", "*", "1.0"))
	return c
}

func (c *MyDirectClient) SetReferences(ctx context.Context, references cref.IReferences) {
	c.dependencyResolver.SetReferences(ctx, references)
	res, err := c.dependencyResolver.GetOneRequired("controller")
	if err != nil {
		panic(err)
	}
	c.controller = res.(*MyController)
}

func (c *MyDirectClient) MyMethod() {
	c.controller.MyMethod()
}

// Instantiation
client := NewMyDirectClient();
// Pre-requisites
import 'package:pip_services3_commons/pip_services3_commons.dart';
import 'package:pip_services3_rpc/pip_services3_rpc.dart';


// Direct client
class MyDirectClient extends DirectClient<MyController> {
  MyDirectClient() {
    dependencyResolver.put('controller',
        Descriptor('pip-services', 'controller', '*', '*', '1.0'));
  }

  @override
  void setReferences(IReferences references) {
    dependencyResolver.setReferences(references);
    controller = dependencyResolver.getOneRequired<MyController>('controller');
  }

  void myMethod() {
    controller.myMethod();
  }
}


// Instantiation
var client = MyDirectClient();
# Pre-requisites

from pip_services3_rpc.clients import DirectClient
from pip_services3_commons.refer import Descriptor, IReferences, DependencyResolver
from pip_services3_commons.config import IConfigurable


# Direct client
class MyDirectClient(DirectClient):
    _dependencyResolver = DependencyResolver() 
        
    def __init__(self):
        super(MyDirectClient, self).__init__()
        self._controller: MyController = None
        self._dependencyResolver.put("controller", Descriptor("pip-services", "controller", "*", "*", "1.0"))
        
        
    def set_references(self, references: IReferences):
        self._dependencyResolver.set_references(references)
        self._controller = self._dependencyResolver.get_one_required("controller")
        
    def my_method(self):
        self._controller.my_method()

# Instantiation        
client = MyDirectClient()
Not available

Reference setting

The next step is to define the association between our reference in the client and the controller. The following code shows how to do it.

// Pre-requisites
import { References } from "pip-services3-commons-nodex";

// Reference setting
client.setReferences(References.fromTuples(
    new Descriptor("pip-services", "controller", "controller", "default", "1.0"), myController));
// Pre-requisites
using PipServices3.Commons.Refer;

// Reference setting
client.setReferences(References.FromTuples(
    new Descriptor("pip-services", "controller", "controller", "default", "1.0"), myController));
// Pre-requisites
import (
    cref "github.com/pip-services3-gox/pip-services3-commons-gox/refer"
)

// Reference setting
client := NewMyDirectClient()
client.SetReferences(context.Background(), cref.NewReferencesFromTuples(context.Background(),
	cref.NewDescriptor("pip-services", "controller", "controller", "default", "1.0"), myController,
))
// Pre-requisites
import 'package:pip_services3_commons/pip_services3_commons.dart';

// Reference setting
client.setReferences(References.fromTuples([
  Descriptor('pip-services', 'controller', 'controller', 'default', '1.0'),
  myController
]));
# Pre-requisites
from pip_services3_commons.refer import References

# Reference setting
client.set_references(References.from_tuples(
    Descriptor("pip-services", "controller", "controller", "default", "1.0"), myController))
Not available

Calling “my_method”

Our aim is to call “my_method” from the client. We have made this possible by connecting the controller and the client. Thus, our final step is to call this method from the client with the following command:

client.myMethod();
client.myMethod();
client.MyMethod()
client.myMethod();
client.my_method()
Not available

Which after execution produces the following result:

figure 1

Final code

The following code summarizes all the previous steps:

import { ConfigParams, DependencyResolver, Descriptor, IConfigurable, IReferenceable, IReferences, References } from "pip-services3-commons-nodex";
import { DirectClient } from "pip-services3-rpc-nodex";


export async function main() {
    // Instantiation
    let myController = new MyController();

    // Instantiation
    let client = new MyDirectClient();

    // Reference setting
    client.setReferences(References.fromTuples(
        new Descriptor("pip-services", "controller", "controller", "default", "1.0"), myController));
    
    // Calling "my_method"
    client.myMethod();
}

export class MyDirectClient extends DirectClient<MyController> {
    _dependencyResolver =  new DependencyResolver();

    public constructor() {
        super();
        this._controller = null
        this._dependencyResolver.put("controller", new Descriptor("pip-services", "controller", "*", "*", "1.0"))
    }

    public setReferences(references: IReferences): void {
        this._dependencyResolver.setReferences(references);
        this._controller = this._dependencyResolver.getOneRequired("controller");
    }

    public myMethod(): void {
        this._controller.myMethod();
    }
}


export class MyController implements IConfigurable, IReferenceable {
    public configure(config: ConfigParams): void {
    }

    public setReferences(references: IReferences): void {
    }

    public myMethod(): void {
        console.log('Hello world');
    }
}
using System;
using PipServices3.Commons.Refer;
using PipServices3.Commons.Config;
using PipServices3.Rpc.Clients;

namespace ExampleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            // Instantiation
            var myController = new MyController();

            // Instantiation
            var client = new MyDirectClient();

            // Reference setting
            client.setReferences(References.FromTuples(
                new Descriptor("pip-services", "controller", "controller", "default", "1.0"), myController));

            client.myMethod();
        }
    }

    class MyDirectClient: DirectClient<MyController>
    {
        public MyDirectClient()
        {
            _controller = null;
            _dependencyResolver.Put("controller", new Descriptor("pip-services", "controller", "*", "*", "1.0"));
        }

        public void setReferences(IReferences references)
        {
            this._dependencyResolver.SetReferences(references);
            this._controller = _dependencyResolver.GetOneRequired<MyController>("controller");
        }

        public void myMethod()
        {
            _controller.myMethod();
        }
    }


    class MyController : IConfigurable, IReferenceable
    {
        public void Configure(ConfigParams config)
        {
        }

        public void SetReferences(IReferences references)
        {
        }

        public void myMethod()
        {
            Console.WriteLine("Hello world");
        }
    }
}
import (
	"context"
	"fmt"

	cconf "github.com/pip-services3-gox/pip-services3-commons-gox/config"
	cref "github.com/pip-services3-gox/pip-services3-commons-gox/refer"
	rpcclnt "github.com/pip-services3-gox/pip-services3-rpc-gox/clients"
)

func main() {
	// Instantiation
	myController := &MyController{}

	// Instantiation
	client := NewMyDirectClient()

	// Reference setting
	client.SetReferences(context.Background(), cref.NewReferencesFromTuples(context.Background(),
		cref.NewDescriptor("pip-services", "controller", "controller", "default", "1.0"), myController,
	))

	// Calling "my_method"
	client.MyMethod()
}

type MyDirectClient struct {
	*rpcclnt.DirectClient
	dependencyResolver *cref.DependencyResolver
	controller         *MyController
}

func NewMyDirectClient() *MyDirectClient {
	c := &MyDirectClient{}
	c.dependencyResolver = cref.NewDependencyResolver()
	c.dependencyResolver.Put(context.Background(), "controller", cref.NewDescriptor("pip-services", "controller", "*", "*", "1.0"))
	return c
}

func (c *MyDirectClient) SetReferences(ctx context.Context, references cref.IReferences) {
	c.dependencyResolver.SetReferences(ctx, references)
	res, err := c.dependencyResolver.GetOneRequired("controller")
	if err != nil {
		panic(err)
	}
	c.controller = res.(*MyController)
}

func (c *MyDirectClient) MyMethod() {
	c.controller.MyMethod()
}

type MyController struct {
}

func (c *MyController) Configure(ctx context.Context, config *cconf.ConfigParams) {

}

func (c *MyController) SetReferences(ctx context.Context, references cref.IReferences) {

}

func (c *MyController) MyMethod() {
	fmt.Println("Hello world")
}
import 'package:pip_services3_commons/pip_services3_commons.dart';
import 'package:pip_services3_rpc/pip_services3_rpc.dart';

void main(List<String> argument) {
  // Instantiation
  var myController = MyController();

  // Instantiation
  var client = MyDirectClient();

  client.setReferences(References.fromTuples([
    Descriptor('pip-services', 'controller', 'controller', 'default', '1.0'),
    myController
  ]));

  client.myMethod();
}

class MyDirectClient extends DirectClient<MyController> {
  MyDirectClient() {
    dependencyResolver.put('controller',
        Descriptor('pip-services', 'controller', '*', '*', '1.0'));
  }

  @override
  void setReferences(IReferences references) {
    dependencyResolver.setReferences(references);
    controller = dependencyResolver.getOneRequired<MyController>('controller');
  }

  void myMethod() {
    controller.myMethod();
  }
}

class MyController implements IConfigurable, IReferenceable {
  void configure(ConfigParams config) {}

  void setReferences(IReferences references) {}

  void myMethod() {
    print('Hello world');
  }
}

# Pre-requisites
from pip_services3_rpc.clients import DirectClient
from pip_services3_commons.refer import Descriptor, References, IReferences, IReferenceable, DependencyResolver
from pip_services3_commons.config import IConfigurable


# Direct client
class MyDirectClient(DirectClient):
    _dependencyResolver = DependencyResolver() 
        
    def __init__(self):
        self._controller: MyController = None
        self._dependencyResolver.put("controller", Descriptor("pip-services", "controller", "*", "*", "1.0"))
        super(MyDirectClient, self).__init__()
        
    def set_references(self, references: IReferences):
        self._dependencyResolver.set_references(references)
        self._controller = self._dependencyResolver.get_one_required("controller")
        
    def my_method(self):
        self._controller.my_method()

# Instantiation        
client = MyDirectClient()

# Controller
class MyController(IConfigurable, IReferenceable):

    def __init__(self):
        pass

    def configure(self, config):
        pass

    def set_references(self, references: IReferences):
        pass

    def my_method(self):
        print("Hello world")

# Instantiation 
myController = MyController()

# Reference setting
client.set_references(References.from_tuples(
    Descriptor("pip-services", "controller", "controller", "default", "1.0"), myController))

# Calling "my_method"
client.my_method()
Not available

Which, after running, produces the following outcome:

figure 1

Wrapping up

In this tutorial, we have seen how to create a direct client by using the DirectClient component. To understand this class, we created a controller with a method that prints “Hello world”. Then, we created a client with the controller as a dependency and connected both components. Finally, we ran the created method from the client and saw the results.