REST Client

How to use the RestClient component.

Key takeaways

RestClient Component used to call remote endpoints using the HTTP/REST protocol.
RestController 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 controller 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 controller by using the RestController 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 controller. We will end by reviewing what we learned in the different sections.

The REST controller

Our first step is to create a REST controller. For this, we create a subclass of the RestController 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 controller, 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 { RestController } from "pip-services4-http-node";
import { ConfigParams } from "pip-services4-components-node";

export class MyRestController extends RestController {

    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 myRestController = new MyRestController();

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

// Connection
await myRestController.open(ctx);
Not available
Not available
Not available
# Pre-requisites
from bottle import request
from pip_services4_http.controller import RestController
from pip_services3_commons.config import ConfigParams


class MyRestController(RestController):

    def __init__(self):
        super(MyRestController, self).__init__()
        self._base_route = "/my_controller"

    # 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
controller = MyRestController()

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



Not available

The REST client

Now that we have our REST controller, 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 controller.

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

import { RestClient } from "pip-services4-http-node";
import { ConfigParams, Context } from "pip-services4-components-node";

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

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

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

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

    // PUT
    public async getDataPut(ctx: Context, name: string): Promise<string> {
        let result = await this.call<string>("put", "/my_page/" + name, ctx, { 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(ctx)  
Not available
Not available
Not available
# Pre-requisites
from pip_services4_http.clients import RestClient


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

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

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

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

    def get_data_put(self, context, name: str):
        result = self._call("put", "/my_page/" + name, context, 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(None)

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(ctx, "David");
Not available
Not available
Not available
# GET
client.get_data_get(None, "David")
Not available

figure 3

// HEAD
await client.getDataHead(ctx, "David");

Not available
Not available
Not available
# HEAD
client.get_data_head(None, "David")

Not available

Note: the HEAD method produces no output.

// POST
await client.getDataPost(ctx, "David");

Not available
Not available
Not available
# POST
client.get_data_post(None, "David")

Not available

figure 1

// PUT
await client.getDataPut(ctx, "David");

Not available
Not available
Not available
# PUT
client.get_data_put(None, "David")

Not available

figure 1

Final code

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


import { RestClient } from "pip-services4-http-node";
import { ConfigParams, Context } from "pip-services4-components-node";
import { RestController } from "pip-services4-http-node";

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

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


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

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

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

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

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

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

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

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

export class MyRestController extends RestController {

    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)
    }
}
Not available
Not available
Not available
# REST controller

# Pre-requisites
from bottle import request
from pip_services4_http.controller import RestController
from pip_services4_components.config import ConfigParams


class MyRestController(RestController):

    def __init__(self):
        super(MyRestController, self).__init__()
        self._base_route = "/my_controller"

    # 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
controller = MyRestController()

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

# REST client

# Pre-requisites
from pip_services4_http.clients import RestClient


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

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

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

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

    def get_data_put(self, context, name: str):
        result = self._call("put", "/my_page/" + name, context, 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(None)

# Using the different HTTP methods

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

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

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

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

# Close REST controller and REST client
client.close(None)
controller.close(None)
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 controller. We used the RestClient and the RestController classes to define these components, and we added functions for the GET, HEAD, POST and PUT methods in the controller and the client. We concluded by creating a program that summarizes all the learned concepts.