REST Client

How to use the RestClient component.

Key takeaways

RestClient Component used to call remote endpoints using the HTTP/REST protocol.
RestService Component used to receive remote calls via the HTTP/REST protocol.
GET, HEAD, POST, PUT, DELETE HTTP methods supported by the RestClient component.

Introduction

A REST client is a program used to communicate with a service via the HTTP/REST protocol. Within Pip.Services, the RestClient component can be used as a base to build REST clients.

In this tutorial, you will be introduced to the RestClient component. First, we will see how to create a REST service by using the RestService class. Then, we will learn how to create a REST client with a class that extends the RestClient component. Following this, we will understand how to use the different HTML methods to communicate between the client and the service. We will end by reviewing what we learned in the different sections.

The REST service

Our first step is to create a REST service. For this, we create a subclass of the RestService class. To show the different HTTP communication methods, this subclass includes one function per HTTP method. Each of these functions returns a message and a data parameter. Our component also includes a register() method, which is used to register the route for each of the HTTP methods.

Once we have defined our REST service, we instantiate and configure it to run on our local machine. Then, we make it available with the open() method. The following code shows how this program looks like:

import { ConfigParams } from "pip-services3-commons-nodex";
import { RestService } from "pip-services3-rpc-nodex";


export class MyRestService extends RestService {

    public constructor() {
        super();
        this._baseRoute = "/my_service";
    }

    // GET
    public async myPageGet(req: any, res: any): Promise<void> {
        let result = req.query.message + ", " + req.route.params.name;
        this.sendResult(req, res, result);
    }

    // HEAD
    public async myPageHead(req: any, res: any): Promise<void> {
        this.sendResult(req, res, null);
    }

    // POST
    public async myPagePost(req: any, res: any): Promise<void> {
        let result = req.query.message + ", " + req.route.params.name + ", " + "data:" + req.body.data1;
        this.sendResult(req, res, result);
    }

    // PUT
    public async myPagePut(req: any, res: any): Promise<void> {
        let result = req.query.message + ", " + req.route.params.name + ", " + "data:" + req.body.data1;
        this.sendResult(req, res, result);
    }

    // Route registration
    public register(): void {
        this.registerRoute("GET", "/my_page/:name", null, this.myPageGet)
        this.registerRoute("HEAD", "/my_page/:name", null, this.myPageHead)
        this.registerRoute("POST", "/my_page/:name", null, this.myPagePost)
        this.registerRoute("PUT", "/my_page/:name", null, this.myPagePut)
    }
}


// Instantiation
let myRestService = new MyRestService();

// REST service configuration
myRestService.configure(ConfigParams.fromTuples(
    "connection.protocol", "http",
    "connection.host", "localhost",
    "connection.port", 15235
));

// Connection
await myRestService.open("123");


using PipServices3.Commons.Config;
using PipServices3.Rpc.Services;


    class MyRestService : RestService
    {
        public MyRestService(): base()
        {
            _baseRoute = "/my_service";
        }

        // GET
        private async Task MyPageGet(HttpRequest request, HttpResponse response, RouteData routeData)
        {
            var name = routeData.Values["name"].ToString();
            var message = request.Query.TryGetValue("message", out StringValues sortValues)
                ? sortValues.ToString()
                : string.Empty;

            var res = message + ", " + name;
            await this.SendResultAsync(response, res);
        }

        // HEAD
        private async Task MyPageHead(HttpRequest request, HttpResponse response, RouteData routeData)
        {
            await this.SendEmptyResultAsync(response);
        }

        // POST
        private async Task MyPagePost(HttpRequest request, HttpResponse response, RouteData routeData)
        {
            
            var name = routeData.Values["name"].ToString();
            var message = request.Query.TryGetValue("message", out StringValues sortValues)
                ? sortValues.ToString()
                : string.Empty;

            IDictionary<string, object> data = null;
            using (var streamReader = new StreamReader(request.Body))
            {
                data = JsonConverter.ToMap(streamReader.ReadToEnd());
            }

            var res = message + ", " + name + ", " + "data:" + data["data1"];

            await this.SendResultAsync(response, res);
        }

        // PUT
        private async Task MyPagePut(HttpRequest request, HttpResponse response, RouteData routeData)
        {

            var name = routeData.Values["name"].ToString();
            var message = request.Query.TryGetValue("message", out StringValues sortValues)
                ? sortValues.ToString()
                : string.Empty;

            IDictionary<string, object> data = null;
            using (var streamReader = new StreamReader(request.Body))
            {
                data = JsonConverter.ToMap(streamReader.ReadToEnd());
            }

            var res = message + ", " + name + ", " + "data:" + data["data1"];

            await this.SendResultAsync(response, res);
        }
    }


// Instantiation
var myRestService = new MyRestService();

// REST service configuration
myRestService.Configure(ConfigParams.FromTuples(
    "connection.protocol", "http",
    "connection.host", "localhost",
    "connection.port", 15235
));
            
// Connection
await myRestService.OpenAsync("123");

import (
	"context"
	"net/http"

	cconf "github.com/pip-services3-gox/pip-services3-commons-gox/config"
	cerr "github.com/pip-services3-gox/pip-services3-commons-gox/errors"
	"github.com/pip-services3-gox/pip-services3-rpc-gox/services"
)

func main() {
	// Instantiation
	myRestService := NewMyRestService()

	// REST service configuration
	myRestService.Configure(context.Background(), cconf.NewConfigParamsFromTuples(
		"connection.protocol", "http",
		"connection.host", "localhost",
		"connection.port", 15235,
	))

	// Connection
	myRestService.Open(context.Background(), "123")

}

type MyRestService struct {
	*services.RestService
}

func NewMyRestService() *MyRestService {
	c := &MyRestService{}
	c.RestService = services.InheritRestService(c)
	c.BaseRoute = "/my_service"
	return c
}

// GET
func (c *MyRestService) myPageGet(res http.ResponseWriter, req *http.Request) {
	params := req.URL.Query()
	routeVars := mux.Vars(req)
	result := params.Get("message") + ", " + routeVars["name"]
	c.SendResult(res, req, result, nil)
}

// HEAD
func (c *MyRestService) myPageHead(res http.ResponseWriter, req *http.Request) {
	c.SendResult(res, req, nil, nil)
}

// POST
func (c *MyRestService) myPagePost(res http.ResponseWriter, req *http.Request) {
	correlationId := c.GetCorrelationId(req)
	params := req.URL.Query()
	routeVars := mux.Vars(req)
	result := params.Get("message") + ", " + routeVars["name"]

	var data string

	bodyBytes, bodyErr := ioutil.ReadAll(req.Body)
	_ = req.Body.Close()
	if bodyErr != nil {
		err := cerr.NewInternalError(correlationId, "JSON_CNV_ERR", "Cant convert from JSON to Data").WithCause(bodyErr)
		c.SendError(res, req, err)
		return
	}

	data = string(bodyBytes)
	result = result + ", data:" + data
	c.SendResult(res, req, result, nil)
}

// PUT
func (c *MyRestService) myPagePut(res http.ResponseWriter, req *http.Request) {
	correlationId := c.GetCorrelationId(req)
	params := req.URL.Query()
	routeVars := mux.Vars(req)
	result := params.Get("message") + ", " + routeVars["name"]

	var data string

	bodyBytes, bodyErr := ioutil.ReadAll(req.Body)
	_ = req.Body.Close()
	if bodyErr != nil {
		err := cerr.NewInternalError(correlationId, "JSON_CNV_ERR", "Cant convert from JSON to Data").WithCause(bodyErr)
		c.SendError(res, req, err)
		return
	}

	data = string(bodyBytes)
	result = result + ", data:" + data
	c.SendResult(res, req, result, nil)
}

// Route registration
func (c *MyRestService) Register() {
	c.RegisterRoute(
		http.MethodGet, "/my_page/{name}",
		nil,
		c.myPageGet,
	)

	c.RegisterRoute(
		http.MethodHead, "/my_page/{name}",
		nil,
		c.myPageHead,
	)

	c.RegisterRoute(
		http.MethodPost, "/my_page/{name}",
		nil,
		c.myPagePost,
	)

	c.RegisterRoute(
		http.MethodPut, "/my_page/{name}",
		nil,
		c.myPagePut,
	)
}

import 'package:pip_services3_commons/pip_services3_commons.dart';
import 'package:pip_services3_rpc/pip_services3_rpc.dart';


class MyRestService extends RestService {
  MyRestService() {
    baseRoute = '/my_service';
  }

  // GET
  FutureOr<Response> _myPageGet(Request req) async {
    var result =
        req.url.queryParameters['message']! + ', ' + req.params['name']!;

    return await sendResult(req, result);
  }

  // HEAD
  FutureOr<Response> _myPageHead(Request req) async {
    return await sendResult(req, null);
  }

  // POST
  FutureOr<Response> _myPagePost(Request req) async {
    var data = json.decode(await req.readAsString());
    var result = req.url.queryParameters['message']! +
        ', ' +
        req.params['name']! +
        ', ' +
        'data:' +
        data['data1'];

    return await sendResult(req, result);
  }

  // PUT
  FutureOr<Response> _myPagePut(Request req) async {
    var data = json.decode(await req.readAsString());
    var result = req.url.queryParameters['message']! +
        ', ' +
        req.params['name']! +
        ', ' +
        'data:' +
        data['data1'];

    return await sendResult(req, result);
  }

  // Route registration
  @override
  void register() {
    registerRoute('get', '/my_page/<name>', null, _myPageGet);
    registerRoute('head', '/my_page/<name>', null, _myPageHead);
    registerRoute('post', '/my_page/<name>', null, _myPagePost);
    registerRoute('put', '/my_page/<name>', null, _myPagePut);
  }
}


// Instantiation
var myRestService = MyRestService();

// REST service configuration
myRestService.configure(ConfigParams.fromTuples([
  'connection.protocol',
  'http',
  'connection.host',
  'localhost',
  'connection.port',
  15235
]));

// Connection
await myRestService.open('123');

# Pre-requisites
from bottle import request
from pip_services3_rpc.services import RestService
from pip_services3_commons.config import ConfigParams


class MyRestService(RestService):

    def __init__(self):
        super(MyRestService, self).__init__()
        self._base_route = "/my_service"

    # GET
    def my_page_get(self, name):
        result = f"{request.query.get('message')}, {name}"
        return self.send_result(result)

    # HEAD
    def my_page_head(self, name):
        return self.send_result(None)

    # POST
    def my_page_post(self, name):
        body_data = self._get_data()
        result = f"{request.query.get('message')}, {name}, " \
                 f'data:{body_data.get("data1")}'
        return self.send_result(result)

    # PUT
    def my_page_put(self, name):
        body_data = self._get_data()
        result = f"{request.query.get('message')}, {name}, " \
                 f'data:{body_data.get("data1")}'
        return self.send_result(result)

    # Route registration
    def register(self):
        self.register_route(method="GET", route="/my_page/<name>", schema=None, handler=self.my_page_get)
        self.register_route(method="HEAD", route="/my_page/<name>", schema=None, handler=self.my_page_head)
        self.register_route(method="POST", route="/my_page/<name>", schema=None, handler=self.my_page_post)
        self.register_route(method="PUT", route="/my_page/<name>", schema=None, handler=self.my_page_put)


# Instantiation
service = MyRestService()

# Configuration
service.configure(ConfigParams.from_tuples("connection.protocol", "http",
                                           "connection.host", "localhost",
                                           "connection.port", 15231))
# Connection
service.open("123")


Not available

The REST client

Now that we have our REST service, we build a REST client that connects to it. This client has a function for each of the HTTP methods which calls the corresponding methods in our REST service.

Once we have defined our component, we instantiate and configure it, pointing toward the endpoint previously defined in the REST service. Then, we connect it to the service with the open() method. The code below shows how to do this:

import { ConfigParams } from "pip-services3-commons-nodex";
import { RestClient } from "pip-services3-rpc-nodex";

export class MyRestClient extends RestClient {
    public constructor() {
        super();
        this._baseRoute = '/my_service';
    }

    // GET
    public async getDataGet(correlationId: string, name: string): Promise<string> {
        let result = await this.call<string>("get", "/my_page/" + name, correlationId, { message: 'Hello' });
        return result;
    }

    // HEAD
    public async getDataHead(correlationId: string, name: string): Promise<string> {
        let result = await this.call<string>("head", "/my_page/" + name, correlationId, { message: 'Hello' });
        return result;
    }

    // POST
    public async getDataPost(correlationId: string, name: string): Promise<string> {
        let result = await this.call<string>("post", "/my_page/" + name, correlationId, { message: 'Hello' }, { data1: 'my data' });
        return result;
    }

    // PUT
    public async getDataPut(correlationId: string, name: string): Promise<string> {
        let result = await this.call<string>("put", "/my_page/" + name, correlationId, { message: 'Hello' }, { data1: 'my data' });
        return result;
    }
}
        
// Instantiation
let client = new MyRestClient();
// REST client configuration
client.configure(ConfigParams.fromTuples(
    "connection.protocol", "http",
    "connection.host", "localhost",
    "connection.port", 15235
));
                                     
// Connection
client.open("123")  
using PipServices3.Commons.Config;
using PipServices3.Rpc.Clients;

class MyRestClient: RestClient
{
    public MyRestClient()
    {
        _baseRoute = "/my_service";
    }

    public async Task<string> GetDataGet(string correlationId, string name)
    {
        return await this.CallAsync<string>(correlationId, HttpMethod.Get, "/my_page/" + name + "?message=Hello");
    }

    public async Task<string> GetDataHead(string correlationId, string name)
    {
        return await this.CallAsync<string>(correlationId, HttpMethod.Head, "/my_page/" + name + "?message=Hello");
    }

    public async Task<string> GetDataPost(string correlationId, string name)
    {
        return await this.CallAsync<string>(correlationId, HttpMethod.Post, "/my_page/" + name + "?message=Hello", new { data1= "my data" });
    }

    public async Task<string> GetDataPut(string correlationId, string name)
    {
        return await this.CallAsync<string>(correlationId, HttpMethod.Put, "/my_page/" + name + "?message=Hello", new { data1 = "my data" });
    }
}
        
// Instantiation
var client = new MyRestClient();

// REST client configuration
client.Configure(ConfigParams.FromTuples(
    "connection.protocol", "http",
    "connection.host", "localhost",
    "connection.port", 15235
));

// Connection
await client.OpenAsync("123"); 
import (
	"context"
	"net/http"

	cconf "github.com/pip-services3-gox/pip-services3-commons-gox/config"
	cdata "github.com/pip-services3-gox/pip-services3-commons-gox/data"
	"github.com/pip-services3-gox/pip-services3-rpc-gox/clients"
)

func main() {
	// Instantiation
	client := NewMyRestClient()
	// REST client configuration
	client.Configure(context.Background(), cconf.NewConfigParamsFromTuples(
		"connection.protocol", "http",
		"connection.host", "localhost",
		"connection.port", 15235,
	))

	// Connection
	client.Open(context.Background(), "123")
}

type MyRestClient struct {
	*clients.RestClient
}

func NewMyRestClient() *MyRestClient {
	drc := MyRestClient{}
	drc.RestClient = clients.NewRestClient()
	drc.BaseRoute = "/my_service"
	return &drc
}

// GET
func (c *MyRestClient) GetDataGet(ctx context.Context, correlationId string, name string) (result string, err error) {
	params := cdata.NewEmptyStringValueMap()
	params.Put("message", "hello")

	response, err := c.Call(ctx, http.MethodGet, "/my_page/"+name, correlationId, params, nil)
	if err != nil {
		return "", err
	}

	return clients.HandleHttpResponse[string](response, correlationId)
}

// HEAD
func (c *MyRestClient) GetDataHead(ctx context.Context, correlationId string, name string) (result string, err error) {

	params := cdata.NewEmptyStringValueMap()
	params.Put("message", "hello")

	response, err := c.Call(ctx, http.MethodHead, "/my_page/"+name, correlationId, params, nil)
	if err != nil || response == nil {
		return "", err
	}

	return clients.HandleHttpResponse[string](response, correlationId)
}

// POST
func (c *MyRestClient) GetDataPost(ctx context.Context, correlationId string, name string) (result string, err error) {

	params := cdata.NewEmptyStringValueMap()
	params.Put("message", "hello")

	response, err := c.Call(ctx, http.MethodPost, "/my_page/"+name, correlationId, params, map[string]string{"data1": "my data"})
	if err != nil {
		return "", err
	}

	return clients.HandleHttpResponse[string](response, correlationId)
}

// PUT
func (c *MyRestClient) GetDataPut(ctx context.Context, correlationId string, name string) (result string, err error) {

	params := cdata.NewEmptyStringValueMap()
	params.Put("message", "hello")

	response, err := c.Call(ctx, http.MethodPost, "/my_page/"+name, correlationId, params, map[string]string{"data1": "my data"})
	if err != nil {
		return "", err
	}

	return clients.HandleHttpResponse[string](response, correlationId)
}

import 'package:pip_services3_commons/pip_services3_commons.dart';
import 'package:pip_services3_rpc/pip_services3_rpc.dart';

class MyRestClient extends RestClient {
  MyRestClient() {
    baseRoute = '/my_service';
  }

  // GET
  Future<String> getDataGet(String? correlationId, String name) async {
    return await call(
        'get', '/my_page/' + name, correlationId, {'message': 'Hello'}, null);
  }

  // HEAD
  Future<String> getDataHead(String? correlationId, String name) async {
    var res = await call(
        'head', '/my_page/' + name, correlationId, {'message': 'Hello'}, null);
    return res ?? '';
  }

  // POST
  Future<String> getDataPost(String? correlationId, String name) async {
    return await call('post', '/my_page/' + name, correlationId,
        {'message': 'Hello'}, {'data1': 'my data'});
  }

  // PUT
  Future<String> getDataPut(String? correlationId, String name) async {
    return await call('put', '/my_page/' + name, correlationId,
        {'message': 'Hello'}, {'data1': 'my data'});
  }
}
        
// Instantiation
var client = MyRestClient();

// REST client configuration
client.configure(ConfigParams.fromTuples([
  'connection.protocol',
  'http',
  'connection.host',
  'localhost',
  'connection.port',
  15235
]));

// Connection
await client.open('123');
# Pre-requisites
from pip_services3_rpc.clients import RestClient


class MyRestClient(RestClient):
    def __init__(self):
        super().__init__()
        self._base_route = '/my_service'

    def get_data_get(self, correlation_id, name: str):
        result = self._call("get", "/my_page/" + name, correlation_id, params={'message': 'Hello'})
        return result

    def get_data_head(self, correlation_id, name: str):
        result = self._call("head", "/my_page/" + name, correlation_id, params={'message': 'Hello'}, data={
            "data1": "my data"})
        return result

    def get_data_post(self, correlation_id, name: str):
        result = self._call("post", "/my_page/" + name, correlation_id, params={'message': 'Hello'}, data={
            "data1": "my data"})
        return result

    def get_data_put(self, correlation_id, name: str):
        result = self._call("put", "/my_page/" + name, correlation_id, params={'message': 'Hello'}, data={
            "data1": "my data"})
        return result


# Instantiation
client = MyRestClient()

# Configuration
client.configure(ConfigParams.from_tuples("connection.protocol", "http",
                                          "connection.host", "localhost",
                                          "connection.port", 15231))
# Connection
client.open("123")
Not available

Using the different HTTP methods

Our last step is to call each of the client’s functions and obtain the respective results. The following commands and their outcomes show how to do this:

// GET
await client.getDataGet("123", "David");
// GET
await client.GetDataGet("123", "David");
// GET
res, err := client.GetDataGet(context.Background(), "123", "David")
// GET
await client.getDataGet("123", "David");
# GET
client.get_data_get("123", "David")
Not available

figure 3

// HEAD
await client.getDataHead("123", "David");
// HEAD
await client.GetDataHead("123", "David");
// HEAD
res, err = client.GetDataHead(context.Background(), "123", "David")
// HEAD
await client.getDataHead("123", "David");
# HEAD
client.get_data_head("123", "David")
Not available

Note: the HEAD method produces no output.

// POST
await client.getDataPost("123", "David");
// POST
await client.GetDataPost("123", "David");
// POST
res, err = client.GetDataPost(context.Background(), "123", "David")
// POST
await client.getDataPost("123", "David");
# POST
client.get_data_post("123", "David")
Not available

figure 1

// PUT
await client.getDataPut("123", "David");
// PUT
await client.GetDataPut("123", "David");
// PUT
res, err = client.GetDataPut(context.Background(), "123", "David")
// PUT
await client.getDataPut("123", "David");
# PUT
client.get_data_put("123", "David")
Not available

figure 1

Final code

The code below summarizes the steps learned in the previous sections.

import { ConfigParams } from "pip-services3-commons-nodex";
import { RestClient, RestService } from "pip-services3-rpc-nodex";

export async function main() {
    // Instantiation
    let myRestService = new MyRestService();

    // REST service configuration
    myRestService.configure(ConfigParams.fromTuples(
        "connection.protocol", "http",
        "connection.host", "localhost",
        "connection.port", 15235
    ));
    // Connection
    await myRestService.open("123");


    // Instantiation
    let client = new MyRestClient();

    // REST client configuration
    client.configure(ConfigParams.fromTuples(
        "connection.protocol", "http",
        "connection.host", "localhost",
        "connection.port", 15235
    ));

    // Connection
    await client.open("123");

    // Using the different HTTP methods
    // GET
    console.log("GET: " + await client.getDataGet("123", "David"));
    // HEAD
    console.log("HEAD: " + await client.getDataHead("123", "David"));
    // POST
    console.log("POST: " + await client.getDataPost("123", "David"));
    // PUT
    console.log("PUT: " + await client.getDataPut("123", "David"));

    // Close REST service and REST client
    await client.close("123");
    await myRestService.close("123");
}

export class MyRestClient extends RestClient {
    public constructor() {
        super();
        this._baseRoute = '/my_service';
    }

    // GET
    public async getDataGet(correlationId: string, name: string): Promise<string> {
        let result = await this.call<string>("get", "/my_page/" + name, correlationId, { message: 'Hello' });
        return result;
    }

    // HEAD
    public async getDataHead(correlationId: string, name: string): Promise<string> {
        let result = await this.call<string>("head", "/my_page/" + name, correlationId, { message: 'Hello' });
        return result;
    }

    // POST
    public async getDataPost(correlationId: string, name: string): Promise<string> {
        let result = await this.call<string>("post", "/my_page/" + name, correlationId, { message: 'Hello' }, { data1: 'my data' });
        return result;
    }

    // PUT
    public async getDataPut(correlationId: string, name: string): Promise<string> {
        let result = await this.call<string>("put", "/my_page/" + name, correlationId, { message: 'Hello' }, { data1: 'my data' });
        return result;
    }
}

export class MyRestService extends RestService {

    public constructor() {
        super();
        this._baseRoute = "/my_service";
    }

    // GET
    public async myPageGet(req: any, res: any): Promise<void> {
        let result = req.query.message + ", " + req.route.params.name;
        this.sendResult(req, res, result);
    }

    // HEAD
    public async myPageHead(req: any, res: any): Promise<void> {
        this.sendResult(req, res, null);
    }

    // POST
    public async myPagePost(req: any, res: any): Promise<void> {
        let result = req.query.message + ", " + req.route.params.name + ", " + "data:" + req.body.data1;
        this.sendResult(req, res, result);
    }

    // PUT
    public async myPagePut(req: any, res: any): Promise<void> {
        let result = req.query.message + ", " + req.route.params.name + ", " + "data:" + req.body.data1;
        this.sendResult(req, res, result);
    }

    // Route registration
    public register(): void {
        this.registerRoute("GET", "/my_page/:name", null, this.myPageGet)
        this.registerRoute("HEAD", "/my_page/:name", null, this.myPageHead)
        this.registerRoute("POST", "/my_page/:name", null, this.myPagePost)
        this.registerRoute("PUT", "/my_page/:name", null, this.myPagePut)
    }
}
using System;
using System.IO;
using System.Net.Http;
using System.Collections.Generic;
using System.Threading.Tasks;

using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;

using PipServices3.Commons.Convert;
using PipServices3.Commons.Config;
using PipServices3.Rpc.Services;
using PipServices3.Rpc.Clients;

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

            // REST service configuration
            myRestService.Configure(ConfigParams.FromTuples(
                "connection.protocol", "http",
                "connection.host", "localhost",
                "connection.port", 15235
            ));
            
            // Connection
            myRestService.OpenAsync("123").Wait();


            // Instantiation
            var client = new MyRestClient();

            // REST client configuration
            client.Configure(ConfigParams.FromTuples(
                "connection.protocol", "http",
                "connection.host", "localhost",
                "connection.port", 15235
            ));

            // Connection
            client.OpenAsync("123").Wait();

            // Using the different HTTP methods
            // GET
            Console.WriteLine("GET: " + client.GetDataGet("123", "David").Result);
            // HEAD
            Console.WriteLine("HEAD: " + client.GetDataHead("123", "David").Result);
            // POST
            Console.WriteLine("POST: " + client.GetDataPost("123", "David").Result);
            // PUT
            Console.WriteLine("PUT: " + client.GetDataPut("123", "David").Result);

            // Close REST service and REST client
            client.CloseAsync("123").Wait();
            myRestService.CloseAsync("123").Wait();
        }
    }

    class MyRestClient: RestClient
    {
        public MyRestClient()
        {
            _baseRoute = "/my_service";
        }

        public async Task<string> GetDataGet(string correlationId, string name)
        {
            return await this.CallAsync<string>(correlationId, HttpMethod.Get, "/my_page/" + name + "?message=Hello");
        }

        public async Task<string> GetDataHead(string correlationId, string name)
        {
            return await this.CallAsync<string>(correlationId, HttpMethod.Head, "/my_page/" + name + "?message=Hello");
        }

        public async Task<string> GetDataPost(string correlationId, string name)
        {
            return await this.CallAsync<string>(correlationId, HttpMethod.Post, "/my_page/" + name + "?message=Hello", new { data1= "my data" });
        }

        public async Task<string> GetDataPut(string correlationId, string name)
        {
            return await this.CallAsync<string>(correlationId, HttpMethod.Put, "/my_page/" + name + "?message=Hello", new { data1 = "my data" });
        }
    }

    // REST service
    class MyRestService : RestService
    {
        public MyRestService(): base()
        {
            _baseRoute = "/my_service";
        }

        // GET
        private async Task MyPageGet(HttpRequest request, HttpResponse response, RouteData routeData)
        {
            var name = routeData.Values["name"].ToString();
            var message = request.Query.TryGetValue("message", out StringValues sortValues)
                ? sortValues.ToString()
                : string.Empty;

            var res = message + ", " + name;
            await this.SendResultAsync(response, res);
        }

        // HEAD
        private async Task MyPageHead(HttpRequest request, HttpResponse response, RouteData routeData)
        {
            await this.SendEmptyResultAsync(response);
        }

        // POST
        private async Task MyPagePost(HttpRequest request, HttpResponse response, RouteData routeData)
        {
            
            var name = routeData.Values["name"].ToString();
            var message = request.Query.TryGetValue("message", out StringValues sortValues)
                ? sortValues.ToString()
                : string.Empty;

            IDictionary<string, object> data = null;
            using (var streamReader = new StreamReader(request.Body))
            {
                data = JsonConverter.ToMap(streamReader.ReadToEnd());
            }

            var res = message + ", " + name + ", " + "data:" + data["data1"];

            await this.SendResultAsync(response, res);
        }

        // PUT
        private async Task MyPagePut(HttpRequest request, HttpResponse response, RouteData routeData)
        {

            var name = routeData.Values["name"].ToString();
            var message = request.Query.TryGetValue("message", out StringValues sortValues)
                ? sortValues.ToString()
                : string.Empty;

            IDictionary<string, object> data = null;
            using (var streamReader = new StreamReader(request.Body))
            {
                data = JsonConverter.ToMap(streamReader.ReadToEnd());
            }

            var res = message + ", " + name + ", " + "data:" + data["data1"];

            await this.SendResultAsync(response, res);
        }

        public override void Register()
        {
            this.RegisterRoute("get", "/my_page/{name}", MyPageGet);
            this.RegisterRoute("head", "/my_page/{name}", MyPageHead);
            this.RegisterRoute("post", "/my_page/{name}", MyPagePost);
            this.RegisterRoute("put", "/my_page/{name}", MyPagePut);
        }
    }
}
import (
	"context"
	"fmt"
	"io/ioutil"
	"net/http"

	"github.com/gorilla/mux"
	cconf "github.com/pip-services3-gox/pip-services3-commons-gox/config"
	cdata "github.com/pip-services3-gox/pip-services3-commons-gox/data"
	cerr "github.com/pip-services3-gox/pip-services3-commons-gox/errors"
	"github.com/pip-services3-gox/pip-services3-rpc-gox/clients"
	"github.com/pip-services3-gox/pip-services3-rpc-gox/services"
)

func main() {
	// Instantiation
	myRestService := NewMyRestService()

	// REST service configuration
	myRestService.Configure(context.Background(), cconf.NewConfigParamsFromTuples(
		"connection.protocol", "http",
		"connection.host", "localhost",
		"connection.port", 15235,
	))

	// Connection
	myRestService.Open(context.Background(), "123")

	////////////////////////////////////////////////////////////

	// Instantiation
	client := NewMyRestClient()
	// REST client configuration
	client.Configure(context.Background(), cconf.NewConfigParamsFromTuples(
		"connection.protocol", "http",
		"connection.host", "localhost",
		"connection.port", 15235,
	))

	// Connection
	client.Open(context.Background(), "123")

	// GET
	res, err := client.GetDataGet(context.Background(), "123", "David")
	fmt.Println(err)
	fmt.Println(res)

	// HEAD
	res, err = client.GetDataHead(context.Background(), "123", "David")
	fmt.Println(err)
	fmt.Println(res)

	// POST
	res, err = client.GetDataPost(context.Background(), "123", "David")
	fmt.Println(err)
	fmt.Println(res)

	// PUT
	res, err = client.GetDataPut(context.Background(), "123", "David")
	fmt.Println(err)
	fmt.Println(res)

	// Close REST service and REST client
	_ = client.Close(context.Background(), "123")
	_ = myRestService.Close(context.Background(), "123")
}

type MyRestClient struct {
	*clients.RestClient
}

func NewMyRestClient() *MyRestClient {
	drc := MyRestClient{}
	drc.RestClient = clients.NewRestClient()
	drc.BaseRoute = "/my_service"
	return &drc
}

// GET
func (c *MyRestClient) GetDataGet(ctx context.Context, correlationId string, name string) (result string, err error) {
	params := cdata.NewEmptyStringValueMap()
	params.Put("message", "hello")

	response, err := c.Call(ctx, http.MethodGet, "/my_page/"+name, correlationId, params, nil)
	if err != nil {
		return "", err
	}

	return clients.HandleHttpResponse[string](response, correlationId)
}

// HEAD
func (c *MyRestClient) GetDataHead(ctx context.Context, correlationId string, name string) (result string, err error) {

	params := cdata.NewEmptyStringValueMap()
	params.Put("message", "hello")

	response, err := c.Call(ctx, http.MethodHead, "/my_page/"+name, correlationId, params, nil)
	if err != nil || response == nil {
		return "", err
	}

	return clients.HandleHttpResponse[string](response, correlationId)
}

// POST
func (c *MyRestClient) GetDataPost(ctx context.Context, correlationId string, name string) (result string, err error) {

	params := cdata.NewEmptyStringValueMap()
	params.Put("message", "hello")

	response, err := c.Call(ctx, http.MethodPost, "/my_page/"+name, correlationId, params, map[string]string{"data1": "my data"})
	if err != nil {
		return "", err
	}

	return clients.HandleHttpResponse[string](response, correlationId)
}

// PUT
func (c *MyRestClient) GetDataPut(ctx context.Context, correlationId string, name string) (result string, err error) {

	params := cdata.NewEmptyStringValueMap()
	params.Put("message", "hello")

	response, err := c.Call(ctx, http.MethodPost, "/my_page/"+name, correlationId, params, map[string]string{"data1": "my data"})
	if err != nil {
		return "", err
	}

	return clients.HandleHttpResponse[string](response, correlationId)
}

////////////////////////////////////////

type MyRestService struct {
	*services.RestService
}

func NewMyRestService() *MyRestService {
	c := &MyRestService{}
	c.RestService = services.InheritRestService(c)
	c.BaseRoute = "/my_service"
	return c
}

// GET
func (c *MyRestService) myPageGet(res http.ResponseWriter, req *http.Request) {
	params := req.URL.Query()
	routeVars := mux.Vars(req)
	result := params.Get("message") + ", " + routeVars["name"]
	c.SendResult(res, req, result, nil)
}

// HEAD
func (c *MyRestService) myPageHead(res http.ResponseWriter, req *http.Request) {
	c.SendResult(res, req, nil, nil)
}

// POST
func (c *MyRestService) myPagePost(res http.ResponseWriter, req *http.Request) {
	correlationId := c.GetCorrelationId(req)
	params := req.URL.Query()
	routeVars := mux.Vars(req)
	result := params.Get("message") + ", " + routeVars["name"]

	var data string

	bodyBytes, bodyErr := ioutil.ReadAll(req.Body)
	_ = req.Body.Close()
	if bodyErr != nil {
		err := cerr.NewInternalError(correlationId, "JSON_CNV_ERR", "Cant convert from JSON to Data").WithCause(bodyErr)
		c.SendError(res, req, err)
		return
	}

	data = string(bodyBytes)
	result = result + ", data:" + data
	c.SendResult(res, req, result, nil)
}

// PUT
func (c *MyRestService) myPagePut(res http.ResponseWriter, req *http.Request) {
	correlationId := c.GetCorrelationId(req)
	params := req.URL.Query()
	routeVars := mux.Vars(req)
	result := params.Get("message") + ", " + routeVars["name"]

	var data string

	bodyBytes, bodyErr := ioutil.ReadAll(req.Body)
	_ = req.Body.Close()
	if bodyErr != nil {
		err := cerr.NewInternalError(correlationId, "JSON_CNV_ERR", "Cant convert from JSON to Data").WithCause(bodyErr)
		c.SendError(res, req, err)
		return
	}

	data = string(bodyBytes)
	result = result + ", data:" + data
	c.SendResult(res, req, result, nil)
}

// Route registration
func (c *MyRestService) Register() {
	c.RegisterRoute(
		http.MethodGet, "/my_page/{name}",
		nil,
		c.myPageGet,
	)

	c.RegisterRoute(
		http.MethodHead, "/my_page/{name}",
		nil,
		c.myPageHead,
	)

	c.RegisterRoute(
		http.MethodPost, "/my_page/{name}",
		nil,
		c.myPagePost,
	)

	c.RegisterRoute(
		http.MethodPut, "/my_page/{name}",
		nil,
		c.myPagePut,
	)
}

import 'dart:async';
import 'dart:convert';

import 'package:pip_services3_commons/pip_services3_commons.dart';
import 'package:pip_services3_rpc/pip_services3_rpc.dart';

import 'package:shelf/shelf.dart';
import 'package:shelf_router/shelf_router.dart';

void main(List<String> argument) async {
  // Instantiation
  var myRestService = MyRestService();

  // REST service configuration
  myRestService.configure(ConfigParams.fromTuples([
    'connection.protocol',
    'http',
    'connection.host',
    'localhost',
    'connection.port',
    15235
  ]));
  // Connection
  await myRestService.open('123');

  // Instantiation
  var client = MyRestClient();

  // REST client configuration
  client.configure(ConfigParams.fromTuples([
    'connection.protocol',
    'http',
    'connection.host',
    'localhost',
    'connection.port',
    15235
  ]));

  // Connection
  await client.open('123');

  // Using the different HTTP methods
  // GET
  print('GET: ' + await client.getDataGet('123', 'David'));
  // HEAD
  print('HEAD: ' + await client.getDataHead('123', 'David'));
  // POST
  print('POST: ' + await client.getDataPost('123', 'David'));
  // PUT
  print('PUT: ' + await client.getDataPut('123', 'David'));

  // Close REST service and REST client
  await client.close('123');
  await myRestService.close('123');
}

class MyRestClient extends RestClient {
  MyRestClient() {
    baseRoute = '/my_service';
  }

  // GET
  Future<String> getDataGet(String? correlationId, String name) async {
    return await call(
        'get', '/my_page/' + name, correlationId, {'message': 'Hello'}, null);
  }

  // HEAD
  Future<String> getDataHead(String? correlationId, String name) async {
    var res = await call(
        'head', '/my_page/' + name, correlationId, {'message': 'Hello'}, null);
    return res ?? '';
  }

  // POST
  Future<String> getDataPost(String? correlationId, String name) async {
    return await call('post', '/my_page/' + name, correlationId,
        {'message': 'Hello'}, {'data1': 'my data'});
  }

  // PUT
  Future<String> getDataPut(String? correlationId, String name) async {
    return await call('put', '/my_page/' + name, correlationId,
        {'message': 'Hello'}, {'data1': 'my data'});
  }
}

class MyRestService extends RestService {
  MyRestService() {
    baseRoute = '/my_service';
  }

  // GET
  FutureOr<Response> _myPageGet(Request req) async {
    var result =
        req.url.queryParameters['message']! + ', ' + req.params['name']!;

    return await sendResult(req, result);
  }

  // HEAD
  FutureOr<Response> _myPageHead(Request req) async {
    return await sendResult(req, null);
  }

  // POST
  FutureOr<Response> _myPagePost(Request req) async {
    var data = json.decode(await req.readAsString());
    var result = req.url.queryParameters['message']! +
        ', ' +
        req.params['name']! +
        ', ' +
        'data:' +
        data['data1'];

    return await sendResult(req, result);
  }

  // PUT
  FutureOr<Response> _myPagePut(Request req) async {
    var data = json.decode(await req.readAsString());
    var result = req.url.queryParameters['message']! +
        ', ' +
        req.params['name']! +
        ', ' +
        'data:' +
        data['data1'];

    return await sendResult(req, result);
  }

  // Route registration
  @override
  void register() {
    registerRoute('get', '/my_page/<name>', null, _myPageGet);
    registerRoute('head', '/my_page/<name>', null, _myPageHead);
    registerRoute('post', '/my_page/<name>', null, _myPagePost);
    registerRoute('put', '/my_page/<name>', null, _myPagePut);
  }
}

# REST service

# Pre-requisites
from bottle import request
from pip_services3_rpc.services import RestService
from pip_services3_commons.config import ConfigParams


class MyRestService(RestService):

    def __init__(self):
        super(MyRestService, self).__init__()
        self._base_route = "/my_service"

    # GET
    def my_page_get(self, name):
        result = f"{request.query.get('message')}, {name}"
        return self.send_result(result)

    # HEAD
    def my_page_head(self, name):
        return self.send_result(None)

    # POST
    def my_page_post(self, name):
        body_data = self._get_data()
        result = f"{request.query.get('message')}, {name}, " \
                 f'data:{body_data.get("data1")}'
        return self.send_result(result)

    # PUT
    def my_page_put(self, name):
        body_data = self._get_data()
        result = f"{request.query.get('message')}, {name}, " \
                 f'data:{body_data.get("data1")}'
        return self.send_result(result)

    # Route registration
    def register(self):
        self.register_route(method="GET", route="/my_page/<name>", schema=None, handler=self.my_page_get)
        self.register_route(method="HEAD", route="/my_page/<name>", schema=None, handler=self.my_page_head)
        self.register_route(method="POST", route="/my_page/<name>", schema=None, handler=self.my_page_post)
        self.register_route(method="PUT", route="/my_page/<name>", schema=None, handler=self.my_page_put)


# Instantiation
service = MyRestService()

# Configuration
service.configure(ConfigParams.from_tuples("connection.protocol", "http",
                                           "connection.host", "localhost",
                                           "connection.port", 15231))
# Connection
service.open("123")

# REST client

# Pre-requisites
from pip_services3_rpc.clients import RestClient


class MyRestClient(RestClient):
    def __init__(self):
        super().__init__()
        self._base_route = '/my_service'

    def get_data_get(self, correlation_id, name: str):
        result = self._call("get", "/my_page/" + name, correlation_id, params={'message': 'Hello'})
        return result

    def get_data_head(self, correlation_id, name: str):
        result = self._call("head", "/my_page/" + name, correlation_id, params={'message': 'Hello'}, data={
            "data1": "my data"})
        return result

    def get_data_post(self, correlation_id, name: str):
        result = self._call("post", "/my_page/" + name, correlation_id, params={'message': 'Hello'}, data={
            "data1": "my data"})
        return result

    def get_data_put(self, correlation_id, name: str):
        result = self._call("put", "/my_page/" + name, correlation_id, params={'message': 'Hello'}, data={
            "data1": "my data"})
        return result


# Instantiation
client = MyRestClient()

# Configuration
client.configure(ConfigParams.from_tuples("connection.protocol", "http",
                                          "connection.host", "localhost",
                                          "connection.port", 15231))
# Connection
client.open("123")

# Using the different HTTP methods

# GET
print("GET: ", client.get_data_get("123", "David"))

# HEAD
print("HEAD: ", client.get_data_head("123", "David"))

# POST
print("POST: ", client.get_data_post("123", "David"))

# PUT
print("PUT: ", client.get_data_put("123", "David"))

# Close REST service and REST client
client.close("123")
service.close("123")
Not available

Which after running produces the following outcome:

figure 2

Wrapping up

In this tutorial, we have learned how to create a REST client that communicates via an endpoint defined by a REST service. We used the RestClient and the RestService classes to define these components, and we added functions for the GET, HEAD, POST and PUT methods in the service and the client. We concluded by creating a program that summarizes all the learned concepts.