Direct client

How to use the DirectClient component.

Key takeaways

Direct client A component that calls a service directly in the same memory space.
Service 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 service 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 service that contains a method that prints “Hello world”. Then, we will learn how to create a direct client that connects to this service and allows us to use the method previously defined in our service. Finally, we will run our program and see the results.

The service

Our service 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-services4-components-node";

export async function main() {
    // Instantiation
    let myService = new MyService();
}

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

    public setReferences(references: IReferences): void {
    }

    public myMethod(): void {
        console.log('Hello world');
    }
}
Not available
import (
	"context"
	"fmt"

	cconf "github.com/pip-services4/pip-services4-go/pip-services4-components-go/config"
	cref "github.com/pip-services4/pip-services4-go/pip-services4-components-go/refer"
)

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

type MyService struct {
}

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

}

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

}

func (c *MyService) MyMethod() {
	fmt.Println("Hello world")
}
Not available
# Pre-requisites
from pip_services4_components.refer import Descriptor, IReferences, IReferenceable
from pip_services4_components.config import IConfigurable

# Service
class MyService(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 
myService = MyService()
Not available

The direct client

Now that we have our service, 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 service via two components: References and DependencyResolver. This last class is used to give a name to our service’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 service. Lastly, we create a method that invokes “my_method” from the service. Once our class is defined, we create an instance of it. The following code shows how to do this.

import { DependencyResolver, Descriptor, IReferences } from "pip-services4-components-node";
import { DirectClient } from "pip-services4-rpc-node";

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

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

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

// Instantiation
let client = new MyDirectClient();
Not available
import (
	"context"
	"fmt"

	cconf "github.com/pip-services4/pip-services4-go/pip-services4-components-go/config"
	cref "github.com/pip-services4/pip-services4-go/pip-services4-components-go/refer"
	rpcclnt "github.com/pip-services4/pip-services4-go/pip-services4-rpc-go/clients"
)

// Direct client
type MyDirectClient struct {
	*rpcclnt.DirectClient
	dependencyResolver *cref.DependencyResolver
	service  *MyService
}

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

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

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

// Instantiation
client := NewMyDirectClient();
Not available
# Pre-requisites

from pip_services4_rpc.clients import DirectClient
from pip_services4_components.refer import Descriptor, IReferences, DependencyResolver
from pip_services4_components.config import IConfigurable


# Direct client
class MyDirectClient(DirectClient):
    _dependencyResolver = DependencyResolver() 
        
    def __init__(self):
        super(MyDirectClient, self).__init__()
        self._service: MyController = None
        self._dependencyResolver.put("service", Descriptor("pip-services", "service", "*", "*", "1.0"))
        
        
    def set_references(self, references: IReferences):
        self._dependencyResolver.set_references(references)
        self._service = self._dependencyResolver.get_one_required("service")
        
    def my_method(self):
        self._service.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 service. The following code shows how to do it.

import { Descriptor, References } from "pip-services4-components-node";

// Reference settig
client.setReferences(References.fromTuples(
    new Descriptor("pip-services", "service", "service", "default", "1.0"), myService));
Not available
// Reference setting
client := NewMyDirectClient()
client.SetReferences(context.Background(), cref.NewReferencesFromTuples(context.Background(),
	cref.NewDescriptor("pip-services", "service", "service", "default", "1.0"), myService,
))
Not available
# Pre-requisites
from pip_services4_components.refer import References

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

Not available

Calling “my_method”

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

client.myMethod();
Not available
client.MyMethod()
Not available
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-services4-components-node";
import { DirectClient } from "pip-services4-rpc-node";

export async function main() {
    // Instantiation
    let myService = new MyService();

    // Instantiation
    let client = new MyDirectClient();

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

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

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

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

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


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

    public setReferences(references: IReferences): void {
    }

    public myMethod(): void {
        console.log('Hello world');
    }
}
Not available
import (
	"context"
	"fmt"

	cconf "github.com/pip-services4/pip-services4-go/pip-services4-components-go/config"
	cref "github.com/pip-services4/pip-services4-go/pip-services4-components-go/refer"
	rpcclnt "github.com/pip-services4/pip-services4-go/pip-services4-rpc-go/clients"
)

func main() {
	// Instantiation
	myService := &MyService{}

	// Instantiation
	client := NewMyDirectClient()

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

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

// Direct client
type MyDirectClient struct {
	*rpcclnt.DirectClient
	dependencyResolver *cref.DependencyResolver
	service            *MyService
}

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

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

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

type MyService struct {
}

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

}

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

}

func (c *MyService) MyMethod() {
	fmt.Println("Hello world")
}
Not available
# Pre-requisites
from pip_services4_rpc.clients import DirectClient
from pip_services4_components.refer import Descriptor, References, IReferences, IReferenceable, DependencyResolver
from pip_services4_components.config import IConfigurable


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

# Instantiation        
client = MyDirectClient()

# Controller
class MyService(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 
myService = MyService()

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

# 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 service with a method that prints “Hello world”. Then, we created a client with the service as a dependency and connected both components. Finally, we ran the created method from the client and saw the results.