Swagger
Key takeaways
Swagger module | Contains components used to generate Swagger UIs. |
Swagger YAML file | File used to declare methods to be documented via Swagger. |
Swagger | An Interface Description Language for describing RESTful APIs using JSON. |
Introduction
In this tutorial, you will learn how to generate Swagger documentation for a REST service. We will see three different cases. The first is a common REST service, which is documented via a YAML file containing a description of its methods. The second is a commandable REST service, which has a defined set of commands that is used to define the Swagger document. Finally, the last case considers a commandable REST component with a command set and a Swagger UI defined by a YAML file.
Swagger document generation
Pip.Services offers two types of REST services, which are defined by two different classes. The first is an ordinary REST service and is defined by the RestService component. The second is a REST service that contains a set of predefined commands (or methods) that can be called from other services and is defined by the CommandableHttpService class.
As such, they represent two different approaches when it comes to Swagger documentation: A REST service needs a YAML file that describes its UI in order to generate its documentation, whereas a commandable service allows for automatic generation via a description of the command set or via a YAML file if the path to it is included in the configuration file. Moreover, it should be noted that an automatically-generated description always considers an HTTP method as POST.
To explain these cases, we will create an app that given a name returns the phrase “Hello {name}” by calling a method named greeting. In this app, we will include the necessary elements to create a Swagger UI that documents this method. The following sections teach the steps to achieve this goal.
Pre-requisites
First of all, to create a Swagger UI, we need to install the swagger module. This can be done with the following command:
npm install pip-services3-swagger-nodex --save
dotnet add package PipServices3.Swagger
go get github.com/pip-services3-gox/pip-services3-swagger-gox
dart pub add pip_services3_swagger
pip install pip-services3-swagger
Document 1: REST service
In this case, we want to document the greeting method as part of a REST service. For this, we need to define a YAML file containing the information necessary to create the Swagger UI.
Service
Our REST service is called HelloFriendService. It is defined by a class that inherits from the RestService component and has a method named greetings, which given a name, returns “Hello {name}” on a web page.
It also contains a reference to the controller and a method named register that defines the necessary elements for the Swagger UI. Its code is as follows:
import { ConfigParams, Descriptor, IReferences } from 'pip-services3-commons-nodex';
import { RestService } from 'pip-services3-rpc-nodex';
class HelloFriendRestService extends RestService {
private _controller: HelloFriendController;
// swagger
private _swaggerContent: string;
private _swaggerPath: string;
public constructor() {
super();
this._baseRoute = "/hello_friend";
let controllerDescriptor = new Descriptor("hello-friend", "controller", "*", "*", "1.0");
this._dependencyResolver.put("controller", controllerDescriptor);
}
public configure(config: ConfigParams): void {
super.configure(config);
// swagger
this._swaggerContent = config.getAsNullableString("swagger.content");
this._swaggerPath = config.getAsNullableString("swagger.path");
}
public setReferences(references: IReferences) {
super.setReferences(references);
this._controller = this._dependencyResolver.getOneRequired<HelloFriendController>("controller");
}
public register(): void {
this.registerRoute("GET", "/greeting", null, this.greeting);
// swagger
if (this._swaggerContent != null)
this.registerOpenApiSpec(this._swaggerContent);
if (this._swaggerPath != null)
this.registerOpenApiSpecFromFile(this._swaggerPath);
}
public async greeting(req: any, res: any): Promise<void> {
let name = req.query.name;
let result = this._controller.greeting(name);
this.sendResult(req, res, result);
}
}
using System.Threading.Tasks;
using PipServices3.Commons.Config;
using PipServices3.Commons.Refer;
using PipServices3.Rpc.Services;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
public class HelloFriendRestService: RestService
{
private HelloFriendController _controller;
// swagger
private string _swaggerContent;
private string _swaggerPath;
public HelloFriendRestService(): base()
{
_baseRoute = "/hello_friend";
var controllerDescriptor = new Descriptor("hello-friend", "controller", "*", "*", "1.0");
_dependencyResolver.Put("controller", controllerDescriptor);
}
public override void Configure(ConfigParams config)
{
base.Configure(config);
// swagger
_swaggerContent = config.GetAsNullableString("swagger.content");
_swaggerPath = config.GetAsNullableString("swagger.path");
}
public override void SetReferences(IReferences references)
{
base.SetReferences(references);
_controller = _dependencyResolver.GetOneRequired<HelloFriendController>("controller");
}
public override void Register()
{
RegisterRoute("GET", "/greeting", this.Greeting);
// swagger
if (_swaggerContent != null)
RegisterOpenApiSpec(_swaggerContent);
if (_swaggerPath != null)
RegisterOpenApiSpecFromFile(_swaggerPath);
}
public async Task Greeting(HttpRequest req, HttpResponse res, RouteData routeData)
{
var name = req.Query["name"];
var result = _controller.Greeting(name);
await SendResultAsync(res, result);
}
}
import (
"context"
"net/http"
"os"
ccmd "github.com/pip-services3-gox/pip-services3-commons-gox/commands"
cconf "github.com/pip-services3-gox/pip-services3-commons-gox/config"
crefer "github.com/pip-services3-gox/pip-services3-commons-gox/refer"
crun "github.com/pip-services3-gox/pip-services3-commons-gox/run"
cvalid "github.com/pip-services3-gox/pip-services3-commons-gox/validate"
cbuild "github.com/pip-services3-gox/pip-services3-components-gox/build"
cproc "github.com/pip-services3-gox/pip-services3-container-gox/container"
rbuild "github.com/pip-services3-gox/pip-services3-rpc-gox/build"
rpcservices "github.com/pip-services3-gox/pip-services3-rpc-gox/services"
cswagger "github.com/pip-services3-gox/pip-services3-swagger-gox/build"
)
// REST service (Swagger UI from YAML file)
type HelloFriendRestService struct {
*rpcservices.RestService
_swaggerContent string
_swaggerPath string
_controller *HelloFriendController
}
func NewHelloFriendRestService() *HelloFriendRestService {
c := &HelloFriendRestService{}
c.RestService = rpcservices.InheritRestService(c)
c.BaseRoute = "/hello_friend"
controllerDescriptor := crefer.NewDescriptor("hello-friend", "controller", "*", "*", "1.0")
c.DependencyResolver.Put(context.Background(), "controller", controllerDescriptor)
return c
}
func (c *HelloFriendRestService) Configure(ctx context.Context, config *cconf.ConfigParams) {
c.RestService.Configure(context.Background(), config)
// swagger
c._swaggerContent, _ = config.GetAsNullableString("swagger.content")
c._swaggerPath, _ = config.GetAsNullableString("swagger.path")
}
func (c *HelloFriendRestService) SetReferences(ctx context.Context, references crefer.IReferences) {
c.RestService.SetReferences(ctx, references)
depRes, depErr := c.DependencyResolver.GetOneRequired("controller")
if depErr == nil && depRes != nil {
c._controller = depRes.(*HelloFriendController)
}
}
func (c *HelloFriendRestService) greeting(res http.ResponseWriter, req *http.Request) {
// vars := mux.Vars(req)
name := req.URL.Query().Get("message")
// message := vars["name"]
result := c._controller.Greeting(name)
c.SendResult(res, req, result, nil)
}
func (c *HelloFriendRestService) Register() {
c.RegisterRoute("GET", "/greeting", nil, c.greeting)
// swagger
if c._swaggerContent != "" {
c.RegisterOpenApiSpec(c._swaggerContent)
}
if c._swaggerPath != "" {
c.RegisterOpenApiSpecFromFile(c._swaggerPath)
}
}
import 'dart:async';
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';
class HelloFriendRestService extends RestService {
HelloFriendController? _controller;
String? _swaggerContent;
String? _swaggerPath;
HelloFriendRestService() : super() {
baseRoute = '/hello_friend';
var controllerDescriptor =
Descriptor('hello-friend', 'controller', '*', '*', '1.0');
dependencyResolver.put('controller', controllerDescriptor);
}
@override
void configure(ConfigParams config) {
super.configure(config);
// swagger
_swaggerContent = config.getAsNullableString("swagger.content");
_swaggerPath = config.getAsNullableString("swagger.path");
}
@override
void setReferences(IReferences references) {
super.setReferences(references);
_controller =
dependencyResolver.getOneRequired<HelloFriendController>('controller');
}
@override
void register() {
registerRoute('get', '/greeting', null, _greeting);
// swagger
if (_swaggerContent != null) {
registerOpenApiSpec_(_swaggerContent!);
}
if (_swaggerPath != null) {
registerOpenApiSpecFromFile(_swaggerPath!);
}
}
FutureOr<Response> _greeting(Request req) {
var name = req.params['name'];
var result = _controller!.greeting(name);
return sendResult(req, result);
}
}
from pip_services3_commons.refer import Descriptor
from pip_services3_commons.validate import Schema
from pip_services3_rpc.services import RestService
import bottle
class HelloFriendRestService(RestService):
def __init__(self):
super(HelloFriendRestService, self).__init__()
self._base_route = "/hello_friend"
ControllerDescriptor = Descriptor('hello-friend', 'controller', '*', '*', '1.0')
self._dependency_resolver.put('controller', ControllerDescriptor)
self._controller = None
# Swagger
self._swagger_content = None
self._swagger_path = None
def configure(self, config):
super().configure(config)
# Swagger
self._swagger_content = config.get_as_nullable_string("swagger.content")
self._swagger_path = config.get_as_nullable_string('swagger.path')
def set_references(self, references):
super(HelloFriendRestService, self).set_references(references)
self._controller = self._dependency_resolver.get_one_required('controller')
def register(self):
self.register_route(method="GET", route="/greeting", schema=Schema(), handler=self.greeting)
# Swagger
if self._swagger_content:
self._register_open_api_spec(self._swagger_content)
if self._swagger_path:
self._register_open_api_spec_from_file(self._swagger_path)
def greeting(self):
name = bottle.request.query.get('name')
result = self._controller.greeting(name)
return self.send_result(result)
Configuration
As we will use a process container to run the example, we need to describe this service in the configuration file. In this description, we set the Swagger’s enable field to true to specify that we want to generate a Swagger UI for the service, and we define the path to our YAML file containing the Swagger UI description.
# HTTP Service V1
- descriptor: "hello-friend:service:http:default:1.0"
swagger:
enable: true
path: './rest_swagger.yml'
# HTTP Service V1
- descriptor: "hello-friend:service:http:default:1.0"
swagger:
enable: true
path: '../../../rest_swagger.yml'
# HTTP Service V1
- descriptor: "hello-friend:service:http:default:1.0"
swagger:
enable: true
path: './rest_swagger.yml'
# HTTP Service V1
- descriptor: "hello-friend:service:http:default:1.0"
swagger:
enable: true
path: './rest_swagger.yml'
# HTTP Service V1
- descriptor: "hello-friend:service:http:default:1.0"
swagger:
enable: true
path: './rest_swagger.yml'
Swagger YAML file
Now, we create a YAML file that will be used by Swagger to define the UI. In our case, the service has the greeting method only, which we consider of type GET. An example of this file is:
openapi: '3.0.2'
info:
title: 'Friends Service'
description: 'REST API from YAML file'
version: '1'
paths:
/hello_friend/greeting:
get:
tags:
- hello_friend
parameters:
- in: query
name: name
schema:
type: string
required: true
responses:
201:
description: 'Successful response'
content:
application/json:
schema:
type: 'object'
Documents 2 & 3: Commandable REST service
These two cases document the same commandable REST service. The difference between them is that the first automatically generates the Swagger UI based on a command set, and the second uses a YAML file.
Command set
To create a command set, we extend the CommandSet class and define our greeting command in it. The code below illustrates how to do this:
import {
Command, CommandSet, ICommand,
ObjectSchema, TypeCode, Parameters
} from 'pip-services3-commons-nodex';
class FriendsCommandSet extends CommandSet {
private _controller: HelloFriendController;
public constructor(controller: HelloFriendController) {
super();
this._controller = controller;
this.addCommand(this.makeGreeting());
}
private makeGreeting(): ICommand {
return new Command('greeeting',
new ObjectSchema(true).withRequiredProperty('name', TypeCode.String),
async (correlationId: string, args: Parameters) =>
{
let name = args.getAsString("name");
let res = this._controller.greeting(name);
return res;
}
);
}
}
using System;
using PipServices3.Commons.Commands;
using PipServices3.Commons.Validate;
using PipServices3.Commons.Run;
public class FriendsCommandSet: CommandSet
{
private HelloFriendController _controller;
public FriendsCommandSet(HelloFriendController controller) : base()
{
_controller = controller;
AddCommand(MakeGreeting());
}
private ICommand MakeGreeting()
{
return new Command("greeting",
new ObjectSchema().WithRequiredProperty("name", TypeCode.String),
(string correlationId, Parameters args) =>
{
var name = args.GetAsString("name");
var res = _controller.Greeting(name);
return res;
}
);
}
}
import (
crun "github.com/pip-services3-gox/pip-services3-commons-gox/run"
cvalid "github.com/pip-services3-gox/pip-services3-commons-gox/validate"
ccmd "github.com/pip-services3-gox/pip-services3-commons-gox/commands"
)
// Command set
type FriendsCommandSet struct {
*ccmd.CommandSet
controller *HelloFriendController
}
func NewFriendsCommandSet(controller *HelloFriendController) *FriendsCommandSet {
c := &FriendsCommandSet{
CommandSet: ccmd.NewCommandSet(),
controller: controller,
}
c.AddCommand(c.makeGreetingCommand())
return c
}
func (c *FriendsCommandSet) makeGreetingCommand() ccmd.ICommand {
return ccmd.NewCommand(
"greeting",
cvalid.NewObjectSchema().
WithRequiredProperty("name", cvalid.NewFilterParamsSchema()),
func(ctx context.Context, correllationId string, args *crun.Parameters) (result interface{}, err error) {
name := args.GetAsString("name")
return c.controller.Greeting(name), nil
})
}
import 'package:pip_services3_commons/pip_services3_commons.dart';
class FriendsCommandSet extends CommandSet {
HelloFriendController _controller;
FriendsCommandSet(HelloFriendController controller)
: _controller = controller,
super() {
addCommand(_makeGreeting());
}
ICommand _makeGreeting() {
return Command('greeting', null,
(String? correlationId, Parameters args) async {
var name = args.getAsString('name');
var res = _controller.greeting(name);
return res;
});
}
}
from pip_services3_commons.commands import Command, CommandSet, ICommand
from pip_services3_commons.run import Parameters
from pip_services3_commons.validate import Schema, ObjectSchema
from pip_services3_commons.convert import TypeCode
from typing import Optional
class FriendsCommandSet(CommandSet):
_controller: 'HelloFriendController'
def __init__(self, controller):
super().__init__()
self._controller = controller
self.add_command(self._make_greeting())
def _make_greeting(self) -> ICommand:
def handler(correlation_id: Optional[str], args: Parameters):
name = args.get_as_string("name")
res = self._controller.greeting(name)
return res
return Command(
"greeting",
ObjectSchema(True).with_required_property("name", TypeCode.String),
handler
)
Service for document 2
Once our command set has been defined, we create our commandable REST service by extending the CommandableHttpService class and we link it to our controller. This service checks for a YAML file in the configuration file. If not found, it builds the Swagger UI from the command set. In our example, the configuration file doesn’t include a path to a YAML file, and the Swagger UI is generated from the command set previously defined.
import { ConfigParams, Descriptor } from 'pip-services3-commons-nodex';
import { CommandableHttpService } from 'pip-services3-rpc-nodex';
class FriendCommandableHttpService1 extends CommandableHttpService {
private _swaggerPath: string;
public constructor() {
super("commandable_hello_friend1");
this._dependencyResolver.put('controller', new Descriptor("hello-friend", "controller", "*", "*", "*"));
}
public configure(config: ConfigParams): void {
super.configure(config);
// Swagger
this._swaggerPath = config.getAsNullableString("swagger.path");
}
public register(): void {
super.register();
if (this._swaggerPath != null)
this.registerOpenApiSpecFromFile(this._swaggerPath);
}
}
using PipServices3.Commons.Config;
using PipServices3.Commons.Refer;
using PipServices3.Rpc.Services;
public class FriendCommandableHttpService1: CommandableHttpService
{
private string _swaggerPath;
public FriendCommandableHttpService1(): base("commandable_hello_friend1")
{
_dependencyResolver.Put("controller", new Descriptor("hello-friend", "controller", "*", "*", "*"));
}
public override void Configure(ConfigParams config)
{
base.Configure(config);
// Swagger
_swaggerPath = config.GetAsNullableString("swagger.path");
}
public override void Register()
{
base.Register();
if (_swaggerPath != null)
RegisterOpenApiSpecFromFile(_swaggerPath);
}
}
import (
refer "github.com/pip-services3-gox/pip-services3-commons-gox/refer"
cservices "github.com/pip-services3-gox/pip-services3-rpc-gox/services"
cconf "github.com/pip-services3-gox/pip-services3-commons-gox/config"
)
type FriendCommandableHttpService1 struct {
*rpcservices.CommandableHttpService
_swaggerPath string
}
func NewFriendCommandableHttpService1() *FriendCommandableHttpService1 {
c := &FriendCommandableHttpService1{}
c.CommandableHttpService = rpcservices.InheritCommandableHttpService(c, "commandable_hello_friend1")
c.DependencyResolver.Put(context.Background(), "controller", crefer.NewDescriptor("hello-friend", "controller", "*", "*", "*"))
return c
}
func (c *FriendCommandableHttpService1) Configure(ctx context.Context, config *cconf.ConfigParams) {
c.RestService.Configure(ctx, config)
// swagger
c._swaggerPath, _ = config.GetAsNullableString("swagger.path")
}
func (c *FriendCommandableHttpService1) Register() {
c.CommandableHttpService.Register()
// swagger
if c._swaggerPath != "" {
c.RegisterOpenApiSpecFromFile(c._swaggerPath)
}
}
import 'package:pip_services3_commons/pip_services3_commons.dart';
import 'package:pip_services3_rpc/pip_services3_rpc.dart';
class FriendCommandableHttpService1 extends CommandableHttpService {
String? _swaggerPath;
FriendCommandableHttpService1() : super('commandable_hello_friend1') {
dependencyResolver.put(
'controller', Descriptor('hello-friend', 'controller', '*', '*', '*'));
}
@override
set config(ConfigParams? _config) {
super.config = _config;
// swagger
_swaggerPath = config?.getAsNullableString('swagger.path');
}
@override
void register() {
super.register();
if (_swaggerPath != null) registerOpenApiSpecFromFile(_swaggerPath!);
}
}
from pip_services3_rpc.services import CommandableHttpService
class FriendCommandableHttpService1(CommandableHttpService):
def __init__(self):
super().__init__('commandable_hello_friend1')
self._dependency_resolver.put('controller', Descriptor('hello-friend', 'controller', '*', '*', '*'))
self._swagger_path = None
def configure(self, config):
super().configure(config)
# Swagger
self._swagger_path = config.get_as_nullable_string('swagger.path')
def register(self):
super().register()
if self._swagger_path:
self._register_open_api_spec_from_file(self._swagger_path)
Configuration for document 2
To be able to generate a Swagger UI, we need to set the swagger’s enable field to true. Besides, as we want to document the commands defined in the command set, we declare auto as true and we define the route field that will be part of the URL for the generated Swagger UI. The example below shows this configuration.
- descriptor: "hello-friend:service:commandable-http1:default:1.0"
swagger:
enable: true
auto: true
route: swagger
name: Friends Service
description: Commandable REST API - Automatic
Service for document 3
Similar to the previous one, this service builds the Swagger UI from the YAML file defined in the configuration file.
import { ConfigParams, Descriptor } from 'pip-services3-commons-nodex';
import { CommandableHttpService } from 'pip-services3-rpc-nodex';
class FriendCommandableHttpService2 extends CommandableHttpService {
private _swaggerPath: string;
public constructor() {
super("commandable_hello_friend2");
this._dependencyResolver.put('controller', new Descriptor("hello-friend", "controller", "*", "*", "*"));
}
public configure(config: ConfigParams): void {
super.configure(config);
// Swagger
this._swaggerPath = config.getAsNullableString("swagger.path");
}
public register(): void {
super.register();
if (this._swaggerPath != null)
this.registerOpenApiSpecFromFile(this._swaggerPath);
}
}
using PipServices3.Rpc.Services;
public class FriendCommandableHttpService2 : CommandableHttpService
{
private string _swaggerPath;
public FriendCommandableHttpService2() : base("commandable_hello_friend2")
{
_dependencyResolver.Put("controller", new Descriptor("hello-friend", "controller", "*", "*", "*"));
}
public override void Configure(ConfigParams config)
{
base.Configure(config);
// Swagger
_swaggerPath = config.GetAsNullableString("swagger.path");
}
public override void Register()
{
base.Register();
if (_swaggerPath != null)
RegisterOpenApiSpecFromFile(_swaggerPath);
}
}
import (
refer "github.com/pip-services3-gox/pip-services3-commons-gox/refer"
cservices "github.com/pip-services3-gox/pip-services3-rpc-gox/services"
cconf "github.com/pip-services3-gox/pip-services3-commons-gox/config"
)
type FriendCommandableHttpService2 struct {
rpcservices.CommandableHttpService
_swaggerPath string
}
func NewFriendCommandableHttpService2() *FriendCommandableHttpService2 {
c := &FriendCommandableHttpService2{}
c.CommandableHttpService = *rpcservices.InheritCommandableHttpService(c, "commandable_hello_friend2")
c.DependencyResolver.Put(context.Background(), "controller", crefer.NewDescriptor("hello-friend", "controller", "*", "*", "*"))
return c
}
func (c *FriendCommandableHttpService2) Configure(ctx context.Context, config *cconf.ConfigParams) {
c.RestService.Configure(ctx, config)
// swagger
c._swaggerPath, _ = config.GetAsNullableString("swagger.path")
}
func (c *FriendCommandableHttpService2) Register() {
c.CommandableHttpService.Register()
// swagger
if c._swaggerPath != "" {
c.RegisterOpenApiSpecFromFile(c._swaggerPath)
}
}
import 'package:pip_services3_commons/pip_services3_commons.dart';
import 'package:pip_services3_rpc/pip_services3_rpc.dart';
class FriendCommandableHttpService2 extends CommandableHttpService {
String? _swaggerPath;
FriendCommandableHttpService2() : super('commandable_hello_friend2') {
dependencyResolver.put(
'controller', Descriptor('hello-friend', 'controller', '*', '*', '*'));
}
@override
set config(ConfigParams? _config) {
super.config = _config;
// swagger
_swaggerPath = config?.getAsNullableString('swagger.path');
}
@override
void register() {
super.register();
if (_swaggerPath != null) registerOpenApiSpecFromFile(_swaggerPath!);
}
}
from pip_services3_rpc.services import CommandableHttpService
class FriendCommandableHttpService2(CommandableHttpService):
def __init__(self):
super().__init__('commandable_hello_friend2')
self._dependency_resolver.put('controller', Descriptor('hello-friend', 'controller', '*', '*', '*'))
self._swagger_path = None
def configure(self, config):
super().configure(config)
# Swagger
self._swagger_path = config.get_as_nullable_string('swagger.path')
def register(self):
super().register()
if self._swagger_path:
self._register_open_api_spec_from_file(self._swagger_path)
Configuration for document 3
In this case, we declare a path to a YAML file containing the description for the Swagger UI. As a result, even though we have declared auto as true, the system will choose this file over the automatic generation.
- descriptor: "hello-friend:service:commandable-http2:default:1.0"
swagger:
enable: true
auto: false
route: swagger
path: './commandable_swagger.yml'
- descriptor: "hello-friend:service:commandable-http2:default:1.0"
swagger:
enable: true
auto: false
route: swagger
path: '../../../commandable_swagger.yml'
- descriptor: "hello-friend:service:commandable-http2:default:1.0"
swagger:
enable: true
auto: false
route: swagger
path: './commandable_swagger.yml'
- descriptor: "hello-friend:service:commandable-http2:default:1.0"
swagger:
enable: true
auto: false
route: swagger
path: './commandable_swagger.yml'
- descriptor: "hello-friend:service:commandable-http2:default:1.0"
swagger:
enable: true
auto: false
route: swagger
path: './commandable_swagger.yml'
Swagger yam file for document 3
Here, we use the YAML file below to describe the UI. As we can see, the main difference with the previous one is that we declare the HTTP method as POST instead of GET, and therefore, we define the requestBody as required.
openapi: '3.0.2'
info:
title: 'Friends Service'
description: 'Commandable REST API from YAM file'
version: '1'
paths:
/commandable_hello_friend/greeting:
post:
tags:
- commandable_hello_friend
requestBody:
required: true
description: Friend name
content:
application/json:
schema:
type: object
properties:
name:
type: string
responses:
201:
description: 'Successful response'
content:
application/json:
schema:
type: 'object'
Containerization
Now that our REST services are defined, we want to create a process container to run them. For this, we need to define our factory of components and a class extending ProcessContainer. The following sections explain how to do this.
Factory
To create our factory of components, we extend the Factory class and register our REST and commandable REST services.
import { Descriptor } from 'pip-services3-commons-nodex';
import { Factory } from 'pip-services3-components-nodex';
class HelloFriendServiceFactory extends Factory {
public constructor()
{
super();
let HttpServiceDescriptor = new Descriptor("hello-friend", "service", "http", "*", "1.0"); // View 1
let CommandableHttpServiceDescriptor1 = new Descriptor("hello-friend", "service", "commandable-http1", "*", "1.0"); // View 2
let CommandableHttpServiceDescriptor2 = new Descriptor("hello-friend", "service", "commandable-http2", "*", "1.0"); // View 2
let ControllerDescriptor = new Descriptor("hello-friend", "controller", "default", "*", "1.0"); // Controller
this.registerAsType(HttpServiceDescriptor, HelloFriendRestService); // View 1
this.registerAsType(CommandableHttpServiceDescriptor1, FriendCommandableHttpService1); // View 2
this.registerAsType(CommandableHttpServiceDescriptor2, FriendCommandableHttpService2); // View 3
this.registerAsType(ControllerDescriptor, HelloFriendController); // Controller
}
}
using PipServices3.Components.Build;
using PipServices3.Commons.Refer;
public class HelloFriendServiceFactory: Factory
{
public HelloFriendServiceFactory(): base()
{
var HttpServiceDescriptor = new Descriptor("hello-friend", "service", "http", "*", "1.0"); // View 1
var CommandableHttpServiceDescriptor1 = new Descriptor("hello-friend", "service", "commandable-http1", "*", "1.0"); // View 2
var CommandableHttpServiceDescriptor2 = new Descriptor("hello-friend", "service", "commandable-http2", "*", "1.0"); // View 2
var ControllerDescriptor = new Descriptor("hello-friend", "controller", "default", "*", "1.0"); // Controller
RegisterAsType(HttpServiceDescriptor, typeof(HelloFriendRestService)); // View 1
RegisterAsType(CommandableHttpServiceDescriptor1, typeof(FriendCommandableHttpService1)); // View 2
RegisterAsType(CommandableHttpServiceDescriptor2, typeof(FriendCommandableHttpService2)); // View 3
RegisterAsType(ControllerDescriptor, typeof(HelloFriendController)); // Controller
}
}
import (
cbuild "github.com/pip-services3-gox/pip-services3-components-gox/build"
cref "github.com/pip-services3-gox/pip-services3-commons-gox/refer"
)
type HelloFriendServiceFactory struct {
*cbuild.Factory
}
func NewHelloFriendServiceFactory() *HelloFriendServiceFactory {
c := &HelloFriendServiceFactory{
Factory: cbuild.NewFactory(),
}
HttpServiceDescriptor := crefer.NewDescriptor("hello-friend", "service", "http", "*", "1.0") // View 1
CommandableHttpServiceDescriptor1 := crefer.NewDescriptor("hello-friend", "service", "commandable-http1", "*", "1.0") // View 2
CommandableHttpServiceDescriptor2 := crefer.NewDescriptor("hello-friend", "service", "commandable-http2", "*", "1.0") // View 2
ControllerDescriptor := crefer.NewDescriptor("hello-friend", "controller", "default", "*", "1.0") // Controller
c.RegisterType(HttpServiceDescriptor, NewHelloFriendRestService) // View 1
c.RegisterType(CommandableHttpServiceDescriptor1, NewFriendCommandableHttpService1) // View 2
c.RegisterType(CommandableHttpServiceDescriptor2, NewFriendCommandableHttpService2) // View 3
c.RegisterType(ControllerDescriptor, NewHelloFriendController) // Controller
return c
}
import 'package:pip_services3_commons/pip_services3_commons.dart';
import 'package:pip_services3_components/pip_services3_components.dart';
class HelloFriendServiceFactory extends Factory {
HelloFriendServiceFactory() : super() {
var HttpServiceDescriptor =
Descriptor('hello-friend', 'service', 'http', '*', '1.0'); // View 1
var CommandableHttpServiceDescriptor1 = Descriptor(
'hello-friend', 'service', 'commandable-http1', '*', '1.0'); // View 2
var CommandableHttpServiceDescriptor2 = Descriptor(
'hello-friend', 'service', 'commandable-http2', '*', '1.0'); // View 2
var ControllerDescriptor = Descriptor(
'hello-friend', 'controller', 'default', '*', '1.0'); // Controller
registerAsType(HttpServiceDescriptor, HelloFriendRestService); // View 1
registerAsType(CommandableHttpServiceDescriptor1,
FriendCommandableHttpService1); // View 2
registerAsType(CommandableHttpServiceDescriptor2,
FriendCommandableHttpService2); // View 3
registerAsType(ControllerDescriptor, HelloFriendController); // Controller
}
}
from pip_services3_commons.refer import Descriptor
from pip_services3_components.build import Factory
class HelloFriendServiceFactory(Factory):
def __init__(self):
super(HelloFriendServiceFactory, self).__init__()
HttpServiceDescriptor = Descriptor('hello-friend', 'service', 'http', '*', '1.0') # View 1
CommandableHttpServiceDescriptor1 = Descriptor('hello-friend', 'service', 'commandable-http1', '*', '1.0') # View 2
CommandableHttpServiceDescriptor2 = Descriptor('hello-friend', 'service', 'commandable-http2', '*', '1.0') # View 2
ControllerDescriptor = Descriptor('hello-friend', 'controller', 'default', '*', '1.0') # Controller
self.register_as_type(HttpServiceDescriptor, HelloFriendRestService) # View 1
self.register_as_type(CommandableHttpServiceDescriptor1, FriendCommandableHttpService1) # View 2
self.register_as_type(CommandableHttpServiceDescriptor2, FriendCommandableHttpService2) # View 3
self.register_as_type(ControllerDescriptor, HelloFriendController) # Controller
Process container
Once we have our factory, we define our process container by extending the ProcessContainer class and adding the factories for the services and Swagger. Our code will look something like this:
import { DefaultSwaggerFactory } from 'pip-services3-swagger-nodex';
import { DefaultRpcFactory } from 'pip-services3-rpc-nodex';
import { ProcessContainer } from 'pip-services3-container-nodex';
class HelloFriendProcess extends ProcessContainer {
public constructor() {
super("hello-friend", "HelloFriend microservice");
this._configPath = "./config.yml";
this._factories.add(new HelloFriendServiceFactory());
this._factories.add(new DefaultRpcFactory());
this._factories.add(new DefaultSwaggerFactory());
}
}
using PipServices3.Container;
using PipServices3.Rpc.Build;
using PipServices3.Swagger.Build;
public class HelloFriendProcess : ProcessContainer
{
public HelloFriendProcess() : base("hello-friend", "HelloFriend microservice")
{
_configPath = "../../../config.yml";
_factories.Add(new HelloFriendServiceFactory());
_factories.Add(new DefaultRpcFactory());
_factories.Add(new DefaultSwaggerFactory());
}
}
import (
cproc "github.com/pip-services3-gox/pip-services3-container-gox/container"
rbuild "github.com/pip-services3-gox/pip-services3-rpc-gox/build"
sbuild "github.com/pip-services3-gox/pip-services3-swagger-gox/build"
)
type HelloFriendProcess struct {
*cproc.ProcessContainer
}
func NewHelloFriendProcess() *HelloFriendProcess {
c := &HelloFriendProcess{
ProcessContainer: cproc.NewProcessContainer("hello-friend", "HelloFriend microservice"),
}
c.SetConfigPath("./config.yml")
c.AddFactory(NewHelloFriendServiceFactory())
c.AddFactory(rbuild.NewDefaultRpcFactory())
c.AddFactory(cswagger.NewDefaultSwaggerFactory())
return c
}
import 'package:pip_services3_container/pip_services3_container.dart';
import 'package:pip_services3_rpc/pip_services3_rpc.dart';
import 'package:pip_services3_swagger/pip_services3_swagger.dart';
class HelloFriendProcess extends ProcessContainer {
HelloFriendProcess() : super('hello-friend', 'HelloFriend microservice') {
configPath = './config.yml';
factories.add(HelloFriendServiceFactory());
factories.add(DefaultRpcFactory());
factories.add(DefaultSwaggerFactory());
}
}
from pip_services3_container.ProcessContainer import ProcessContainer
from pip_services3_rpc.build import DefaultRpcFactory
from pip_services3_swagger.build.DefaultSwaggerFactory import DefaultSwaggerFactory
class HelloFriendProcess(ProcessContainer):
def __init__(self):
super(HelloFriendProcess, self).__init__('hello-friend', 'HelloFriend microservice')
self._config_path = './configV6.yml'
self._factories.add(HelloFriendServiceFactory())
self._factories.add(DefaultRpcFactory())
self._factories.add(DefaultSwaggerFactory())
Runner
After our components are defined, we can run our app by invoking the run method from our process container.
export async function main() {
try {
let proc = new HelloFriendProcess();
proc.run(process.argv);
} catch (ex) {
console.error(ex);
}
}
class Program
{
static void Main(string[] args)
{
try
{
var task = (new HelloFriendProcess()).RunAsync(args);
task.Wait();
}
catch (Exception ex)
{
Console.Error.WriteLine(ex);
}
}
}
import (
"os"
)
func main() {
proc := NewHelloFriendProcess()
proc.Run(context.Background(), os.Environ())
}
void main(List<String> argument) {
try {
var proc = HelloFriendProcess();
proc.run(argument);
} catch (ex) {
print(ex);
}
}
if __name__ == '__main__':
runner = HelloFriendProcess()
print("run")
try:
runner.run()
except Exception as ex:
print(ex)
And, after executing our code, we will see the following messages on our console:
Results
To see the generated Swagger UIs, we can use the following URL:
http://localhost:8080/swagger/index.html
General Interface
The generated Swagger UI presents a drop-down menu that can be used to select any of the cases defined in this exercise.
Document 1: REST service
If we select the hello_friend option, we will see a UI that presents all the information defined in the Swagger YAML file.
Document 2: Commandable REST service
Alternatively, if we choose the commandable_hello_friend1 option, we will be presented by a UI showing the information automatically generated from the command set.
Document 3: Commandable REST service.
Finally, if we select commandable_hello_friend2, we get a similar UI but generated from our YAML file.
Final code
In this section, we show the complete code and the corresponding configuration YAML file.
swagger.py
Code Example
import {
Command, CommandSet, ConfigParams,
Descriptor, ICommand, IReferences,
ObjectSchema, TypeCode, Parameters, ICommandable, IConfigurable
} from 'pip-services3-commons-nodex';
import { CommandableHttpService, DefaultRpcFactory, RestService } from 'pip-services3-rpc-nodex';
import { DefaultSwaggerFactory } from 'pip-services3-swagger-nodex';
import { ProcessContainer } from 'pip-services3-container-nodex';
import { Factory } from 'pip-services3-components-nodex';
export async function main() {
// Runner
try {
let proc = new HelloFriendProcess();
proc.run(process.argv);
} catch (ex) {
console.error(ex);
}
}
// REST service (Swagger UI from YAML file)
class HelloFriendRestService extends RestService {
private _controller: HelloFriendController;
// swagger
private _swaggerContent: string;
private _swaggerPath: string;
public constructor() {
super();
this._baseRoute = "/hello_friend";
let controllerDescriptor = new Descriptor("hello-friend", "controller", "*", "*", "1.0");
this._dependencyResolver.put("controller", controllerDescriptor);
}
public configure(config: ConfigParams): void {
super.configure(config);
// swagger
this._swaggerContent = config.getAsNullableString("swagger.content");
this._swaggerPath = config.getAsNullableString("swagger.path");
}
public setReferences(references: IReferences) {
super.setReferences(references);
this._controller = this._dependencyResolver.getOneRequired<HelloFriendController>("controller");
}
public register(): void {
this.registerRoute("GET", "/greeting", null, this.greeting);
// swagger
if (this._swaggerContent != null)
this.registerOpenApiSpec(this._swaggerContent);
if (this._swaggerPath != null)
this.registerOpenApiSpecFromFile(this._swaggerPath);
}
public async greeting(req: any, res: any): Promise<void> {
let name = req.query.name;
let result = this._controller.greeting(name);
this.sendResult(req, res, result);
}
}
// Command set
class FriendsCommandSet extends CommandSet {
private _controller: HelloFriendController;
public constructor(controller: HelloFriendController) {
super();
this._controller = controller;
this.addCommand(this.makeGreeting());
}
private makeGreeting(): ICommand {
return new Command('greeeting',
new ObjectSchema(true).withRequiredProperty('name', TypeCode.String),
async (correlationId: string, args: Parameters) =>
{
let name = args.getAsString("name");
let res = this._controller.greeting(name);
return res;
}
);
}
}
// Commandable REST service (Swagger UI automatically generated from command set)
class FriendCommandableHttpService1 extends CommandableHttpService {
private _swaggerPath: string;
public constructor() {
super("commandable_hello_friend1");
this._dependencyResolver.put('controller', new Descriptor("hello-friend", "controller", "*", "*", "*"));
}
public configure(config: ConfigParams): void {
super.configure(config);
// Swagger
this._swaggerPath = config.getAsNullableString("swagger.path");
}
public register(): void {
super.register();
if (this._swaggerPath != null)
this.registerOpenApiSpecFromFile(this._swaggerPath);
}
}
// Commandable REST service (Swagger UI generated from YAML file)
class FriendCommandableHttpService2 extends CommandableHttpService {
private _swaggerPath: string;
public constructor() {
super("commandable_hello_friend2");
this._dependencyResolver.put('controller', new Descriptor("hello-friend", "controller", "*", "*", "*"));
}
public configure(config: ConfigParams): void {
super.configure(config);
// Swagger
this._swaggerPath = config.getAsNullableString("swagger.path");
}
public register(): void {
super.register();
if (this._swaggerPath != null)
this.registerOpenApiSpecFromFile(this._swaggerPath);
}
}
// Controller
class HelloFriendController implements IConfigurable, ICommandable {
private defaultName: string;
private commandSet: FriendsCommandSet;
public constructor() {
this.defaultName = "Pip User";
}
public configure(config: ConfigParams): void {
this.defaultName = config.getAsStringWithDefault("default_name", this.defaultName);
}
public getCommandSet(): CommandSet {
if (this.commandSet == null)
this.commandSet = new FriendsCommandSet(this);
return this.commandSet;
}
public greeting(name: string): string {
return "Hello " + name ?? this.defaultName + " !";
}
}
// Factory
class HelloFriendServiceFactory extends Factory {
public constructor()
{
super();
let HttpServiceDescriptor = new Descriptor("hello-friend", "service", "http", "*", "1.0"); // View 1
let CommandableHttpServiceDescriptor1 = new Descriptor("hello-friend", "service", "commandable-http1", "*", "1.0"); // View 2
let CommandableHttpServiceDescriptor2 = new Descriptor("hello-friend", "service", "commandable-http2", "*", "1.0"); // View 2
let ControllerDescriptor = new Descriptor("hello-friend", "controller", "default", "*", "1.0"); // Controller
this.registerAsType(HttpServiceDescriptor, HelloFriendRestService); // View 1
this.registerAsType(CommandableHttpServiceDescriptor1, FriendCommandableHttpService1); // View 2
this.registerAsType(CommandableHttpServiceDescriptor2, FriendCommandableHttpService2); // View 3
this.registerAsType(ControllerDescriptor, HelloFriendController); // Controller
}
}
// Container
class HelloFriendProcess extends ProcessContainer {
public constructor() {
super("hello-friend", "HelloFriend microservice");
this._configPath = "./config.yml";
this._factories.add(new HelloFriendServiceFactory());
this._factories.add(new DefaultRpcFactory());
this._factories.add(new DefaultSwaggerFactory());
}
}
Code Example
using System;
using System.Threading.Tasks;
using PipServices3.Commons.Config;
using PipServices3.Commons.Refer;
using PipServices3.Rpc.Services;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using PipServices3.Commons.Commands;
using PipServices3.Commons.Validate;
using PipServices3.Commons.Run;
using PipServices3.Components.Build;
using PipServices3.Container;
using PipServices3.Rpc.Build;
using PipServices3.Swagger.Build;
namespace ExampleApp
{
class Program
{
static void Main(string[] args)
{
// Runner
try
{
var task = (new HelloFriendProcess()).RunAsync(args);
task.Wait();
}
catch (Exception ex)
{
Console.Error.WriteLine(ex);
}
}
}
// REST service (Swagger UI from YAML file)
public class HelloFriendRestService: RestService
{
private HelloFriendController _controller;
// swagger
private string _swaggerContent;
private string _swaggerPath;
public HelloFriendRestService(): base()
{
_baseRoute = "/hello_friend";
var controllerDescriptor = new Descriptor("hello-friend", "controller", "*", "*", "1.0");
_dependencyResolver.Put("controller", controllerDescriptor);
}
public override void Configure(ConfigParams config)
{
base.Configure(config);
// swagger
_swaggerContent = config.GetAsNullableString("swagger.content");
_swaggerPath = config.GetAsNullableString("swagger.path");
}
public override void SetReferences(IReferences references)
{
base.SetReferences(references);
_controller = _dependencyResolver.GetOneRequired<HelloFriendController>("controller");
}
public override void Register()
{
RegisterRoute("GET", "/greeting", this.Greeting);
// swagger
if (_swaggerContent != null)
RegisterOpenApiSpec(_swaggerContent);
if (_swaggerPath != null)
RegisterOpenApiSpecFromFile(_swaggerPath);
}
public async Task Greeting(HttpRequest req, HttpResponse res, RouteData routeData)
{
var name = req.Query["name"];
var result = _controller.Greeting(name);
await SendResultAsync(res, result);
}
}
// Command set
public class FriendsCommandSet : CommandSet
{
private HelloFriendController _controller;
public FriendsCommandSet(HelloFriendController controller) : base()
{
_controller = controller;
AddCommand(MakeGreeting());
}
private ICommand MakeGreeting()
{
return new Command("greeting",
new ObjectSchema().WithRequiredProperty("name", TypeCode.String),
async (string correlationId, Parameters args) =>
{
var name = args.GetAsString("name");
var res = _controller.Greeting(name);
return res;
}
);
}
}
// Commandable REST service (Swagger UI automatically generated from command set)
public class FriendCommandableHttpService1 : CommandableHttpService
{
private string _swaggerPath;
public FriendCommandableHttpService1() : base("commandable_hello_friend1")
{
_dependencyResolver.Put("controller", new Descriptor("hello-friend", "controller", "*", "*", "*"));
}
public override void Configure(ConfigParams config)
{
base.Configure(config);
// Swagger
_swaggerPath = config.GetAsNullableString("swagger.path");
}
public override void Register()
{
base.Register();
if (_swaggerPath != null)
RegisterOpenApiSpecFromFile(_swaggerPath);
}
}
// Commandable REST service (Swagger UI generated from YAML file)
public class FriendCommandableHttpService2 : CommandableHttpService
{
private string _swaggerPath;
public FriendCommandableHttpService2() : base("commandable_hello_friend2")
{
_dependencyResolver.Put("controller", new Descriptor("hello-friend", "controller", "*", "*", "*"));
}
public override void Configure(ConfigParams config)
{
base.Configure(config);
// Swagger
_swaggerPath = config.GetAsNullableString("swagger.path");
}
public override void Register()
{
base.Register();
if (_swaggerPath != null)
RegisterOpenApiSpecFromFile(_swaggerPath);
}
}
// Controller
public class HelloFriendController : IConfigurable, ICommandable
{
private string defaultName;
private FriendsCommandSet commandSet;
public HelloFriendController()
{
defaultName = "Pip User";
}
public void Configure(ConfigParams config)
{
defaultName = config.GetAsStringWithDefault("default_name", defaultName);
}
public CommandSet GetCommandSet()
{
if (commandSet == null)
commandSet = new FriendsCommandSet(this);
return commandSet;
}
public string Greeting(string name)
{
return "Hello " + name ?? defaultName + " !";
}
}
// Factory
public class HelloFriendServiceFactory : Factory
{
public HelloFriendServiceFactory() : base()
{
var HttpServiceDescriptor = new Descriptor("hello-friend", "service", "http", "*", "1.0"); // View 1
var CommandableHttpServiceDescriptor1 = new Descriptor("hello-friend", "service", "commandable-http1", "*", "1.0"); // View 2
var CommandableHttpServiceDescriptor2 = new Descriptor("hello-friend", "service", "commandable-http2", "*", "1.0"); // View 2
var ControllerDescriptor = new Descriptor("hello-friend", "controller", "default", "*", "1.0"); // Controller
RegisterAsType(HttpServiceDescriptor, typeof(HelloFriendRestService)); // View 1
RegisterAsType(CommandableHttpServiceDescriptor1, typeof(FriendCommandableHttpService1)); // View 2
RegisterAsType(CommandableHttpServiceDescriptor2, typeof(FriendCommandableHttpService2)); // View 3
RegisterAsType(ControllerDescriptor, typeof(HelloFriendController)); // Controller
}
}
// Container
public class HelloFriendProcess : ProcessContainer
{
public HelloFriendProcess() : base("hello-friend", "HelloFriend microservice")
{
_configPath = "../../../config.yml";
_factories.Add(new HelloFriendServiceFactory());
_factories.Add(new DefaultRpcFactory());
_factories.Add(new DefaultSwaggerFactory());
}
}
}
Code Example
package main
import (
"context"
"net/http"
"os"
ccmd "github.com/pip-services3-gox/pip-services3-commons-gox/commands"
cconf "github.com/pip-services3-gox/pip-services3-commons-gox/config"
crefer "github.com/pip-services3-gox/pip-services3-commons-gox/refer"
crun "github.com/pip-services3-gox/pip-services3-commons-gox/run"
cvalid "github.com/pip-services3-gox/pip-services3-commons-gox/validate"
cbuild "github.com/pip-services3-gox/pip-services3-components-gox/build"
cproc "github.com/pip-services3-gox/pip-services3-container-gox/container"
rbuild "github.com/pip-services3-gox/pip-services3-rpc-gox/build"
rpcservices "github.com/pip-services3-gox/pip-services3-rpc-gox/services"
cswagger "github.com/pip-services3-gox/pip-services3-swagger-gox/build"
)
// Runner
func main() {
proc := NewHelloFriendProcess()
proc.Run(context.Background(), os.Environ())
}
// REST service (Swagger UI from YAML file)
type HelloFriendRestService struct {
*rpcservices.RestService
_swaggerContent string
_swaggerPath string
_controller *HelloFriendController
}
func NewHelloFriendRestService() *HelloFriendRestService {
c := &HelloFriendRestService{}
c.RestService = rpcservices.InheritRestService(c)
c.BaseRoute = "/hello_friend"
controllerDescriptor := crefer.NewDescriptor("hello-friend", "controller", "*", "*", "1.0")
c.DependencyResolver.Put(context.Background(), "controller", controllerDescriptor)
return c
}
func (c *HelloFriendRestService) Configure(ctx context.Context, config *cconf.ConfigParams) {
c.RestService.Configure(context.Background(), config)
// swagger
c._swaggerContent, _ = config.GetAsNullableString("swagger.content")
c._swaggerPath, _ = config.GetAsNullableString("swagger.path")
}
func (c *HelloFriendRestService) SetReferences(ctx context.Context, references crefer.IReferences) {
c.RestService.SetReferences(ctx, references)
depRes, depErr := c.DependencyResolver.GetOneRequired("controller")
if depErr == nil && depRes != nil {
c._controller = depRes.(*HelloFriendController)
}
}
func (c *HelloFriendRestService) greeting(res http.ResponseWriter, req *http.Request) {
// vars := mux.Vars(req)
name := req.URL.Query().Get("message")
// message := vars["name"]
result := c._controller.Greeting(name)
c.SendResult(res, req, result, nil)
}
func (c *HelloFriendRestService) Register() {
c.RegisterRoute("GET", "/greeting", nil, c.greeting)
// swagger
if c._swaggerContent != "" {
c.RegisterOpenApiSpec(c._swaggerContent)
}
if c._swaggerPath != "" {
c.RegisterOpenApiSpecFromFile(c._swaggerPath)
}
}
// Command set
type FriendsCommandSet struct {
*ccmd.CommandSet
controller *HelloFriendController
}
func NewFriendsCommandSet(controller *HelloFriendController) *FriendsCommandSet {
c := &FriendsCommandSet{
CommandSet: ccmd.NewCommandSet(),
controller: controller,
}
c.AddCommand(c.makeGreetingCommand())
return c
}
func (c *FriendsCommandSet) makeGreetingCommand() ccmd.ICommand {
return ccmd.NewCommand(
"greeting",
cvalid.NewObjectSchema().
WithRequiredProperty("name", cvalid.NewFilterParamsSchema()),
func(ctx context.Context, correllationId string, args *crun.Parameters) (result interface{}, err error) {
name := args.GetAsString("name")
return c.controller.Greeting(name), nil
})
}
// Commandable REST service (Swagger UI automatically generated from command set)
type FriendCommandableHttpService1 struct {
*rpcservices.CommandableHttpService
_swaggerPath string
}
func NewFriendCommandableHttpService1() *FriendCommandableHttpService1 {
c := &FriendCommandableHttpService1{}
c.CommandableHttpService = rpcservices.InheritCommandableHttpService(c, "commandable_hello_friend1")
c.DependencyResolver.Put(context.Background(), "controller", crefer.NewDescriptor("hello-friend", "controller", "*", "*", "*"))
return c
}
func (c *FriendCommandableHttpService1) Configure(ctx context.Context, config *cconf.ConfigParams) {
c.RestService.Configure(ctx, config)
// swagger
c._swaggerPath, _ = config.GetAsNullableString("swagger.path")
}
func (c *FriendCommandableHttpService1) Register() {
c.CommandableHttpService.Register()
// swagger
if c._swaggerPath != "" {
c.RegisterOpenApiSpecFromFile(c._swaggerPath)
}
}
// Commandable REST service (Swagger UI generated from YAML file)
type FriendCommandableHttpService2 struct {
rpcservices.CommandableHttpService
_swaggerPath string
}
func NewFriendCommandableHttpService2() *FriendCommandableHttpService2 {
c := &FriendCommandableHttpService2{}
c.CommandableHttpService = *rpcservices.InheritCommandableHttpService(c, "commandable_hello_friend2")
c.DependencyResolver.Put(context.Background(), "controller", crefer.NewDescriptor("hello-friend", "controller", "*", "*", "*"))
return c
}
func (c *FriendCommandableHttpService2) Configure(ctx context.Context, config *cconf.ConfigParams) {
c.RestService.Configure(ctx, config)
// swagger
c._swaggerPath, _ = config.GetAsNullableString("swagger.path")
}
func (c *FriendCommandableHttpService2) Register() {
c.CommandableHttpService.Register()
// swagger
if c._swaggerPath != "" {
c.RegisterOpenApiSpecFromFile(c._swaggerPath)
}
}
// Controller
type HelloFriendController struct {
commandSet *FriendsCommandSet
defaultName string
}
func NewHelloFriendController() *HelloFriendController {
c := &HelloFriendController{defaultName: "Pip User"}
return c
}
func (c *HelloFriendController) Configure(config *cconf.ConfigParams) {
c.defaultName = config.GetAsStringWithDefault("default_name", c.defaultName)
}
func (c *HelloFriendController) GetCommandSet() *ccmd.CommandSet {
if c.commandSet == nil {
c.commandSet = NewFriendsCommandSet(c)
}
return c.commandSet.CommandSet
}
func (c *HelloFriendController) Greeting(name string) string {
if name != "" {
return "Hello " + name + " !"
} else {
return "Hello " + c.defaultName + " !"
}
}
// Factory
type HelloFriendServiceFactory struct {
*cbuild.Factory
}
func NewHelloFriendServiceFactory() *HelloFriendServiceFactory {
c := &HelloFriendServiceFactory{
Factory: cbuild.NewFactory(),
}
HttpServiceDescriptor := crefer.NewDescriptor("hello-friend", "service", "http", "*", "1.0") // View 1
CommandableHttpServiceDescriptor1 := crefer.NewDescriptor("hello-friend", "service", "commandable-http1", "*", "1.0") // View 2
CommandableHttpServiceDescriptor2 := crefer.NewDescriptor("hello-friend", "service", "commandable-http2", "*", "1.0") // View 2
ControllerDescriptor := crefer.NewDescriptor("hello-friend", "controller", "default", "*", "1.0") // Controller
c.RegisterType(HttpServiceDescriptor, NewHelloFriendRestService) // View 1
c.RegisterType(CommandableHttpServiceDescriptor1, NewFriendCommandableHttpService1) // View 2
c.RegisterType(CommandableHttpServiceDescriptor2, NewFriendCommandableHttpService2) // View 3
c.RegisterType(ControllerDescriptor, NewHelloFriendController) // Controller
return c
}
// Container
type HelloFriendProcess struct {
*cproc.ProcessContainer
}
func NewHelloFriendProcess() *HelloFriendProcess {
c := &HelloFriendProcess{
ProcessContainer: cproc.NewProcessContainer("hello-friend", "HelloFriend microservice"),
}
c.SetConfigPath("./config.yml")
c.AddFactory(NewHelloFriendServiceFactory())
c.AddFactory(rbuild.NewDefaultRpcFactory())
c.AddFactory(cswagger.NewDefaultSwaggerFactory())
return c
}
Code Example
import 'dart:async';
import 'package:pip_services3_commons/pip_services3_commons.dart';
import 'package:pip_services3_components/pip_services3_components.dart';
import 'package:pip_services3_container/pip_services3_container.dart';
import 'package:pip_services3_rpc/pip_services3_rpc.dart';
import 'package:pip_services3_swagger/pip_services3_swagger.dart';
import 'package:shelf/shelf.dart';
import 'package:shelf_router/shelf_router.dart';
void main(List<String> argument) {
// Runner
try {
var proc = HelloFriendProcess();
proc.run(argument);
} catch (ex) {
print(ex);
}
}
// REST service (Swagger UI from YAML file)
class HelloFriendRestService extends RestService {
HelloFriendController? _controller;
String? _swaggerContent;
String? _swaggerPath;
HelloFriendRestService() : super() {
baseRoute = '/hello_friend';
var controllerDescriptor =
Descriptor('hello-friend', 'controller', '*', '*', '1.0');
dependencyResolver.put('controller', controllerDescriptor);
}
@override
void configure(ConfigParams config) {
super.configure(config);
// swagger
_swaggerContent = config.getAsNullableString('swagger.content');
_swaggerPath = config.getAsNullableString('swagger.path');
}
@override
void setReferences(IReferences references) {
super.setReferences(references);
_controller =
dependencyResolver.getOneRequired<HelloFriendController>('controller');
}
@override
void register() {
registerRoute('get', '/greeting', null, _greeting);
// swagger
if (_swaggerContent != null) {
registerOpenApiSpec_(_swaggerContent!);
}
if (_swaggerPath != null) {
registerOpenApiSpecFromFile(_swaggerPath!);
}
}
FutureOr<Response> _greeting(Request req) {
var name = req.params['name'];
var result = _controller!.greeting(name);
return sendResult(req, result);
}
}
// Command set
class FriendsCommandSet extends CommandSet {
HelloFriendController _controller;
FriendsCommandSet(HelloFriendController controller)
: _controller = controller,
super() {
addCommand(_makeGreeting());
}
ICommand _makeGreeting() {
return Command('greeting', null,
(String? correlationId, Parameters args) async {
var name = args.getAsString('name');
var res = _controller.greeting(name);
return res;
});
}
}
// Commandable REST service (Swagger UI automatically generated from command set)
class FriendCommandableHttpService1 extends CommandableHttpService {
String? _swaggerPath;
FriendCommandableHttpService1() : super('commandable_hello_friend1') {
dependencyResolver.put(
'controller', Descriptor('hello-friend', 'controller', '*', '*', '*'));
}
@override
set config(ConfigParams? _config) {
super.config = _config;
// swagger
_swaggerPath = config?.getAsNullableString('swagger.path');
}
@override
void register() {
super.register();
if (_swaggerPath != null) registerOpenApiSpecFromFile(_swaggerPath!);
}
}
// Commandable REST service (Swagger UI generated from YAML file)
class FriendCommandableHttpService2 extends CommandableHttpService {
String? _swaggerPath;
FriendCommandableHttpService2() : super('commandable_hello_friend2') {
dependencyResolver.put(
'controller', Descriptor('hello-friend', 'controller', '*', '*', '*'));
}
@override
set config(ConfigParams? _config) {
super.config = _config;
// swagger
_swaggerPath = config?.getAsNullableString('swagger.path');
}
@override
void register() {
super.register();
if (_swaggerPath != null) registerOpenApiSpecFromFile(_swaggerPath!);
}
}
// Controller
class HelloFriendController implements IConfigurable, ICommandable {
String defaultName;
FriendsCommandSet? commandSet;
HelloFriendController() : defaultName = 'Pip User';
@override
void configure(ConfigParams config) {
defaultName = config.getAsStringWithDefault('default_name', defaultName);
}
@override
CommandSet getCommandSet() {
if (commandSet == null) commandSet = FriendsCommandSet(this);
return commandSet!;
}
String greeting(String? name) {
return 'Hello ' + (name ?? defaultName) + ' !';
}
}
// Factory
class HelloFriendServiceFactory extends Factory {
HelloFriendServiceFactory() : super() {
var HttpServiceDescriptor =
Descriptor('hello-friend', 'service', 'http', '*', '1.0'); // View 1
var CommandableHttpServiceDescriptor1 = Descriptor(
'hello-friend', 'service', 'commandable-http1', '*', '1.0'); // View 2
var CommandableHttpServiceDescriptor2 = Descriptor(
'hello-friend', 'service', 'commandable-http2', '*', '1.0'); // View 2
var ControllerDescriptor = Descriptor(
'hello-friend', 'controller', 'default', '*', '1.0'); // Controller
registerAsType(HttpServiceDescriptor, HelloFriendRestService); // View 1
registerAsType(CommandableHttpServiceDescriptor1,
FriendCommandableHttpService1); // View 2
registerAsType(CommandableHttpServiceDescriptor2,
FriendCommandableHttpService2); // View 3
registerAsType(ControllerDescriptor, HelloFriendController); // Controller
}
}
// Container
class HelloFriendProcess extends ProcessContainer {
HelloFriendProcess() : super('hello-friend', 'HelloFriend microservice') {
configPath = './config.yml';
factories.add(HelloFriendServiceFactory());
factories.add(DefaultRpcFactory());
factories.add(DefaultSwaggerFactory());
}
}
Code Example
from pip_services3_commons.refer import Descriptor
from pip_services3_commons.validate import Schema
from pip_services3_rpc.services import RestService
import bottle
# REST service (Swagger UI from YAML file)
class HelloFriendRestService(RestService):
def __init__(self):
super(HelloFriendRestService, self).__init__()
self._base_route = "/hello_friend"
ControllerDescriptor = Descriptor('hello-friend', 'controller', '*', '*', '1.0')
self._dependency_resolver.put('controller', ControllerDescriptor)
self._controller = None
# Swagger
self._swagger_content = None
self._swagger_path = None
def configure(self, config):
super().configure(config)
# Swagger
self._swagger_content = config.get_as_nullable_string("swagger.content")
self._swagger_path = config.get_as_nullable_string('swagger.path')
def set_references(self, references):
super(HelloFriendRestService, self).set_references(references)
self._controller = self._dependency_resolver.get_one_required('controller')
def register(self):
self.register_route(method="GET", route="/greeting", schema=Schema(), handler=self.greeting)
# Swagger
if self._swagger_content:
self._register_open_api_spec(self._swagger_content)
if self._swagger_path:
self._register_open_api_spec_from_file(self._swagger_path)
def greeting(self):
name = bottle.request.query.get('name')
result = self._controller.greeting(name)
return self.send_result(result)
# Command set
from pip_services3_commons.commands import Command, CommandSet, ICommand
from pip_services3_commons.run import Parameters
from pip_services3_commons.validate import Schema, ObjectSchema
from pip_services3_commons.convert import TypeCode
from typing import Optional
class FriendsCommandSet(CommandSet):
_controller: 'HelloFriendController'
def __init__(self, controller):
super().__init__()
self._controller = controller
self.add_command(self._make_greeting())
def _make_greeting(self) -> ICommand:
def handler(correlation_id: Optional[str], args: Parameters):
name = args.get_as_string("name")
res = self._controller.greeting(name)
return res
return Command(
"greeting",
ObjectSchema(True).with_required_property("name", TypeCode.String),
handler
)
# Commandable REST service (Swagger UI automatically generated from command set)
from pip_services3_rpc.services import CommandableHttpService
class FriendCommandableHttpService1(CommandableHttpService):
def __init__(self):
super().__init__('commandable_hello_friend1')
self._dependency_resolver.put('controller', Descriptor('hello-friend', 'controller', '*', '*', '*'))
self._swagger_path = None
def configure(self, config):
super().configure(config)
# Swagger
self._swagger_path = config.get_as_nullable_string('swagger.path')
def register(self):
super().register()
if self._swagger_path:
self._register_open_api_spec_from_file(self._swagger_path)
# Commandable REST service (Swagger UI generated from YAML file)
from pip_services3_rpc.services import CommandableHttpService
class FriendCommandableHttpService2(CommandableHttpService):
def __init__(self):
super().__init__('commandable_hello_friend2')
self._dependency_resolver.put('controller', Descriptor('hello-friend', 'controller', '*', '*', '*'))
self._swagger_path = None
def configure(self, config):
super().configure(config)
# Swagger
self._swagger_path = config.get_as_nullable_string('swagger.path')
def register(self):
super().register()
if self._swagger_path:
self._register_open_api_spec_from_file(self._swagger_path)
# Controller
from pip_services3_commons.commands import ICommandable
from pip_services3_commons.config import IConfigurable
class HelloFriendController(IConfigurable, ICommandable):
__defaultName = None
__command_set: 'FriendsCommandSet' = None
def __init__(self):
self.__defaultName = "Pip User"
def configure(self, config):
self.__defaultName = config.get_as_string_with_default("default_name", self.__defaultName)
def get_command_set(self) -> CommandSet:
if self.__command_set is None:
self.__command_set = FriendsCommandSet(self)
return self.__command_set
def greeting(self, name):
return f"Hello, {name if name else self.__defaultName} !"
from pip_services3_commons.refer import Descriptor
from pip_services3_components.build import Factory
# Factory
class HelloFriendServiceFactory(Factory):
def __init__(self):
super(HelloFriendServiceFactory, self).__init__()
HttpServiceDescriptor = Descriptor('hello-friend', 'service', 'http', '*', '1.0') # View 1
CommandableHttpServiceDescriptor1 = Descriptor('hello-friend', 'service', 'commandable-http1', '*', '1.0') # View 2
CommandableHttpServiceDescriptor2 = Descriptor('hello-friend', 'service', 'commandable-http2', '*', '1.0') # View 2
ControllerDescriptor = Descriptor('hello-friend', 'controller', 'default', '*', '1.0') # Controller
self.register_as_type(HttpServiceDescriptor, HelloFriendRestService) # View 1
self.register_as_type(CommandableHttpServiceDescriptor1, FriendCommandableHttpService1) # View 2
self.register_as_type(CommandableHttpServiceDescriptor2, FriendCommandableHttpService2) # View 3
self.register_as_type(ControllerDescriptor, HelloFriendController) # Controller
from pip_services3_container.ProcessContainer import ProcessContainer
from pip_services3_rpc.build import DefaultRpcFactory
from pip_services3_swagger.build.DefaultSwaggerFactory import DefaultSwaggerFactory
# Container
class HelloFriendProcess(ProcessContainer):
def __init__(self):
super(HelloFriendProcess, self).__init__('hello-friend', 'HelloFriend microservice')
self._config_path = './config.yml'
self._factories.add(HelloFriendServiceFactory())
self._factories.add(DefaultRpcFactory())
self._factories.add(DefaultSwaggerFactory())
# Runner
if __name__ == '__main__':
runner = HelloFriendProcess()
print("run")
try:
runner.run()
except Exception as ex:
print(ex)
config.yaml
Code Example
---
# Container context
- descriptor: "pip-services:context-info:default:default:1.0"
name: "hello-friend"
description: "HelloFriend microservice"
# Console logger
- descriptor: "pip-services:logger:console:default:1.0"
level: "trace"
# Performance counter that post values to log
- descriptor: "pip-services:counters:log:default:1.0"
# Controller
- descriptor: "hello-friend:controller:default:default:1.0"
default_name: "Friend"
# Shared HTTP Endpoint
- descriptor: "pip-services:endpoint:http:default:1.0"
connection:
protocol: http
host: 0.0.0.0
port: 8080
# HTTP Service V1
- descriptor: "hello-friend:service:http:default:1.0"
swagger:
enable: true
path: './rest_swagger.yml'
- descriptor: "hello-friend:service:commandable-http1:default:1.0"
swagger:
enable: true
auto: true
route: swagger
name: Friends Service
description: Commandable REST API - Automatic
- descriptor: "hello-friend:service:commandable-http2:default:1.0"
swagger:
enable: true
auto: false
route: swagger
path: './commandable_swagger.yml'
# Heartbeat service
- descriptor: "pip-services:heartbeat-service:http:default:1.0"
# Status service
- descriptor: "pip-services:status-service:http:default:1.0"
# Swagger service
- descriptor: "pip-services:swagger-service:http:default:1.0"
Code Example
---
# Container context
- descriptor: "pip-services:context-info:default:default:1.0"
name: "hello-friend"
description: "HelloFriend microservice"
# Console logger
- descriptor: "pip-services:logger:console:default:1.0"
level: "trace"
# Performance counter that post values to log
- descriptor: "pip-services:counters:log:default:1.0"
# Controller
- descriptor: "hello-friend:controller:default:default:1.0"
default_name: "Friend"
# Shared HTTP Endpoint
- descriptor: "pip-services:endpoint:http:default:1.0"
connection:
protocol: http
host: 0.0.0.0
port: 8080
# HTTP Service V1
- descriptor: "hello-friend:service:http:default:1.0"
swagger:
enable: true
path: '../../../rest_swagger.yml'
- descriptor: "hello-friend:service:commandable-http1:default:1.0"
swagger:
enable: true
auto: true
route: swagger
name: Friends Service
description: Commandable REST API - Automatic
- descriptor: "hello-friend:service:commandable-http2:default:1.0"
swagger:
enable: true
auto: false
route: swagger
path: '../../../commandable_swagger.yml'
# Heartbeat service
- descriptor: "pip-services:heartbeat-service:http:default:1.0"
# Status service
- descriptor: "pip-services:status-service:http:default:1.0"
# Swagger service
- descriptor: "pip-services:swagger-service:http:default:1.0"
Code Example
---
# Container context
- descriptor: "pip-services:context-info:default:default:1.0"
name: "hello-friend"
description: "HelloFriend microservice"
# Console logger
- descriptor: "pip-services:logger:console:default:1.0"
level: "trace"
# Performance counter that post values to log
- descriptor: "pip-services:counters:log:default:1.0"
# Controller
- descriptor: "hello-friend:controller:default:default:1.0"
default_name: "Friend"
# Shared HTTP Endpoint
- descriptor: "pip-services:endpoint:http:default:1.0"
connection:
protocol: http
host: 0.0.0.0
port: 8080
# HTTP Service V1
- descriptor: "hello-friend:service:http:default:1.0"
swagger:
enable: true
path: './rest_swagger.yml'
- descriptor: "hello-friend:service:commandable-http1:default:1.0"
swagger:
enable: true
auto: true
route: swagger
name: Friends Service
description: Commandable REST API - Automatic
- descriptor: "hello-friend:service:commandable-http2:default:1.0"
swagger:
enable: true
auto: false
route: swagger
path: './commandable_swagger.yml'
# Heartbeat service
- descriptor: "pip-services:heartbeat-service:http:default:1.0"
# Status service
- descriptor: "pip-services:status-service:http:default:1.0"
# Swagger service
- descriptor: "pip-services:swagger-service:http:default:1.0"
Code Example
---
# Container context
- descriptor: "pip-services:context-info:default:default:1.0"
name: "hello-friend"
description: "HelloFriend microservice"
# Console logger
- descriptor: "pip-services:logger:console:default:1.0"
level: "trace"
# Performance counter that post values to log
- descriptor: "pip-services:counters:log:default:1.0"
# Controller
- descriptor: "hello-friend:controller:default:default:1.0"
default_name: "Friend"
# Shared HTTP Endpoint
- descriptor: "pip-services:endpoint:http:default:1.0"
connection:
protocol: http
host: 0.0.0.0
port: 8080
# HTTP Service V1
- descriptor: "hello-friend:service:http:default:1.0"
swagger:
enable: true
path: './rest_swagger.yml'
- descriptor: "hello-friend:service:commandable-http1:default:1.0"
swagger:
enable: true
auto: true
route: swagger
name: Friends Service
description: Commandable REST API - Automatic
- descriptor: "hello-friend:service:commandable-http2:default:1.0"
swagger:
enable: true
auto: false
route: swagger
path: './commandable_swagger.yml'
# Heartbeat service
- descriptor: "pip-services:heartbeat-service:http:default:1.0"
# Status service
- descriptor: "pip-services:status-service:http:default:1.0"
# Swagger service
- descriptor: "pip-services:swagger-service:http:default:1.0"
Code Example
---
# Container context
- descriptor: "pip-services:context-info:default:default:1.0"
name: "hello-friend"
description: "HelloFriend microservice"
# Console logger
- descriptor: "pip-services:logger:console:default:1.0"
level: "trace"
# Performance counter that post values to log
- descriptor: "pip-services:counters:log:default:1.0"
# Controller
- descriptor: "hello-friend:controller:default:default:1.0"
default_name: "Friend"
# Shared HTTP Endpoint
- descriptor: "pip-services:endpoint:http:default:1.0"
connection:
protocol: http
host: 0.0.0.0
port: 8080
# HTTP Service V1
- descriptor: "hello-friend:service:http:default:1.0"
swagger:
enable: true
path: './rest_swagger.yml'
- descriptor: "hello-friend:service:commandable-http1:default:1.0"
swagger:
enable: true
auto: true
route: swagger
name: Friends Service
description: Commandable REST API - Automatic
- descriptor: "hello-friend:service:commandable-http2:default:1.0"
swagger:
enable: true
auto: false
route: swagger
path: './commandable_swagger.yml'
# Heartbeat service
- descriptor: "pip-services:heartbeat-service:http:default:1.0"
# Status service
- descriptor: "pip-services:status-service:http:default:1.0"
# Swagger service
- descriptor: "pip-services:swagger-service:http:default:1.0"
Wrapping up
In this tutorial, we have seen how to create Swagger UIs from a REST service and a commandable REST service. First, we created a REST service that is Swagger enabled and obtained all the information necessary to create the UI from a YAML file. After that, we created a commandable REST service, which developed a UI from a set of commands or a YAML file. Finally, we created a process container used to run our app. Once run, our app produced Swagger UIs documenting the greeting method for each case.