So, let’s start developing microservices using the Pip.Services toolkit. As a simple example, we will make a Hello World microservice, which will greet you in response to your request. The communication protocol will be HTTP REST.
The microservice is structurally made up of these components:
To continue, choose the language with which you will be writing the microservice:
Create a folder for the project and within it, add a pubspec.yaml file with the name of your microservice and a list of dependencies for your necessary components. For editing, you can use any text editor or IDE of your choice.
/pubspec.yaml
In the command line, type out the command below to install the dependencies:
Create the file:
/lib/src/pip_quickstart.dart
Create a file:
/lib/helloworld.dart
These files are necessary export classes outside the library.
The controller will be a simple class that implements a single business method, which receives a name and generates a greeting. In general, business methods can call other built-in services or work with a database. Since their execution time might take too long, business methods are implemented in Dart as asynchronous functions:
To demonstrate the dynamic configuration of a component, the recipient name will be specified by the parameter “default_name”. To get the configuration, the component must implement the interface “IConfigurable” with the method “configure”.
Parameters will be read by the microservice from the configuration file and passed to the “configure” method of the corresponding component. Here’s an example of the configuration:
More details on this mechanism can be found in The Configuration recipe.
This is all the code of the controller in the file:
/lib/src/HelloWorldController.dart
One of the most popular ways of transferring data between microservices is using the synchronous HTTP REST protocol. The HelloWorldRestService will be used to implement an external REST interface. This component extends the abstract RestService of the Pip.Services toolkit, which implements all the necessary functionality for processing REST HTTP requests.
Next, we’ll need to register the REST operations that we’ll be using in the class’s register method. In this microservice, we’ll only be needing to implement a single GET command: “/greeting”. This command receives a “name” parameter, calls the controller’s “greeting” method, and returns the generated result to the client.
To get a reference to the controller, we’ll add its descriptor to the _dependencyResolver with a name of “controller”.
Using this descriptor, the base class will be able to find a reference to the controller during component linking. Check out [The Locator Pattern] for more on how this mechanism works.
We also need to set a base route in the service’s constructor using the _baseRoute property. As a result, the microservice’s full REST request will look something like:
Full listing for the REST service found in the file:
/lib/src/HelloWorldRestService.dart
import 'package:angel_framework/angel_framework.dart' as angel;
import 'package:pip_services3_rpc/pip_services3_rpc.dart';
import 'package:pip_services3_commons/pip_services3_commons.dart';
import './HelloWorldController.dart';
class HelloWorldRestService extends RestService {
HelloWorldController controller;
HelloWorldRestService() : super() {
baseRoute = '/hello_world';
dependencyResolver.put(
'controller', Descriptor('hello-world', 'controller', '*', '*', '1.0'));
}
@override
void setReferences(references) {
super.setReferences(references);
controller =
dependencyResolver.getOneRequired<HelloWorldController>('controller');
}
@override
void register() {
registerRoute('get', '/greeting', null,
(angel.RequestContext req, angel.ResponseContext res) async{
var name = req.queryParameters['name'];
sendResult(req, res, null, await controller.greeting(name));
});
}
}
When a microservice is being populated by components based on the configuration being used, it requires a special factory to create components in accordance with their descriptors. The HelloWorldServiceFactory class is used for just that, as it extends the Factory class of the Pip.Services toolkit.
Next, in the factory’s constructor, we’ll be registering descriptors and their corresponding component types.
For more info on how this works, be sure to check out [The Container recipe].
Full listing of the factory’s code found in the file:
/lib/src/HelloWorldServiceFactory.dart
Last but not least, our microservice needs a container component. This component creates all of the other components, links them with one another, and controls their life cycle. Although there exist many different ways of running a microservice in a container (regular classes, serverless functions, serlets, etc), we’ll be running our example microservice as a system process. To do this, we’ll make the HelloWorldProcess extend the ProcessContainer class of the Pip.Services toolkit.
Although containers can be populated by components manually, we’ll be using dynamic configuration to do this. By default, ProcessContainer reads the configuration from an external config.yml file. All we have left to do is register the factory for creating components from their descriptors.
Full listing of the container’s code found in the file:
/lib/src/HelloWorldProcess.dart
The dynamic configuration is defined in the file:
/config.yml
Looking at the configuration file, we can conclude that the following components will be created in the microservice:
As you may have noticed, more than half of the components are being taken from Pip.Services and used “right out of the box”. This significantly expands our microservice’s capabilities, with minimal effort on our part.
In Dart, we’ll need a special file to run the microservice. All this file does is creates a container instance and runs it with the parameters provided from the command line.
/bin/run.dart.
When a microservice starts up, the following sequence of events takes place:
When the microservice receives a signal to stop the process, the reverse sequence takes place:
To start the microservice, run the following command from a terminal:
If the microservice started up successfully, you should see the following result in the terminal:
[echo:INFO:2018-09-25T15:15:30.284Z] Press Control-C to stop the microservice...
[echo:DEBUG:2018-09-25T15:15:30.542Z] Opened REST service at http://0.0.0.0:8080
[echo:INFO:2018-09-25T15:15:30.542Z] Container hello-world started.
Test the microservice by requesting the following URL in a browser:
If all’s well, you should get the following string as a result:
All source codes are available on GitHub.
To learn even more about Pip.Services, consider creating a Data Microservice as your next step!