Commandable HTTP
Key takeaways
CommandableHttpService | Service that receives remote calls via HTTP/REST protocol to execute commands defined in an ICommandable component. |
CommandSet | Set of commands that can be called via HTTP. |
CommandableHttpClient | Client used to consume a CommandableHttpService. |
Introduction
In this tutorial, you will learn how to create and consume CommandableHttpServices. This type of service is characterized by containing a set of commands that can be called via the HTTP/REST protocol.
In order to explain its functionality, this tutorial begins by explaining the necessary pre-requisites to work with this component. Then, it shows how to create a command set and a service that uses it. To complete the service, it describes how to include it in a ProcessContainer.
Once the service has been constructed, the tutorial shows how to consume it via a CommandableHttpClient and from any other application. Finally, it provides a full version of the service and client and a summary of what was learned.
Creating a CommandableHttpService
To create a CommandableHttpService, we need to import this class, create a command set, and implement our version of the service. Then, we build a process container to manage and run it. The following sections explain how to do this.
Pre-requisites
In order to create a CommandableHttpService, we need to import this component. This can be done with the following code:
import { CommandableHttpService } from "pip-services3-rpc-nodex";
using PipServices3.Rpc.Services;
import (
srvc "github.com/pip-services3-gox/pip-services3-rpc-gox/services"
)
import 'package:pip_services3_rpc/pip_services3_rpc.dart';
from pip_services3_rpc.services import CommandableHttpService
Command set
The key aspect of a CommandableHttpService is its dependence on a set of predefined commands. Thus, in our example, we define a command set containing one command named greeting, which is used to create the phrase “Hello {name}” for a given name. The following code shows how to do this.
import {
Command, CommandSet, ICommand,
ObjectSchema, Parameters, TypeCode
} from "pip-services3-commons-nodex";
export class FriendsCommandSet extends CommandSet {
private _controller: HelloFriendController;
public constructor(controller: HelloFriendController) {
super();
this._controller = controller;
this.addCommand(this.makeGreeting());
}
private makeGreeting(): ICommand {
return new Command(
'greeting',
new ObjectSchema(true).withRequiredProperty('name', TypeCode.String),
async (correlationId: string, args: Parameters) => {
let name = args.getAsString("name");
let res = this._controller.greeting(name);
return res;
}
);
}
}
using System;
using PipServices3.Commons.Commands;
using PipServices3.Commons.Run;
using PipServices3.Commons.Validate;
public class FriendsCommandSet : CommandSet
{
private HelloFriendController _controller;
public FriendsCommandSet(HelloFriendController controller)
{
_controller = controller;
AddCommand(MakeGreeting());
}
private ICommand MakeGreeting()
{
return new Command("greeting",
new ObjectSchema().WithRequiredProperty("name", TypeCode.String),
async (string correlationgId, Parameters args) =>
{
var name = args.GetAsString("name");
var res = _controller.Greeting(name);
return res;
}
);
}
}
import (
"context"
ccomand "github.com/pip-services3-gox/pip-services3-commons-gox/commands"
cconv "github.com/pip-services3-gox/pip-services3-commons-gox/convert"
crun "github.com/pip-services3-gox/pip-services3-commons-gox/run"
cvalid "github.com/pip-services3-gox/pip-services3-commons-gox/validate"
)
type FriendsCommandSet struct {
*ccomand.CommandSet
controller HelloFriendController
}
func NewFriendsCommandSet(controller HelloFriendController) *FriendsCommandSet {
c := FriendsCommandSet{}
c.controller = controller
c.CommandSet = ccomand.NewCommandSet()
c.AddCommand(c.makeGreeting())
return &c
}
func (c *FriendsCommandSet) makeGreeting() ccomand.ICommand {
return ccomand.NewCommand(
"greeting",
cvalid.NewObjectSchema().
WithRequiredProperty("name", cconv.String),
func(ctx context.Context, correlationId string, args *crun.Parameters) (result interface{}, err error) {
name := args.GetAsString("name")
return c.controller.Greeting(name), nil
},
)
}
import 'package:pip_services3_commons/pip_services3_commons.dart';
import 'package:pip_services3_rpc/pip_services3_rpc.dart';
class FriendsCommandSet extends CommandSet {
HelloFriendController _controller;
FriendsCommandSet(HelloFriendController controller)
: _controller = controller,
super() {
addCommand(_makeGreeting());
}
ICommand _makeGreeting() {
Future<dynamic> Function(String correlationId, Parameters args) action =
(String? correlationId, Parameters args) async {
var name = args.getAsString('name');
return _controller.greeting(name);
};
return Command(
'greeting',
ObjectSchema(true).withRequiredProperty('name', TypeCode.String),
action);
}
}
from pip_services3_commons.commands import Command, CommandSet, ICommand
from pip_services3_commons.run import Parameters
from pip_services3_commons.validate import Schema, ObjectSchema
from pip_services3_commons.convert import TypeCode
from typing import Optional
class FriendsCommandSet(CommandSet):
_controller: 'HelloFriendController'
def __init__(self, controller):
super().__init__()
self._controller = controller
self.add_command(self._make_greeting())
def _make_greeting(self) -> ICommand:
def handler(correlation_id: Optional[str], args: Parameters):
name = args.get_as_string("name")
res = self._controller.greeting(name)
return res
return Command(
"greeting",
ObjectSchema(True).with_required_property("name", TypeCode.String),
handler
)
CommandableHttpService
Now that we have our command set, we can code our CommandableHttpService. For this, we create a subclass of this component and add the controller as a dependency.
import { Descriptor} from "pip-services3-commons-nodex";
import { CommandableHttpService } from "pip-services3-rpc-nodex";
export class FriendCommandableHttpService extends CommandableHttpService {
public constructor() {
super("commandable_hello_friend");
this._dependencyResolver.put('controller', new Descriptor("hello-friend", "controller", "*", "*", "*"));
}
}
using PipServices3.Rpc.Services;
public class FriendCommandableHttpService: CommandableHttpService
{
public FriendCommandableHttpService(): base("commandable_hello_friend")
{
_dependencyResolver.Put("controller", new Descriptor("hello-friend", "controller", "*", "*", "*"));
}
}
import (
cref "github.com/pip-services3-gox/pip-services3-commons-gox/refer"
srvc "github.com/pip-services3-gox/pip-services3-rpc-gox/services"
)
type FriendCommandableHttpService struct {
*srvc.CommandableHttpService
DependencyResolver *cref.DependencyResolver
}
func NewFriendCommandableHttpService() *FriendCommandableHttpService {
c := &FriendCommandableHttpService{}
c.CommandableHttpService = srvc.InheritCommandableHttpService(c, "commandable_hello_friend")
c.DependencyResolver.Put("controller", cref.NewDescriptor("hello-friend", "controller", "*", "*", "*"))
return c
}
import 'package:pip_services3_commons/pip_services3_commons.dart';
import 'package:pip_services3_rpc/pip_services3_rpc.dart';
class FriendCommandableHttpService extends CommandableHttpService {
FriendCommandableHttpService() : super('commandable_hello_friend') {
dependencyResolver.put('controller', Descriptor('hello-friend', 'controller', '*', '*', '*'));
}
}
from pip_services3_rpc.services import CommandableHttpService
class FriendCommandableHttpService(CommandableHttpService):
def __init__(self):
super().__init__('commandable_hello_friend')
self._dependency_resolver.put('controller', Descriptor('hello-friend', 'controller', '*', '*', '*'))
Controller
The next step is to define a controller that contains the definition of our function.
import { CommandSet, ConfigParams, ICommandable, IConfigurable } from "pip-services3-commons-nodex";
export class HelloFriendController implements IConfigurable, ICommandable {
private _defaultName: string = "World";
private _commandSet: FriendsCommandSet;
public constructor() {
this._defaultName = "Pip User";
}
public configure(config: ConfigParams): void {
this._defaultName = config.getAsStringWithDefault('default_name', this._defaultName);
}
public getCommandSet(): CommandSet {
if (this._commandSet == null) {
this._commandSet = new FriendsCommandSet(this);
}
return this._commandSet;
}
public greeting(name: string): string {
return `Hello, ${name ?? this._defaultName}`;
}
}
using PipServices3.Commons.Commands;
using PipServices3.Commons.Config;
public class HelloFriendController : IConfigurable, ICommandable
{
private string _defaultName = "World";
private FriendsCommandSet __commandSet;
public HelloFriendController()
{
_defaultName = "Pip User";
}
public void Configure(ConfigParams config)
{
_defaultName = config.GetAsStringWithDefault("default_name", _defaultName);
}
public CommandSet GetCommandSet()
{
if (__commandSet == null)
__commandSet = new FriendsCommandSet(this);
return __commandSet;
}
public string Greeting(string name)
{
return $"Hello, {name ?? _defaultName} !";
}
}
import (
ccomand "github.com/pip-services3-gox/pip-services3-commons-gox/commands"
cconf "github.com/pip-services3-gox/pip-services3-commons-gox/config"
)
type HelloFriendController struct {
commandSet *FriendsCommandSet
defaultName string
}
func NewHelloFriendController() *HelloFriendController {
c := HelloFriendController{}
c.defaultName = "World"
return &c
}
func (c *HelloFriendController) Configure(ctx context.Context, config *cconf.ConfigParams) {
// You can read configuration parameters here...
}
func (c *HelloFriendController) GetCommandSet() *ccomand.CommandSet {
if c.commandSet == nil {
c.commandSet = NewFriendsCommandSet(*c)
}
return &c.commandSet.CommandSet
}
func (c *HelloFriendController) Greeting(name string) string {
if name != "" {
return "Hello, " + name + " !"
}
return "Hello, " + c.defaultName + " !"
}
import 'package:pip_services3_commons/pip_services3_commons.dart';
import 'package:pip_services3_rpc/pip_services3_rpc.dart';
class HelloFriendController implements IConfigurable, ICommandable {
String _defaultName = 'World';
FriendsCommandSet? _commandSet;
HelloFriendController() {
_defaultName = 'Pip User';
}
@override
void configure(ConfigParams config) {
_defaultName = config.getAsStringWithDefault('default_name', _defaultName);
}
@override
CommandSet getCommandSet() {
_commandSet ??= FriendsCommandSet(this);
return _commandSet!;
}
String greeting(String? name) {
return 'Hello, ${name ?? _defaultName}';
}
}
from pip_services3_commons.commands import ICommandable
from pip_services3_commons.config import IConfigurable
class HelloFriendController(IConfigurable, ICommandable):
__defaultName = "World"
__command_set: 'FriendsCommandSet' = None
def __init__(self):
self.__defaultName = "Pip User"
def configure(self, config):
self.__defaultName = config.get_as_string_with_default("default_name", self.__defaultName)
def get_command_set(self) -> CommandSet:
if self.__command_set is None:
self.__command_set = FriendsCommandSet(self)
return self.__command_set
def greeting(self, name):
return f"Hello, {name if name else self.__defaultName} !"
Factory
Now, we create a factory that builds our service and controller. The code below shows how to do this.
import { Factory } from "pip-services3-components-nodex";
import { Descriptor } from "pip-services3-commons-nodex";
export class HelloFriendServiceFactory extends Factory {
public constructor() {
super();
var CommandableHttpServiceDescriptor = new Descriptor("hello-friend", "service", "commandable-http", "*", "1.0"); // View
var ControllerDescriptor = new Descriptor("hello-friend", "controller", "default", "*", "1.0"); // Controller
this.registerAsType(CommandableHttpServiceDescriptor, FriendCommandableHttpService);
this.registerAsType(ControllerDescriptor, HelloFriendController);
}
}
using PipServices3.Commons.Refer;
using PipServices3.Components.Build;
public class HelloFriendServiceFactory: Factory
{
public HelloFriendServiceFactory()
{
var CommandableHttpServiceDescriptor = new Descriptor("hello-friend", "service", "commandable-http", "*", "1.0"); // View
var ControllerDescriptor = new Descriptor("hello-friend", "controller", "default", "*", "1.0"); // Controller
RegisterAsType(CommandableHttpServiceDescriptor, typeof(FriendCommandableHttpService));
RegisterAsType(ControllerDescriptor, typeof(HelloFriendController));
}
}
import (
cref "github.com/pip-services3-gox/pip-services3-commons-gox/refer"
cbuild "github.com/pip-services3-gox/pip-services3-components-gox/build"
)
type HelloFriendServiceFactory struct {
*cbuild.Factory
}
func NewHelloFriendServiceFactory() *HelloFriendServiceFactory {
c := HelloFriendServiceFactory{}
c.Factory = cbuild.NewFactory()
commandableHttpServiceDescriptor := cref.NewDescriptor("hello-friend", "service", "commandable-http", "*", "1.0") // View
controllerDescriptor := cref.NewDescriptor("hello-friend", "controller", "default", "*", "1.0") // Controller
c.RegisterType(commandableHttpServiceDescriptor, NewFriendCommandableHttpService)
c.RegisterType(controllerDescriptor, NewHelloFriendController)
return &c
}
import 'package:pip_services3_commons/pip_services3_commons.dart';
import 'package:pip_services3_components/pip_services3_components.dart';
import 'package:pip_services3_rpc/pip_services3_rpc.dart';
class HelloFriendServiceFactory extends Factory {
HelloFriendServiceFactory() : super() {
var CommandableHttpServiceDescriptor = Descriptor(
'hello-friend', 'service', 'commandable-http', '*', '1.0'); // View
var ControllerDescriptor = Descriptor(
'hello-friend', 'controller', 'default', '*', '1.0'); // Controller
registerAsType(
CommandableHttpServiceDescriptor, FriendCommandableHttpService);
registerAsType(ControllerDescriptor, HelloFriendController);
}
}
from pip_services3_commons.refer import Descriptor
from pip_services3_components.build import Factory
class HelloFriendServiceFactory(Factory):
def __init__(self):
super(HelloFriendServiceFactory, self).__init__()
CommandableHttpServiceDescriptor = Descriptor('hello-friend', 'service', 'commandable-http', '*', '1.0') # View
ControllerDescriptor = Descriptor('hello-friend', 'controller', 'default', '*', '1.0') # Controller
self.register_as_type(CommandableHttpServiceDescriptor, FriendCommandableHttpService) # View
self.register_as_type(ControllerDescriptor, HelloFriendController) # Controller
Container
After we have our controller and factory, we create a process container to manage our service’s lifecycle.
import { ProcessContainer } from "pip-services3-container-nodex";
import { DefaultRpcFactory } from "pip-services3-rpc-nodex";
import { DefaultSwaggerFactory } from "pip-services3-swagger-nodex";
export class HelloFriendProcess extends ProcessContainer {
public constructor() {
super("hello-friend", "HelloFriend microservice");
this._configPath = "./config.yaml";
this._factories.add(new HelloFriendServiceFactory());
this._factories.add(new DefaultRpcFactory());
this._factories.add(new DefaultSwaggerFactory());
}
}
using PipServices3.Container;
using PipServices3.Rpc.Build;
using PipServices3.Swagger.Build;
public class HelloFriendProcess: ProcessContainer
{
public HelloFriendProcess(): base("hello-friend", "HelloFriend microservice")
{
_configPath = "../../../config.yaml";
_factories.Add(new HelloFriendServiceFactory());
_factories.Add(new DefaultRpcFactory());
_factories.Add(new DefaultSwaggerFactory());
}
}
import (
rbuild "github.com/pip-services3-gox/pip-services3-rpc-gox/build"
sbuild "github.com/pip-services3-gox/pip-services3-swagger-gox/build"
cproc "github.com/pip-services3-gox/pip-services3-container-gox/container"
)
type HelloFriendProcess struct {
*cproc.ProcessContainer
}
func NewHelloFriendProcess() *HelloFriendProcess {
c := &HelloFriendProcess{
ProcessContainer: cproc.NewProcessContainer("Hellow", "Hello friend microservice"),
}
c.SetConfigPath("./config.yaml")
c.AddFactory(NewHelloFriendServiceFactory())
c.AddFactory(rbuild.NewDefaultRpcFactory())
c.AddFactory(sbuild.NewDefaultSwaggerFactory())
return c
}
import 'package:pip_services3_container/pip_services3_container.dart';
import 'package:pip_services3_rpc/pip_services3_rpc.dart';
import 'package:pip_services3_swagger/pip_services3_swagger.dart';
class HelloFriendProcess extends ProcessContainer {
HelloFriendProcess() : super('hello-friend', 'HelloFriend microservice') {
configPath = './config.yaml';
factories.add(HelloFriendServiceFactory());
factories.add(DefaultRpcFactory());
factories.add(DefaultSwaggerFactory());
}
}
from pip_services3_container.ProcessContainer import ProcessContainer
from pip_services3_rpc.build import DefaultRpcFactory
from pip_services3_swagger.build.DefaultSwaggerFactory import DefaultSwaggerFactory
class HelloFriendProcess(ProcessContainer):
def __init__(self):
super(HelloFriendProcess, self).__init__('hello-friend', 'HelloFriend microservice')
self._config_path = './config2DComm.yaml'
self._factories.add(HelloFriendServiceFactory())
self._factories.add(DefaultRpcFactory())
self._factories.add(DefaultSwaggerFactory())
And, then run it via the run() method.
export async function main() {
try {
let proc = new HelloFriendProcess();
proc.run(process.argv);
} catch (ex) {
console.error(ex);
}
}
class Program
{
static void Main(string[] args)
{
try
{
var runner = (new HelloFriendProcess()).RunAsync(args);
runner.Wait();
}
catch (Exception ex)
{
Console.Error.WriteLine(ex);
}
}
}
import (
"os"
)
func main() {
proc := NewHelloFriendProcess()
proc.Run(os.Args)
}
void main(List<String> argument) {
try {
var proc = HelloFriendProcess();
proc.run(argument);
} catch (ex) {
print(ex);
}
}
if __name__ == '__main__':
runner = HelloFriendProcess()
print("run")
try:
runner.run()
except Exception as ex:
print(ex)
Once our service is running, it is ready to receive requests.
Consuming a CommandableHttpService
There are several ways to consume our service. In this tutorial, we will consider two of them, namely using Pip.Services' CommandableHttpClient class and via code.
Using a CommandableHttpClient
Pip.Services offers the CommandableHttpClient component, which can be used to interact with a CommandableHttpService. In order to use it, we need to import it first.
import { CommandableHttpClient } from "pip-services3-rpc-nodex";
using PipServices3.Rpc.Clients;
import (
clnt "github.com/pip-services3-gox/pip-services3-rpc-gox/clients"
)
import 'package:pip_services3_rpc/pip_services3_rpc.dart';
from pip_services3_rpc.clients import CommandableHttpClient
Once imported, we can create our client by extending this class. The following example shows how to do this:
export class MyCommandableHttpClient extends CommandableHttpClient {
public constructor(baseRoute: string) {
super(baseRoute);
}
public async greeting(correlationId: string): Promise<string> {
return await this.callCommand<string>("greeting", correlationId, { name: "Peter" });
}
}
public class MyCommandableHttpClient : CommandableHttpClient
{
public MyCommandableHttpClient(string baseRoute) : base(baseRoute) { }
public async Task<string> Greeting(string correlationId)
{
return await CallCommandAsync<string>("greeting", correlationId, new { name = "Peter" });
}
}
import (
"reflect"
cdata "github.com/pip-services3-gox/pip-services3-commons-gox/data"
clnt "github.com/pip-services3-gox/pip-services3-rpc-gox/clients"
)
type MyCommandableHttpClient struct {
*clnt.CommandableHttpClient
}
func NewMyCommandableHttpClient(baseRoute string) *MyCommandableHttpClient {
c := MyCommandableHttpClient{}
c.CommandableHttpClient = clnt.NewCommandableHttpClient(baseRoute)
return &c
}
func (c *MyCommandableHttpClient) Greeting(correlationId string) (result string, err error) {
params := cdata.NewEmptyStringValueMap()
params.Put("name", "Peter")
res, calErr := c.CallCommand(context.Background(), "greeting", correlationId, cdata.NewAnyValueMapFromValue(params.Value()))
return clnt.HandleHttpResponse[string](res, correlationId)
}
class MyCommandableHttpClient extends CommandableHttpClient {
MyCommandableHttpClient(String baseRoute) : super(baseRoute);
Future<String> greeting(String correlationId) async {
return await callCommand('greeting', correlationId, {'name': 'Peter'});
}
}
class MyCommandableHttpClient(CommandableHttpClient):
def __init__(self, base_route: str):
super().__init__(base_route)
def greeting(self, correlation_id):
return self.call_command("greeting", correlation_id, {'name': 'Peter'})
Which, we then instantiate, configure, and connect to our previously defined service.
let client = new MyCommandableHttpClient("commandable_hello_friend");
client.configure(ConfigParams.fromTuples(
"connection.protocol", "http",
"connection.host", "localhost",
"connection.port", 8080
));
await client.open(null);
var client = new MyCommandableHttpClient("commandable_hello_friend");
client.Configure(ConfigParams.FromTuples(
"connection.protocol", "http",
"connection.host", "localhost",
"connection.port", 8080
));
await client.OpenAsync(null);
import (
"fmt"
"reflect"
"time"
cconf "github.com/pip-services3-gox/pip-services3-commons-gox/config"
)
client := NewMyCommandableHttpClient("commandable_hello_friend")
client.Configure(context.Background(), cconf.NewConfigParamsFromTuples(
"connection.protocol", "http",
"connection.host", "localhost",
"connection.port", 8080,
))
client.Open(context.Background(), "")
defer client.Close(context.Background(), "")
var client = MyCommandableHttpClient('commandable_hello_friend');
client.configure(ConfigParams.fromTuples([
'connection.protocol', 'http',
'connection.host', 'localhost',
'connection.port', 8080
]));
await client.open(null);
client = MyCommandableHttpClient("commandable_hello_friend")
client.configure(ConfigParams.from_tuples("connection.protocol", "http",
"connection.host", "localhost",
"connection.port", 8080))
client.open(None)
And then, we request a greeting and get our response.
let data = await client.greeting("123"); // Returns 'Hello, Peter !'
var data = await client.Greeting("123"); // Returns 'Hello, Peter !'
data, _ := client.Greeting(context.Background(), "123")
fmt.Println(*data) // Returns 'Hello, Peter !'
var data = await client.greeting('123'); // Returns 'Hello, Peter !'
data = client.greeting("123") # Returns 'Hello, Peter !'
Using code
We can also call our service via code and obtain a similar result. For example:
const restify = require('restify-clients');
export async function main() {
let url = 'http://localhost:8080';
let rest = restify.createJsonClient({ url: url, version: '*' });
let data = await new Promise<string>((resolve, reject) => {
rest.post('/commandable_hello_friend/greeting',
{name: "Peter"},
(err, req, res, data) => {
if (err != null) {
reject(err);
return;
}
resolve(data);
});
});
console.log(data);
}
using System;
using System.Text;
using System.Net.Http;
using System.Threading.Tasks;
var content = "{ \"name\": \"Peter\" }";
var result = new StringContent(content, Encoding.UTF8, "application/json");
var client = new HttpClient();
var response = await client.PostAsync("http://localhost:8080/commandable_hello_friend/greeting", result);
var responseString = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseString); // Returns '"Hello, Cosme !"'
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"time"
)
postBody, _ := json.Marshal(map[string]string{
"name": "Peter",
})
responseBody := bytes.NewBuffer(postBody)
resp, _ := http.Post("http://localhost:8080/commandable_hello_friend/greeting", "application/json", responseBody)
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
sb := string(body)
fmt.Println(sb) // Returns '"Hello, Cosme !"'
import 'dart:convert';
import 'package:http/http.dart' as http;
void main(List<String> argument) async {
var client = http.Client();
try {
var response = await client.post(
Uri.parse('http://localhost:8080/commandable_hello_friend/greeting'),
body: json.encode({'name': 'Peter'}));
var res = response.body;
print(res);
} finally {
client.close();
}
}
import requests
res = requests.post("http://localhost:8080/commandable_hello_friend/greeting", json={"name": "Cosme"})
res.text # Returns '"Hello, Cosme !"'
Final code
Below is the complete code for the service and client.
Service
Code Example
import {
Command, CommandSet, ConfigParams, Descriptor, ICommand,
ICommandable,
IConfigurable,
ObjectSchema, Parameters, TypeCode
} from "pip-services3-commons-nodex";
import { Factory } from "pip-services3-components-nodex";
import { ProcessContainer } from "pip-services3-container-nodex";
import { CommandableHttpService, DefaultRpcFactory } from "pip-services3-rpc-nodex";
import { DefaultSwaggerFactory } from "pip-services3-swagger-nodex";
const restify = require('restify-clients');
export async function main() {
// Runner
try {
let proc = new HelloFriendProcess();
proc.run(process.argv);
} catch (ex) {
console.error(ex);
}
}
// Command set
export class FriendsCommandSet extends CommandSet {
private _controller: HelloFriendController;
public constructor(controller: HelloFriendController) {
super();
this._controller = controller;
this.addCommand(this.makeGreeting());
}
private makeGreeting(): ICommand {
return new Command(
'greeting',
new ObjectSchema(true).withRequiredProperty('name', TypeCode.String),
async (correlationId: string, args: Parameters) => {
let name = args.getAsString("name");
let res = this._controller.greeting(name);
return res;
}
);
}
}
// Service
export class FriendCommandableHttpService extends CommandableHttpService {
public constructor() {
super("commandable_hello_friend");
this._dependencyResolver.put('controller', new Descriptor("hello-friend", "controller", "*", "*", "*"));
}
}
// Controller
export class HelloFriendController implements IConfigurable, ICommandable {
private _defaultName: string = "World";
private _commandSet: FriendsCommandSet;
public constructor() {
this._defaultName = "Pip User";
}
public configure(config: ConfigParams): void {
this._defaultName = config.getAsStringWithDefault('default_name', this._defaultName);
}
public getCommandSet(): CommandSet {
if (this._commandSet == null) {
this._commandSet = new FriendsCommandSet(this);
}
return this._commandSet;
}
public greeting(name: string): string {
return `Hello, ${name ?? this._defaultName}`;
}
}
// Factory
export class HelloFriendServiceFactory extends Factory {
public constructor() {
super();
var CommandableHttpServiceDescriptor = new Descriptor("hello-friend", "service", "commandable-http", "*", "1.0"); // View
var ControllerDescriptor = new Descriptor("hello-friend", "controller", "default", "*", "1.0"); // Controller
this.registerAsType(CommandableHttpServiceDescriptor, FriendCommandableHttpService);
this.registerAsType(ControllerDescriptor, HelloFriendController);
}
}
// Container
export class HelloFriendProcess extends ProcessContainer {
public constructor() {
super("hello-friend", "HelloFriend microservice");
this._configPath = "./config.yaml";
this._factories.add(new HelloFriendServiceFactory());
this._factories.add(new DefaultRpcFactory());
this._factories.add(new DefaultSwaggerFactory());
}
}
Code Example
using System;
using PipServices3.Commons.Commands;
using PipServices3.Commons.Config;
using PipServices3.Commons.Refer;
using PipServices3.Commons.Run;
using PipServices3.Commons.Validate;
using PipServices3.Components.Build;
using PipServices3.Container;
using PipServices3.Rpc.Build;
using PipServices3.Rpc.Services;
using PipServices3.Swagger.Build;
namespace ExampleApp
{
class Program
{
// Runner
static void Main(string[] args)
{
try
{
var runner = (new HelloFriendProcess()).RunAsync(args);
runner.Wait();
}
catch (Exception ex)
{
Console.Error.WriteLine(ex);
}
}
}
// Command set
public class FriendsCommandSet : CommandSet
{
private HelloFriendController _controller;
public FriendsCommandSet(HelloFriendController controller)
{
_controller = controller;
AddCommand(MakeGreeting());
}
private ICommand MakeGreeting()
{
return new Command("greeting",
new ObjectSchema().WithRequiredProperty("name", TypeCode.String),
async (string correlationgId, Parameters args) =>
{
var name = args.GetAsString("name");
var res = _controller.Greeting(name);
return res;
}
);
}
}
// Controller
public class HelloFriendController : IConfigurable, ICommandable
{
private string _defaultName = "World";
private FriendsCommandSet _commandSet;
public HelloFriendController()
{
_defaultName = "Pip User";
}
public void Configure(ConfigParams config)
{
_defaultName = config.GetAsStringWithDefault("default_name", _defaultName);
}
public CommandSet GetCommandSet()
{
if (_commandSet == null)
_commandSet = new FriendsCommandSet(this);
return _commandSet;
}
public string Greeting(string name)
{
return $"Hello, {name ?? _defaultName} !";
}
}
// Service
public class FriendCommandableHttpService : CommandableHttpService
{
public FriendCommandableHttpService() : base("commandable_hello_friend")
{
_dependencyResolver.Put("controller", new Descriptor("hello-friend", "controller", "*", "*", "*"));
}
}
// Factory
public class HelloFriendServiceFactory : Factory
{
public HelloFriendServiceFactory()
{
var CommandableHttpServiceDescriptor = new Descriptor("hello-friend", "service", "commandable-http", "*", "1.0"); // View
var ControllerDescriptor = new Descriptor("hello-friend", "controller", "default", "*", "1.0"); // Controller
RegisterAsType(CommandableHttpServiceDescriptor, typeof(FriendCommandableHttpService));
RegisterAsType(ControllerDescriptor, typeof(HelloFriendController));
}
}
// Container
public class HelloFriendProcess : ProcessContainer
{
public HelloFriendProcess() : base("hello-friend", "HelloFriend microservice")
{
_configPath = "../../../config.yaml";
_factories.Add(new HelloFriendServiceFactory());
_factories.Add(new DefaultRpcFactory());
_factories.Add(new DefaultSwaggerFactory());
}
}
}
Code Example
package main
import (
"context"
"os"
ccomand "github.com/pip-services3-gox/pip-services3-commons-gox/commands"
cconf "github.com/pip-services3-gox/pip-services3-commons-gox/config"
cconv "github.com/pip-services3-gox/pip-services3-commons-gox/convert"
cref "github.com/pip-services3-gox/pip-services3-commons-gox/refer"
crun "github.com/pip-services3-gox/pip-services3-commons-gox/run"
cvalid "github.com/pip-services3-gox/pip-services3-commons-gox/validate"
cbuild "github.com/pip-services3-gox/pip-services3-components-gox/build"
cproc "github.com/pip-services3-gox/pip-services3-container-gox/container"
rbuild "github.com/pip-services3-gox/pip-services3-rpc-gox/build"
srvc "github.com/pip-services3-gox/pip-services3-rpc-gox/services"
sbuild "github.com/pip-services3-gox/pip-services3-swagger-gox/build"
)
// Runner
func main() {
proc := NewHelloFriendProcess()
proc.Run(context.Background(), os.Environ())
}
// Command set
type FriendsCommandSet struct {
ccomand.CommandSet
controller HelloFriendController
}
func NewFriendsCommandSet(controller HelloFriendController) *FriendsCommandSet {
c := FriendsCommandSet{}
c.controller = controller
c.CommandSet = *ccomand.NewCommandSet()
c.AddCommand(c.makeGreeting())
return &c
}
func (c *FriendsCommandSet) makeGreeting() ccomand.ICommand {
return ccomand.NewCommand(
"greeting",
cvalid.NewObjectSchema().
WithRequiredProperty("name", cconv.String),
func(ctx context.Context, correlationId string, args *crun.Parameters) (result interface{}, err error) {
name := args.GetAsString("name")
return c.controller.Greeting(name), nil
},
)
}
// Service
type FriendCommandableHttpService struct {
*srvc.CommandableHttpService
}
func NewFriendCommandableHttpService() *FriendCommandableHttpService {
c := &FriendCommandableHttpService{}
c.CommandableHttpService = srvc.InheritCommandableHttpService(c, "commandable_hello_friend")
c.DependencyResolver.Put(context.Background(), "controller", cref.NewDescriptor("hello-friend", "controller", "*", "*", "*"))
return c
}
// Controller
type HelloFriendController struct {
commandSet *FriendsCommandSet
defaultName string
}
func NewHelloFriendController() *HelloFriendController {
c := HelloFriendController{}
c.defaultName = "World"
return &c
}
func (c *HelloFriendController) Configure(config *cconf.ConfigParams) {
// You can read configuration parameters here...
}
func (c *HelloFriendController) GetCommandSet() *ccomand.CommandSet {
if c.commandSet == nil {
c.commandSet = NewFriendsCommandSet(*c)
}
return &c.commandSet.CommandSet
}
func (c *HelloFriendController) Greeting(name string) string {
if name != "" {
return "Hello, " + name + " !"
}
return "Hello, " + c.defaultName + " !"
}
// Factory
type HelloFriendServiceFactory struct {
cbuild.Factory
}
func NewHelloFriendServiceFactory() *HelloFriendServiceFactory {
c := HelloFriendServiceFactory{}
c.Factory = *cbuild.NewFactory()
commandableHttpServiceDescriptor := cref.NewDescriptor("hello-friend", "service", "commandable-http", "*", "1.0") // View
controllerDescriptor := cref.NewDescriptor("hello-friend", "controller", "default", "*", "1.0") // Controller
c.RegisterType(commandableHttpServiceDescriptor, NewFriendCommandableHttpService)
c.RegisterType(controllerDescriptor, NewHelloFriendController)
return &c
}
// Container
type HelloFriendProcess struct {
*cproc.ProcessContainer
}
func NewHelloFriendProcess() *HelloFriendProcess {
c := &HelloFriendProcess{
ProcessContainer: cproc.NewProcessContainer("Hellow", "Hello friend microservice"),
}
c.SetConfigPath("./config.yaml")
c.AddFactory(NewHelloFriendServiceFactory())
c.AddFactory(rbuild.NewDefaultRpcFactory())
c.AddFactory(sbuild.NewDefaultSwaggerFactory())
return c
}
Code Example
import 'package:pip_services3_commons/pip_services3_commons.dart';
import 'package:pip_services3_components/pip_services3_components.dart';
import 'package:pip_services3_container/pip_services3_container.dart';
import 'package:pip_services3_rpc/pip_services3_rpc.dart';
import 'package:pip_services3_swagger/pip_services3_swagger.dart';
void main(List<String> argument) async {
// Runner
try {
var proc = HelloFriendProcess();
proc.run(argument);
} catch (ex) {
print(ex);
}
}
// Command set
class FriendsCommandSet extends CommandSet {
HelloFriendController _controller;
FriendsCommandSet(HelloFriendController controller)
: _controller = controller,
super() {
addCommand(_makeGreeting());
}
ICommand _makeGreeting() {
Future<dynamic> Function(String correlationId, Parameters args) action =
(String? correlationId, Parameters args) async {
var name = args.getAsString('name');
return _controller.greeting(name);
};
return Command(
'greeting',
ObjectSchema(true).withRequiredProperty('name', TypeCode.String),
action);
}
}
// Service
class FriendCommandableHttpService extends CommandableHttpService {
FriendCommandableHttpService() : super('commandable_hello_friend') {
dependencyResolver.put(
'controller', Descriptor('hello-friend', 'controller', '*', '*', '*'));
}
}
// Controller
class HelloFriendController implements IConfigurable, ICommandable {
String _defaultName = 'World';
FriendsCommandSet? _commandSet;
HelloFriendController() {
_defaultName = 'Pip User';
}
@override
void configure(ConfigParams config) {
_defaultName = config.getAsStringWithDefault('default_name', _defaultName);
}
@override
CommandSet getCommandSet() {
_commandSet ??= FriendsCommandSet(this);
return _commandSet!;
}
String greeting(String? name) {
return 'Hello, ${name ?? _defaultName}';
}
}
// Factory
class HelloFriendServiceFactory extends Factory {
HelloFriendServiceFactory() : super() {
var CommandableHttpServiceDescriptor = Descriptor(
'hello-friend', 'service', 'commandable-http', '*', '1.0'); // View
var ControllerDescriptor = Descriptor(
'hello-friend', 'controller', 'default', '*', '1.0'); // Controller
registerAsType(
CommandableHttpServiceDescriptor, FriendCommandableHttpService);
registerAsType(ControllerDescriptor, HelloFriendController);
}
}
// Container
class HelloFriendProcess extends ProcessContainer {
HelloFriendProcess() : super('hello-friend', 'HelloFriend microservice') {
configPath = './config.yaml';
factories.add(HelloFriendServiceFactory());
factories.add(DefaultRpcFactory());
factories.add(DefaultSwaggerFactory());
}
}
Code Example
# Command set
from pip_services3_commons.commands import Command, CommandSet, ICommand
from pip_services3_commons.run import Parameters
from pip_services3_commons.validate import Schema, ObjectSchema
from pip_services3_commons.convert import TypeCode
from typing import Optional
class FriendsCommandSet(CommandSet):
_controller: 'HelloFriendController'
def __init__(self, controller):
super().__init__()
self._controller = controller
self.add_command(self._make_greeting())
def _make_greeting(self) -> ICommand:
def handler(correlation_id: Optional[str], args: Parameters):
name = args.get_as_string("name")
res = self._controller.greeting(name)
return res
return Command(
"greeting",
ObjectSchema(True).with_required_property("name", TypeCode.String),
handler
)
# Controller
from pip_services3_commons.commands import ICommandable
from pip_services3_commons.config import IConfigurable
class HelloFriendController(IConfigurable, ICommandable):
__defaultName = "World"
__command_set: 'FriendsCommandSet' = None
def __init__(self):
self.__defaultName = "Pip User"
def configure(self, config):
self.__defaultName = config.get_as_string_with_default("default_name", self.__defaultName)
def get_command_set(self) -> CommandSet:
if self.__command_set is None:
self.__command_set = FriendsCommandSet(self)
return self.__command_set
def greeting(self, name):
return f"Hello, {name if name else self.__defaultName} !"
# Service
from pip_services3_rpc.services import CommandableHttpService
class FriendCommandableHttpService(CommandableHttpService):
def __init__(self):
super().__init__('commandable_hello_friend')
self._dependency_resolver.put('controller', Descriptor('hello-friend', 'controller', '*', '*', '*'))
# Factory
from pip_services3_commons.refer import Descriptor
from pip_services3_components.build import Factory
class HelloFriendServiceFactory(Factory):
def __init__(self):
super(HelloFriendServiceFactory, self).__init__()
CommandableHttpServiceDescriptor = Descriptor('hello-friend', 'service', 'commandable-http', '*', '1.0') # View
ControllerDescriptor = Descriptor('hello-friend', 'controller', 'default', '*', '1.0') # Controller
self.register_as_type(CommandableHttpServiceDescriptor, FriendCommandableHttpService) # View
self.register_as_type(ControllerDescriptor, HelloFriendController) # Controller
from pip_services3_container.ProcessContainer import ProcessContainer
from pip_services3_rpc.build import DefaultRpcFactory
from pip_services3_swagger.build.DefaultSwaggerFactory import DefaultSwaggerFactory
# Container
class HelloFriendProcess(ProcessContainer):
def __init__(self):
super(HelloFriendProcess, self).__init__('hello-friend', 'HelloFriend microservice')
self._config_path = './config.yaml'
self._factories.add(HelloFriendServiceFactory())
self._factories.add(DefaultRpcFactory())
self._factories.add(DefaultSwaggerFactory())
# Runner
if __name__ == '__main__':
runner = HelloFriendProcess()
print("run")
try:
runner.run()
except Exception as ex:
print(ex)
Configuration file
Code Example
---
# Container context
- descriptor: "pip-services:context-info:default:default:1.0"
name: "hello-friend"
description: "HelloFriend microservice"
# Console logger
- descriptor: "pip-services:logger:console:default:1.0"
level: "trace"
# Performance counter that post values to log
- descriptor: "pip-services:counters:log:default:1.0"
# Controller
- descriptor: "hello-friend:controller:default:default:1.0"
default_name: "Friend"
# Shared HTTP Endpoint
- descriptor: "pip-services:endpoint:http:default:1.0"
connection:
protocol: http
host: 0.0.0.0
port: 8080
# Commandable HTTP service
- descriptor: "hello-friend:service:commandable-http:default:1.0"
swagger:
enable: true
auto: true
route: swagger
name: Friends Service
description: Commandable REST API
# Heartbeat service
- descriptor: "pip-services:heartbeat-service:http:default:1.0"
# Status service
- descriptor: "pip-services:status-service:http:default:1.0"
# Swagger service
- descriptor: "pip-services:swagger-service:http:default:1.0"
Client
Code Example
import { ConfigParams } from "pip-services3-commons-nodex";
import { CommandableHttpClient } from "pip-services3-rpc-nodex";
export async function main() {
let client = new MyCommandableHttpClient("commandable_hello_friend");
client.configure(ConfigParams.fromTuples(
"connection.protocol", "http",
"connection.host", "localhost",
"connection.port", 8080
));
await client.open(null);
let data = await client.greeting("123"); // Returns 'Hello, Peter !'
console.log(data);
}
export class MyCommandableHttpClient extends CommandableHttpClient {
public constructor(baseRoute: string) {
super(baseRoute);
}
public async greeting(correlationId: string): Promise<string> {
return await this.callCommand<string>("greeting", correlationId, { name: "Peter" });
}
}
Code Example
using System.Threading.Tasks;
using PipServices3.Commons.Config;
using PipServices3.Rpc.Clients;
namespace ExampleApp
{
class Program
{
static void Main(string[] args)
{
var client = new MyCommandableHttpClient("commandable_hello_friend");
client.Configure(ConfigParams.FromTuples(
"connection.protocol", "http",
"connection.host", "localhost",
"connection.port", 8080
));
client.OpenAsync(null).Wait();
var data = client.Greeting("123"); // Returns 'Hello, Peter !'
}
}
public class MyCommandableHttpClient : CommandableHttpClient
{
public MyCommandableHttpClient(string baseRoute) : base(baseRoute) { }
public async Task<string> Greeting(string correlationId)
{
return await CallCommandAsync<string>("greeting", correlationId, new { name = "Peter" });
}
}
}
Code Example
import (
"context"
"fmt"
cconf "github.com/pip-services3-gox/pip-services3-commons-gox/config"
cdata "github.com/pip-services3-gox/pip-services3-commons-gox/data"
clnt "github.com/pip-services3-gox/pip-services3-rpc-gox/clients"
)
func main() {
client := NewMyCommandableHttpClient("commandable_hello_friend")
client.Configure(context.Background(), cconf.NewConfigParamsFromTuples(
"connection.protocol", "http",
"connection.host", "localhost",
"connection.port", 8080,
))
client.Open(context.Background(), "")
defer client.Close(context.Background(), "")
data, _ := client.Greeting(context.Background(), "123") // Returns 'Hello, Peter !'
fmt.Println(data)
}
type MyCommandableHttpClient struct {
*clnt.CommandableHttpClient
}
func NewMyCommandableHttpClient(baseRoute string) *MyCommandableHttpClient {
c := MyCommandableHttpClient{}
c.CommandableHttpClient = clnt.NewCommandableHttpClient(baseRoute)
return &c
}
func (c *MyCommandableHttpClient) Greeting(ctx context.Context, correlationId string) (result string, err error) {
params := cdata.NewEmptyStringValueMap()
params.Put("name", "Peter")
res, calErr := c.CallCommand(context.Background(), "greeting", correlationId, cdata.NewAnyValueMapFromValue(params.Value()))
if calErr != nil {
return "", calErr
}
return clnt.HandleHttpResponse[string](res, correlationId)
}
Code Example
import 'package:pip_services3_commons/pip_services3_commons.dart';
import 'package:pip_services3_rpc/pip_services3_rpc.dart';
export async function main() {
var client = MyCommandableHttpClient('commandable_hello_friend');
client.configure(ConfigParams.fromTuples([
'connection.protocol', 'http',
'connection.host', 'localhost',
'connection.port', 8080
]));
await client.open(null);
var data = await client.greeting('123'); // Returns 'Hello, Peter !'
print(data);
}
class MyCommandableHttpClient extends CommandableHttpClient {
MyCommandableHttpClient(String baseRoute) : super(baseRoute);
Future<String> greeting(String correlationId) async {
return await callCommand('greeting', correlationId, {'name': 'Peter'});
}
}
Code Example
from pip_services3_rpc.clients import CommandableHttpClient
from pip_services3_commons.config import ConfigParams
class MyCommandableHttpClient(CommandableHttpClient):
def greeting(self, correlation_id):
return self.call_command("greeting", None, {'name': 'Peter'})
client = MyCommandableHttpClient("commandable_hello_friend")
client.configure(ConfigParams.from_tuples("connection.protocol", "http",
"connection.host", "localhost",
"connection.port", 8080))
client.open(None)
data = client.greeting("123") # Returns 'Hello, Peter !'
Wrapping up
In this tutorial, we have learned what is and how to create a CommandableHttpService, and how to consume it via a CommandableHttpClient and from any app via code.