The Pip.Services Toolkit has a dedicated component in the RPC module for processing external requests. To make use of this service, create a new class BeaconsHttpServiceV1
, extending the CommandableHttpService
class:
/src/service/version1/BeaconsHttpServicesV1.ts
import { CommandableHttpService } from 'pip-services3-rpc-nodex';
import { Descriptor } from 'pip-services3-commons-nodex';
export class BeaconsHttpServiceV1 extends CommandableHttpService {
public constructor() {
super('v1/beacons');
this._dependencyResolver.put('controller', new Descriptor('beacons', 'controller', '*', '*', '1.0'));
}
}
/src/service/service/version1/BeaconsHttpServicesV1.py
namespace Beacons.Services.Version1
{
public class BeaconsHttpServiceV1: CommandableHttpService
{
public BeaconsHttpServiceV1()
: base("v1/beacons")
{
_dependencyResolver.Put("controller", new Descriptor("beacons", "controller", "default", "*", "1.0"));
}
}
}
/service/version1/BeaconsHttpServicesV1.go
package services1
import (
"context"
cref "github.com/pip-services3-gox/pip-services3-commons-gox/refer"
cservices "github.com/pip-services3-gox/pip-services3-rpc-gox/services"
)
type BeaconsHttpServiceV1 struct {
cservices.CommandableHttpService
}
func NewBeaconsHttpServiceV1() *BeaconsHttpServiceV1 {
c := &BeaconsHttpServiceV1{}
c.CommandableHttpService = *cservices.InheritCommandableHttpService(c, "v1/beacons")
c.DependencyResolver.Put(context.Background(), "controller", cref.NewDescriptor("beacons", "controller", "*", "*", "1.0"))
return c
}
/lib/service/version1/BeaconsCommandableHttpServiceV1.dart
import 'package:pip_services3_rpc/pip_services3_rpc.dart';
import 'package:pip_services3_commons/pip_services3_commons.dart';
class BeaconsCommandableHttpServiceV1 extends CommandableHttpService {
BeaconsCommandableHttpServiceV1() : super('v1/beacons') {
dependencyResolver.put(
'controller', Descriptor('beacons', 'controller', '*', '*', '1.0'));
}
}
/src/service/version1/BeaconsHttpServicesV1.py
from pip_services3_commons.refer import Descriptor
from pip_services3_rpc.services import CommandableHttpService
class BeaconsHttpServiceV1(CommandableHttpService):
def __init__(self):
super(BeaconsHttpServiceV1, self).__init__("v1/beacons")
self._dependency_resolver.put("controller", Descriptor('beacons', 'controller', '*', '*', '1.0'))
The CommandableHttpService
class from the pip-services3-rpc module implements all of the basic functionality needed by the service, right out of the box. All that we need to do on our side is configure it in the child class. This is done by defining a base route to the API (e.g. ‘v1/beacons’) and by setting references to the controller. The rest is taken care of by the parent class and the process container: a controller will be searched for and referenced, after which the service will receive a set of commands, register it, and make those commands available through the API interface. This allows us to run commands by simply posting requests to a URL of the following format:
http://{ip}:{port}/v1/beacons/{command_name}
Even though the BeaconsHttpServiceV1
class barely has any lines of code, there’s a large amount of code being executed in the service itself. To make sure that everything is working as it should, we should add tests for the service itself, as well as for the commands we wrote in the CommandSet. Create a file for the service’s test and paste the following code:
/test/services/version1/BeaconsHttpServiceV1.test.ts
const assert = require('chai').assert;
import { DataPage } from 'pip-services3-commons-nodex';
import { ConfigParams } from 'pip-services3-commons-nodex';
import { Descriptor } from 'pip-services3-commons-nodex';
import { References } from 'pip-services3-commons-nodex';
import { FilterParams } from 'pip-services3-commons-nodex';
import { PagingParams } from 'pip-services3-commons-nodex';
import { TestCommandableHttpClient } from 'pip-services3-rpc-nodex';
import { BeaconV1 } from '../../../src/data/version1/BeaconV1';
import { BeaconTypeV1 } from '../../../src/data/version1/BeaconTypeV1';
import { BeaconsMemoryPersistence } from '../../../src/persistence/BeaconsMemoryPersistence';
import { BeaconsController } from '../../../src/logic/BeaconsController';
import { BeaconsHttpServiceV1 } from '../../../src/services/version1/BeaconsHttpServiceV1';
const BEACON1: BeaconV1 = {
id: '1',
udi: '00001',
type: BeaconTypeV1.AltBeacon,
site_id: '1',
label: 'TestBeacon1',
center: { type: 'Point', coordinates: [ 0, 0 ] },
radius: 50
};
const BEACON2: BeaconV1 = {
id: '2',
udi: '00002',
type: BeaconTypeV1.iBeacon,
site_id: '1',
label: 'TestBeacon2',
center: { type: 'Point', coordinates: [ 2, 2 ] },
radius: 70
};
suite('BeaconsHttpServiceV1', () => {
let persistence: BeaconsMemoryPersistence;
let controller: BeaconsController;
let service: BeaconsHttpServiceV1;
let client: TestCommandableHttpClient;
setup(async () => {
let restConfig = ConfigParams.fromTuples(
'connection.protocol', 'http',
'connection.port', 3000,
'connection.host', 'localhost'
);
persistence = new BeaconsMemoryPersistence();
persistence.configure(new ConfigParams());
controller = new BeaconsController();
controller.configure(new ConfigParams());
service = new BeaconsHttpServiceV1();
service.configure(restConfig);
client = new TestCommandableHttpClient('v1/beacons')
client.configure(restConfig);
let references = References.fromTuples(
new Descriptor('beacons', 'persistence', 'memory', 'default', '1.0'), persistence,
new Descriptor('beacons', 'controller', 'default', 'default', '1.0'), controller,
new Descriptor('beacons', 'service', 'http', 'default', '1.0'), service
);
controller.setReferences(references);
service.setReferences(references);
await persistence.open(null);
await service.open(null);
await client.open(null);
});
teardown(async () => {
await client.close(null);
await service.close(null);
await persistence.close(null);
});
test('CRUD Operations', async () => {
let beacon1: BeaconV1;
// Create the first beacon
let beacon = await client.callCommand<BeaconV1>(
'create_beacon',
null,
{
beacon: BEACON1
}
);
assert.isObject(beacon);
assert.equal(BEACON1.udi, beacon.udi);
assert.equal(BEACON1.site_id, beacon.site_id);
assert.equal(BEACON1.type, beacon.type);
assert.equal(BEACON1.label, beacon.label);
assert.isNotNull(beacon.center);
// Create the second beacon
beacon = await client.callCommand<BeaconV1>(
'create_beacon',
null,
{
beacon: BEACON2
}
);
assert.isObject(beacon);
assert.equal(BEACON2.udi, beacon.udi);
assert.equal(BEACON2.site_id, beacon.site_id);
assert.equal(BEACON2.type, beacon.type);
assert.equal(BEACON2.label, beacon.label);
assert.isNotNull(beacon.center);
// Get all beacons
let page = await client.callCommand<DataPage<BeaconV1>>(
'get_beacons',
null,
{
filter: new FilterParams(),
paging: new PagingParams()
}
);
assert.isObject(page);
assert.lengthOf(page.data, 2);
beacon1 = page.data[0];
// Update the beacon
beacon1.label = 'ABC';
beacon = await client.callCommand(
'update_beacon',
null,
{
beacon: beacon1
}
);
assert.isObject(beacon);
assert.equal(beacon1.id, beacon.id);
assert.equal('ABC', beacon.label);
// Get beacon by udi
beacon = await client.callCommand(
'get_beacon_by_udi',
null,
{
udi: beacon1.udi
}
);
assert.isObject(beacon);
assert.equal(beacon1.id, beacon.id);
// Calculate position for one beacon
let position = await client.callCommand<any>(
'calculate_position',
null,
{
site_id: '1',
udis: ['00001']
}
);
assert.isObject(position);
assert.equal('Point', position.type);
assert.lengthOf(position.coordinates, 2);
assert.equal(0, position.coordinates[0]);
assert.equal(0, position.coordinates[1]);
// Delete the beacon
beacon = await client.callCommand(
'delete_beacon_by_id',
null,
{
beacon_id: beacon1.id
}
);
assert.isObject(beacon);
assert.equal(beacon1.id, beacon.id);
// Try to get deleted beacon
beacon = await client.callCommand(
'get_beacon_by_id',
null,
{
beacon_id: beacon1.id
}
);
assert.isNull(beacon || null);
});
});
Run the npm test
command and make sure that all of the tests pass successfully.
/test/service.test/services/version1/BeaconsHttpServiceV1Test.py
namespace Beacons.Services.Version1
{
public class BeaconsHttpServiceV1Test
{
private BeaconV1 BEACON1 = new BeaconV1
{
Id = "1",
Udi = "00001",
Type = BeaconTypeV1.AltBeacon,
SiteId = "1",
Label = "TestBeacon1",
Center = new CenterObjectV1 { Type = "Point", Coordinates = new double[] { 0, 0 } },
Radius = 50
};
private BeaconV1 BEACON2 = new BeaconV1
{
Id = "2",
Udi = "00002",
Type = BeaconTypeV1.iBeacon,
SiteId = "1",
Label = "TestBeacon2",
Center = new CenterObjectV1 { Type = "Point", Coordinates = new double[] { 2, 2 } },
Radius = 70
};
private static readonly ConfigParams HttpConfig = ConfigParams.FromTuples(
"connection.protocol", "http",
"connection.host", "localhost",
"connection.port", "3000"
);
private BeaconsMemoryPersistence _persistence;
private BeaconsController _controller;
private BeaconsHttpServiceV1 _service;
private TestCommandableHttpClient _client;
public BeaconsHttpServiceV1Test()
{
_persistence = new BeaconsMemoryPersistence();
_controller = new BeaconsController();
_service = new BeaconsHttpServiceV1();
_client = new TestCommandableHttpClient("v1/beacons");
IReferences references = References.FromTuples(
new Descriptor("beacons", "persistence", "memory", "default", "1.0"), _persistence,
new Descriptor("beacons", "controller", "default", "default", "1.0"), _controller,
new Descriptor("beacons", "service", "http", "default", "1.0"), _service,
new Descriptor("beacons", "client", "http", "default", "1.0"), _client
);
_controller.SetReferences(references);
_service.Configure(HttpConfig);
_service.SetReferences(references);
_client.Configure(HttpConfig);
_service.OpenAsync(null).Wait();
// Todo: This is defect! Open shall not block the tread
//Task.Run(() => _service.OpenAsync(null));
//Thread.Sleep(1000); // Just let service a sec to be initialized
_client.OpenAsync(null).Wait();
}
[Fact]
public async Task TestCrudOperationsAsync()
{
// Create the first beacon
var beacon = await _client.CallCommandAsync<BeaconV1>(
"create_beacon", null, new { beacon = BEACON1 });
Assert.NotNull(beacon);
Assert.Equal(BEACON1.Udi, beacon.Udi);
Assert.Equal(BEACON1.SiteId, beacon.SiteId);
Assert.Equal(BEACON1.Type, beacon.Type);
Assert.Equal(BEACON1.Label, beacon.Label);
Assert.NotNull(beacon.Center);
// Create the second beacon
beacon = await _client.CallCommandAsync<BeaconV1>(
"create_beacon", null, new { beacon = BEACON2 });
Assert.NotNull(beacon);
Assert.Equal(BEACON2.Udi, beacon.Udi);
Assert.Equal(BEACON2.SiteId, beacon.SiteId);
Assert.Equal(BEACON2.Type, beacon.Type);
Assert.Equal(BEACON2.Label, beacon.Label);
Assert.NotNull(beacon.Center);
// Get all beacons
var page = await _client.CallCommandAsync<DataPage<BeaconV1>>(
"get_beacons",
null,
new
{
filter = new FilterParams(),
paging = new PagingParams()
}
);
Assert.NotNull(page);
Assert.Equal(2, page.Data.Count);
var beacon1 = page.Data[0];
// Update the beacon
beacon1.Label = "ABC";
beacon = await _client.CallCommandAsync<BeaconV1>(
"update_beacon", null, new { beacon = beacon1 });
Assert.NotNull(beacon);
Assert.Equal(beacon1.Id, beacon.Id);
Assert.Equal("ABC", beacon.Label);
// Get beacon by udi
beacon = await _client.CallCommandAsync<BeaconV1>(
"get_beacon_by_udi", null, new { udi = beacon1.Udi });
Assert.NotNull(beacon);
Assert.Equal(beacon1.Id, beacon.Id);
// Delete the beacon
beacon = await _client.CallCommandAsync<BeaconV1>(
"delete_beacon_by_id", null, new { beacon_id = beacon1.Id });
Assert.NotNull(beacon);
Assert.Equal(beacon1.Id, beacon.Id);
// Try to get deleted beacon
beacon = await _client.CallCommandAsync<BeaconV1>(
"get_beacon_by_id", null, new { beacon_id = beacon1.Id });
Assert.Null(beacon);
}
}
}
Run the dotnet test
command and make sure that all of the tests pass successfully.
/test/services/version1/BeaconsHttpServiceV1_test.go
package test_services1
import (
"context"
cclients "github.com/pip-services3-gox/pip-services3-rpc-gox/clients"
"testing"
data1 "github.com/pip-services-samples/service-beacons-gox/data/version1"
logic "github.com/pip-services-samples/service-beacons-gox/logic"
persist "github.com/pip-services-samples/service-beacons-gox/persistence"
services1 "github.com/pip-services-samples/service-beacons-gox/services/version1"
cconf "github.com/pip-services3-gox/pip-services3-commons-gox/config"
cdata "github.com/pip-services3-gox/pip-services3-commons-gox/data"
cref "github.com/pip-services3-gox/pip-services3-commons-gox/refer"
tclients "github.com/pip-services3-gox/pip-services3-rpc-gox/test"
"github.com/stretchr/testify/assert"
)
type beaconsHttpServiceV1Test struct {
BEACON1 *data1.BeaconV1
BEACON2 *data1.BeaconV1
persistence *persist.BeaconsMemoryPersistence
controller *logic.BeaconsController
service *services1.BeaconsHttpServiceV1
client *tclients.TestCommandableHttpClient
}
func newBeaconsHttpServiceV1Test() *beaconsHttpServiceV1Test {
BEACON1 := &data1.BeaconV1{
Id: "1",
Udi: "00001",
Type: data1.AltBeacon,
SiteId: "1",
Label: "TestBeacon1",
Center: data1.GeoPointV1{Type: "Point", Coordinates: []float32{0.0, 0.0}},
Radius: 50,
}
BEACON2 := &data1.BeaconV1{
Id: "2",
Udi: "00002",
Type: data1.IBeacon,
SiteId: "1",
Label: "TestBeacon2",
Center: data1.GeoPointV1{Type: "Point", Coordinates: []float32{2.0, 2.0}},
Radius: 70,
}
restConfig := cconf.NewConfigParamsFromTuples(
"connection.protocol", "http",
"connection.port", "3000",
"connection.host", "localhost",
)
persistence := persist.NewBeaconsMemoryPersistence()
persistence.Configure(context.Background(), cconf.NewEmptyConfigParams())
controller := logic.NewBeaconsController()
controller.Configure(context.Background(), cconf.NewEmptyConfigParams())
service := services1.NewBeaconsHttpServiceV1()
service.Configure(context.Background(), restConfig)
client := tclients.NewTestCommandableHttpClient("v1/beacons")
client.Configure(context.Background(), restConfig)
references := cref.NewReferencesFromTuples(
context.Background(),
cref.NewDescriptor("beacons", "persistence", "memory", "default", "1.0"), persistence,
cref.NewDescriptor("beacons", "controller", "default", "default", "1.0"), controller,
cref.NewDescriptor("beacons", "service", "http", "default", "1.0"), service,
cref.NewDescriptor("beacons", "client", "http", "default", "1.0"), client,
)
controller.SetReferences(context.Background(), references)
service.SetReferences(context.Background(), references)
return &beaconsHttpServiceV1Test{
BEACON1: BEACON1,
BEACON2: BEACON2,
persistence: persistence,
controller: controller,
service: service,
client: client,
}
}
func (c *beaconsHttpServiceV1Test) setup(t *testing.T) {
err := c.persistence.Open(context.Background(), "")
if err != nil {
t.Error("Failed to open persistence", err)
}
err = c.service.Open(context.Background(), "")
if err != nil {
t.Error("Failed to open service", err)
}
err = c.client.Open(context.Background(), "")
if err != nil {
t.Error("Failed to open client", err)
}
err = c.persistence.Clear(context.Background(), "")
if err != nil {
t.Error("Failed to clear persistence", err)
}
}
func (c *beaconsHttpServiceV1Test) teardown(t *testing.T) {
err := c.client.Close(context.Background(), "")
if err != nil {
t.Error("Failed to close client", err)
}
err = c.service.Close(context.Background(), "")
if err != nil {
t.Error("Failed to close service", err)
}
err = c.persistence.Close(context.Background(), "")
if err != nil {
t.Error("Failed to close persistence", err)
}
}
func (c *beaconsHttpServiceV1Test) testCrudOperations(t *testing.T) {
var beacon1 data1.BeaconV1
// Create the first beacon
params := cdata.NewAnyValueMapFromTuples(
"beacon", c.BEACON1.Clone(),
)
response, err := c.client.CallCommand(context.Background(), "create_beacon", "", params)
assert.Nil(t, err)
assert.NotNil(t, response)
beacon, err := cclients.HandleHttpResponse[data1.BeaconV1](response, "")
assert.Nil(t, err)
assert.NotEqual(t, data1.BeaconV1{}, beacon)
assert.Equal(t, c.BEACON1.Udi, beacon.Udi)
assert.Equal(t, c.BEACON1.SiteId, beacon.SiteId)
assert.Equal(t, c.BEACON1.Type, beacon.Type)
assert.Equal(t, c.BEACON1.Label, beacon.Label)
assert.NotNil(t, beacon.Center)
// Create the second beacon
params = cdata.NewAnyValueMapFromTuples(
"beacon", c.BEACON2.Clone(),
)
response, err = c.client.CallCommand(context.Background(), "create_beacon", "", params)
assert.Nil(t, err)
assert.NotNil(t, response)
beacon, err = cclients.HandleHttpResponse[data1.BeaconV1](response, "")
assert.Nil(t, err)
assert.NotEqual(t, data1.BeaconV1{}, beacon)
assert.Equal(t, c.BEACON2.Udi, beacon.Udi)
assert.Equal(t, c.BEACON2.SiteId, beacon.SiteId)
assert.Equal(t, c.BEACON2.Type, beacon.Type)
assert.Equal(t, c.BEACON2.Label, beacon.Label)
assert.NotNil(t, beacon.Center)
// Get all beacons
params = cdata.NewAnyValueMapFromTuples(
"filter", cdata.NewEmptyFilterParams(),
"paging", cdata.NewEmptyFilterParams(),
)
response, err = c.client.CallCommand(context.Background(), "get_beacons", "", params)
assert.Nil(t, err)
assert.NotNil(t, response)
page, err := cclients.HandleHttpResponse[cdata.DataPage[data1.BeaconV1]](response, "")
assert.Nil(t, err)
assert.True(t, page.HasData())
assert.Len(t, page.Data, 2)
beacon1 = page.Data[0].Clone()
// Update the beacon
beacon1.Label = "ABC"
params = cdata.NewAnyValueMapFromTuples(
"beacon", beacon1,
)
response, err = c.client.CallCommand(context.Background(), "update_beacon", "", params)
assert.Nil(t, err)
assert.NotNil(t, response)
beacon, err = cclients.HandleHttpResponse[data1.BeaconV1](response, "")
assert.Nil(t, err)
assert.NotEqual(t, data1.BeaconV1{}, beacon)
assert.Equal(t, c.BEACON1.Id, beacon.Id)
assert.Equal(t, "ABC", beacon.Label)
// Get beacon by udi
params = cdata.NewAnyValueMapFromTuples(
"udi", beacon1.Udi,
)
response, err = c.client.CallCommand(context.Background(), "get_beacon_by_udi", "", params)
assert.Nil(t, err)
assert.NotNil(t, response)
beacon, err = cclients.HandleHttpResponse[data1.BeaconV1](response, "")
assert.Nil(t, err)
assert.NotEqual(t, data1.BeaconV1{}, beacon)
assert.Equal(t, c.BEACON1.Id, beacon.Id)
// Calculate position for one beacon
params = cdata.NewAnyValueMapFromTuples(
"site_id", "1",
"udis", []string{"00001"},
)
response, err = c.client.CallCommand(context.Background(), "calculate_position", "", params)
assert.Nil(t, err)
assert.NotNil(t, response)
position, err := cclients.HandleHttpResponse[data1.GeoPointV1](response, "")
assert.Nil(t, err)
assert.NotEqual(t, data1.GeoPointV1{}, position)
assert.Equal(t, "Point", position.Type)
assert.Equal(t, (float32)(0.0), position.Coordinates[0])
assert.Equal(t, (float32)(0.0), position.Coordinates[1])
// Delete the beacon
params = cdata.NewAnyValueMapFromTuples(
"beacon_id", beacon1.Id,
)
response, err = c.client.CallCommand(context.Background(), "delete_beacon_by_id", "", params)
assert.Nil(t, err)
beacon, err = cclients.HandleHttpResponse[data1.BeaconV1](response, "")
assert.Nil(t, err)
assert.NotNil(t, response)
assert.NotEqual(t, data1.BeaconV1{}, beacon)
assert.Equal(t, c.BEACON1.Id, beacon.Id)
// Try to get deleted beacon
params = cdata.NewAnyValueMapFromTuples(
"beacon_id", beacon1.Id,
)
response, err = c.client.CallCommand(context.Background(), "get_beacon_by_id", "", params)
assert.Nil(t, err)
assert.NotNil(t, response)
beacon, err = cclients.HandleHttpResponse[data1.BeaconV1](response, "")
assert.Nil(t, err)
assert.Equal(t, data1.BeaconV1{}, beacon)
}
func TestBeaconsCommmandableHttpServiceV1(t *testing.T) {
c := newBeaconsHttpServiceV1Test()
c.setup(t)
t.Run("CRUD Operations", c.testCrudOperations)
c.teardown(t)
}
Run the go test -v ./test/...
command and make sure that all of the tests pass successfully.
/test/services/version1/BeaconsCommandableHttpServiceV1_test.dart
import 'dart:convert';
import 'package:test/test.dart';
import 'package:http/http.dart' as http;
import 'package:pip_services3_commons/pip_services3_commons.dart';
import 'package:pip_services_beacons_dart/pip_services_beacons_dart.dart';
final BEACON1 = BeaconV1(
id: '1',
udi: '00001',
type: BeaconTypeV1.altBeacon,
site_id: '1',
label: 'TestBeacon1',
center: {
'type': 'Point',
'coordinates': [0.0, 0.0]
},
radius: 50.0);
final BEACON2 = BeaconV1(
id: '2',
udi: '00002',
type: BeaconTypeV1.iBeacon,
site_id: '1',
label: 'TestBeacon2',
center: {
'type': 'Point',
'coordinates': [2.0, 2.0]
},
radius: 70.0);
var httpConfig = ConfigParams.fromTuples([
'connection.protocol',
'http',
'connection.host',
'localhost',
'connection.port',
3000
]);
void main() {
group('BeaconsCommandableHttpServiceV1', () {
BeaconsMemoryPersistence persistence;
BeaconsController controller;
BeaconsCommandableHttpServiceV1 service;
http.Client rest;
String url;
setUp(() async {
url = 'http://localhost:3000';
rest = http.Client();
persistence = BeaconsMemoryPersistence();
persistence.configure(ConfigParams());
controller = BeaconsController();
controller.configure(ConfigParams());
service = BeaconsCommandableHttpServiceV1();
service.configure(httpConfig);
var references = References.fromTuples([
Descriptor('beacons', 'persistence', 'memory', 'default', '1.0'),
persistence,
Descriptor('beacons', 'controller', 'default', 'default', '1.0'),
controller,
Descriptor('beacons', 'service', 'http', 'default', '1.0'),
service
]);
controller.setReferences(references);
service.setReferences(references);
await persistence.open(null);
await service.open(null);
});
tearDown(() async {
await service.close(null);
await persistence.close(null);
});
test('CRUD Operations', () async {
BeaconV1 beacon1;
// Create the first beacon
var resp = await rest.post(url + '/v1/beacons/create_beacon',
headers: {'Content-Type': 'application/json'},
body: json.encode({'beacon': BEACON1}));
var beacon = BeaconV1();
beacon.fromJson(json.decode(resp.body));
expect(beacon, isNotNull);
expect(BEACON1.udi, beacon.udi);
expect(BEACON1.site_id, beacon.site_id);
expect(BEACON1.type, beacon.type);
expect(BEACON1.label, beacon.label);
expect(beacon.center, isNotNull);
// Create the second beacon
resp = await rest.post(url + '/v1/beacons/create_beacon',
headers: {'Content-Type': 'application/json'},
body: json.encode({'beacon': BEACON2}));
beacon = BeaconV1();
beacon.fromJson(json.decode(resp.body));
expect(beacon, isNotNull);
expect(BEACON2.udi, beacon.udi);
expect(BEACON2.site_id, beacon.site_id);
expect(BEACON2.type, beacon.type);
expect(BEACON2.label, beacon.label);
expect(beacon.center, isNotNull);
// Get all beacons
resp = await rest.post(url + '/v1/beacons/get_beacons',
headers: {'Content-Type': 'application/json'},
body: json
.encode({'filter': FilterParams(), 'paging': PagingParams()}));
var page = DataPage<BeaconV1>.fromJson(json.decode(resp.body), (item) {
var beacon = BeaconV1();
beacon.fromJson(item);
return beacon;
});
expect(page, isNotNull);
expect(page.data.length, 2);
beacon1 = page.data[0];
// Update the beacon
beacon1.label = 'ABC';
resp = await rest.post(url + '/v1/beacons/update_beacon',
headers: {'Content-Type': 'application/json'},
body: json.encode({'beacon': beacon1}));
beacon = BeaconV1();
beacon.fromJson(json.decode(resp.body));
expect(beacon, isNotNull);
expect(beacon1.id, beacon.id);
expect('ABC', beacon.label);
// Get beacon by udi
resp = await rest.post(url + '/v1/beacons/get_beacon_by_udi',
headers: {'Content-Type': 'application/json'},
body: json.encode({'udi': beacon1.udi}));
beacon = BeaconV1();
beacon.fromJson(json.decode(resp.body));
expect(beacon, isNotNull);
expect(beacon1.id, beacon.id);
// Calculate position for one beacon
resp = await rest.post(url + '/v1/beacons/calculate_position',
headers: {'Content-Type': 'application/json'},
body: json.encode({
'site_id': '1',
'udis': ['00001']
}));
var position = json.decode(resp.body);
expect(position, isNotNull);
expect('Point', position['type']);
expect(position['coordinates'].length, 2);
expect(0, position['coordinates'][0]);
expect(0, position['coordinates'][1]);
// Delete the beacon
resp = await rest.post(url + '/v1/beacons/delete_beacon_by_id',
headers: {'Content-Type': 'application/json'},
body: json.encode({'beacon_id': beacon1.id}));
beacon = BeaconV1();
beacon.fromJson(json.decode(resp.body));
expect(beacon, isNotNull);
expect(beacon1.id, beacon.id);
// Try to get deleted beacon
resp = await rest.post(url + '/v1/beacons/get_beacon_by_id',
headers: {'Content-Type': 'application/json'},
body: json.encode({'beacon_id': beacon1.id}));
expect(resp.body, isEmpty);
});
});
}
Run the pub run test
command and make sure that all of the tests pass successfully.
/test/services/version1/test_BeaconsHttpServiceV1.py
import json
import time
from json import JSONDecodeError
from typing import Union
import requests
from pip_services3_commons.config import ConfigParams
from pip_services3_commons.refer import References, Descriptor
from pip_services3_commons.reflect import PropertyReflector
from pip_services3_commons.run import Parameters
from src.data.version1 import BeaconV1, BeaconTypeV1
from src.logic.BeaconsController import BeaconsController
from src.persistence.BeaconsMemoryPersistence import BeaconsMemoryPersistence
from src.services.version1.BeaconsHttpServiceV1 import BeaconsHttpServiceV1
BEACON1 = BeaconV1("1", "1", BeaconTypeV1.AltBeacon, "00001", "TestBeacon1", {"type": 'Point', "coordinates": [0, 0]},
50.0)
BEACON2 = BeaconV1("2", "1", BeaconTypeV1.iBeacon, "00002", "TestBeacon2", {"type": 'Point', "coordinates": [2, 2]},
70.0)
BEACON3 = BeaconV1("3", "2", BeaconTypeV1.AltBeacon, "00003", "TestBeacon3", {"type": 'Point', "coordinates": [10, 10]},
50.0)
class TestBeaconsHttpServiceV1:
_persistence: BeaconsMemoryPersistence
_controller: BeaconsController
_service: BeaconsHttpServiceV1
@classmethod
def setup_class(cls):
cls._persistence = BeaconsMemoryPersistence()
cls._controller = BeaconsController()
cls._service = BeaconsHttpServiceV1()
cls._service.configure(ConfigParams.from_tuples(
'connection.protocol', 'http',
'connection.port', 3002,
'connection.host', 'localhost'))
references = References.from_tuples(Descriptor('beacons', 'persistence', 'memory', 'default', '1.0'),
cls._persistence,
Descriptor('beacons', 'controller', 'default', 'default', '1.0'),
cls._controller,
Descriptor('beacons', 'service', 'http', 'default', '1.0'),
cls._service)
cls._controller.set_references(references)
cls._service.set_references(references)
cls._persistence.open(None)
cls._service.open(None)
@classmethod
def teardown_class(cls):
cls._persistence.close(None)
cls._service.close(None)
def test_crud_operations(self):
time.sleep(2)
# Create the first beacon
beacon1 = self.invoke("/v1/beacons/create_beacon",
Parameters.from_tuples("beacon", PropertyReflector.get_properties(BEACON1)))
assert beacon1 is not None
assert beacon1['id'] == BEACON1.id
assert beacon1['site_id'] == BEACON1.site_id
assert beacon1['udi'] == BEACON1.udi
assert beacon1['type'] == BEACON1.type
assert beacon1['label'] == BEACON1.label
assert beacon1['center'] is not None
# Create the second beacon
beacon2 = self.invoke("/v1/beacons/create_beacon",
Parameters.from_tuples("beacon", PropertyReflector.get_properties(BEACON2)))
assert beacon2 is not None
assert beacon2['id'] == BEACON2.id
assert beacon2['site_id'] == BEACON2.site_id
assert beacon2['udi'] == BEACON2.udi
assert beacon2['type'] == BEACON2.type
assert beacon2['label'] == BEACON2.label
assert beacon2['center'] is not None
# Get all beacons
page = self.invoke("/v1/beacons/get_beacons", Parameters.from_tuples("beacons"))
assert page is not None
assert len(page['data']) == 2
beacon1 = page['data'][0]
# Update the beacon
beacon1['label'] = "ABC"
beacon = self.invoke("/v1/beacons/update_beacon", Parameters.from_tuples("beacon", beacon1))
assert beacon is not None
assert beacon1['id'] == beacon['id']
assert "ABC" == beacon['label']
# Get beacon by udi
beacon = self.invoke("/v1/beacons/get_beacon_by_udi", Parameters.from_tuples("udi", beacon1['udi']))
assert beacon is not None
assert beacon['id'] == beacon1['id']
# Calculate position for one beacon
position = self.invoke("/v1/beacons/calculate_position",
Parameters.from_tuples("site_id", '1', "udis", ['00001']))
assert position is not None
assert "Point" == position["type"]
assert 2 == len(position["coordinates"])
assert 0 == position["coordinates"][0]
assert 0 == position["coordinates"][1]
# Delete beacon
self.invoke("/v1/beacons/delete_beacon_by_id", Parameters.from_tuples("id", beacon1['id']))
# Try to get deleted beacon
beacon = self.invoke("/v1/beacons/get_beacon_by_id", Parameters.from_tuples("id", beacon1['id']))
assert beacon is False
def invoke(self, route, entity) -> Union[bool, dict]:
params = {}
route = "http://localhost:3002" + route
response = None
timeout = 10000
# Call the service
data = json.dumps(entity)
try:
response = requests.request('POST', route, params=params, json=data, timeout=timeout)
return response.json()
except JSONDecodeError:
if response.status_code == 404:
return False
Run the python test.py
command and make sure that all of the tests pass successfully.
Congratulations! This step finishes off the development of our microservice! However, before we can start our service up as a fully fledged microservice, we’ll first need to compose all of its components using a process container. And that’s exactly what we’ll be doing in Step 7. Wrapping microservice into container.