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 controller. We will see three different cases. The first is a common REST controller, which is documented via a YAML file containing a description of its methods. The second is a commandable REST controller, 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 controllers, which are defined by two different classes. The first is an ordinary REST controller and is defined by the RestController component. The second is a REST controller that contains a set of predefined commands (or methods) that can be called from other controllers and is defined by the CommandableHttpController class.
As such, they represent two different approaches when it comes to Swagger documentation: A REST controller needs a YAML file that describes its UI in order to generate its documentation, whereas a commandable controller 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-services4-swagger-node --save
pip install pip-services3-swagger
Document 1: REST controller
In this case, we want to document the greeting method as part of a REST controller. For this, we need to define a YAML file containing the information necessary to create the Swagger UI.
Controller
Our REST controller is called HelloFriendController. It is defined by a class that inherits from the RestController 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 service 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-services4-components-node";
import { RestController } from "pip-services4-http-node";
class HelloFriendRestController extends RestController {
private _service: HelloFriendService;
// swagger
private _swaggerContent: string;
private _swaggerPath: string;
public constructor() {
super();
this._baseRoute = "/hello_friend";
let serviceDescriptor = new Descriptor("hello-friend", "service", "*", "*", "1.0");
this._dependencyResolver.put("service", serviceDescriptor);
}
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._service = this._dependencyResolver.getOneRequired<HelloFriendService>("service");
}
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._service.greeting(name);
this.sendResult(req, res, result);
}
}
from pip_services4_components.refer import Descriptor
from pip_services4_data.validate import Schema
from pip_services4_http.controller import RestController
import bottle
class HelloFriendRestController(RestController):
def __init__(self):
super(HelloFriendRestController, self).__init__()
self._base_route = "/hello_friend"
ServiceDescriptor = Descriptor('hello-friend', 'service', '*', '*', '1.0')
self._dependency_resolver.put('service', ServiceDescriptor)
self._service = 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(HelloFriendRestController, self).set_references(references)
self._service = self._dependency_resolver.get_one_required('service')
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 controller 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 controller, and we define the path to our YAML file containing the Swagger UI description.
# HTTP Controller V1
- descriptor: "hello-friend:controller:http:default:1.0"
swagger:
enable: true
path: './rest_swagger.yml'
# HTTP Service V1
- descriptor: "hello-friend:controller: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 controller has the greeting method only, which we consider of type GET. An example of this file is:
openapi: '3.0.2'
info:
title: 'Friends Controller'
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 controller
These two cases document the same commandable REST controller. 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 { TypeCode } from "pip-services4-commons-node";
import { Parameters, IContext } from "pip-services4-components-node";
import { ObjectSchema } from "pip-services4-data-node";
import { CommandSet, ICommand, Command } from "pip-services4-rpc-node";
class FriendsCommandSet extends CommandSet {
private _service: HelloFriendService;
public constructor(service: HelloFriendService) {
super();
this._service = service;
this.addCommand(this.makeGreeting());
}
private makeGreeting(): ICommand {
return new Command('greeeting',
new ObjectSchema(true).withRequiredProperty('name', TypeCode.String),
async (ctx: IContext, args: Parameters) =>
{
let name = args.getAsString("name");
let res = this._service.greeting(name);
return res;
}
);
}
}
from pip_services4_rpc.commands import Command, CommandSet, ICommand
from pip_services4_components.exec import Parameters
from pip_services4_data.validate import Schema, ObjectSchema
from pip_services4_commons.convert import TypeCode
from typing import Optional
class FriendsCommandSet(CommandSet):
_service: 'HelloFriendService'
def __init__(self, service):
super().__init__()
self._service = controller
self.add_command(self._make_greeting())
def _make_greeting(self) -> ICommand:
def handler(context: Optional[IContext], 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
)
Controller for document 2
Once our command set has been defined, we create our commandable REST controller by extending the CommandableHttpController class and we link it to our controller. This controller 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 { Descriptor, ConfigParams } from "pip-services4-components-node";
import { CommandableHttpController } from "pip-services4-http-node";
class FriendCommandableHttpService1 extends CommandableHttpController {
private _swaggerPath: string;
public constructor() {
super("commandable_hello_friend1");
this._dependencyResolver.put('service', new Descriptor("hello-friend", "service", "*", "*", "*"));
}
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);
}
}
from pip_services4_http.controller import CommandableHttpController
class FriendCommandableHttpController1(CommandableHttpController):
def __init__(self):
super().__init__('commandable_hello_friend1')
self._dependency_resolver.put('service', Descriptor('hello-friend', 'service', '*', '*', '*'))
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:controller:commandable-http1:default:1.0"
swagger:
enable: true
auto: true
route: swagger
name: Friends Controller
description: Commandable REST API - Automatic
Controller for document 3
Similar to the previous one, this controller builds the Swagger UI from the YAML file defined in the configuration file.
import { Descriptor, ConfigParams } from "pip-services4-components-node";
import { CommandableHttpController } from "pip-services4-http-node";
class FriendCommandableHttpService2 extends CommandableHttpController {
private _swaggerPath: string;
public constructor() {
super("commandable_hello_friend1");
this._dependencyResolver.put('service', new Descriptor("hello-friend", "service", "*", "*", "*"));
}
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);
}
}
from pip_services4_http.controller import CommandableHttpController
class FriendCommandableHttpController2(CommandableHttpController):
def __init__(self):
super().__init__('commandable_hello_friend2')
self._dependency_resolver.put('service', Descriptor('hello-friend', 'service', '*', '*', '*'))
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:controller: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 Controller'
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 controllers 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 controllers.
import { Descriptor, Factory } from "pip-services4-components-node";
class HelloFriendServiceFactory extends Factory {
public constructor()
{
super();
let HttpControllerDescriptor = new Descriptor("hello-friend", "controller", "http", "*", "1.0"); // Controller 1
let CommandableHttpControllerDescriptor1 = new Descriptor("hello-friend", "controller", "commandable-http1", "*", "1.0"); // Controller 2
let CommandableHttpontrollerDescriptor2 = new Descriptor("hello-friend", "controller", "commandable-http2", "*", "1.0"); // Controller 2
let ServiceDescriptor = new Descriptor("hello-friend", "service", "default", "*", "1.0"); // Service
this.registerAsType(HttpControllerDescriptor, HelloFriendRestController); // View 1
this.registerAsType(CommandableHttpControllerDescriptor1, FriendCommandableHttpController1); // View 2
this.registerAsType(CommandableHttpontrollerDescriptor2, FriendCommandableHttpController2); // View 3
this.registerAsType(ServiceDescriptor, HelloFriendService); // Service
}
}
from pip_services4_components.refer import Descriptor
from pip_services4_components.build import Factory
class HelloFriendControllerFactory(Factory):
def __init__(self):
super(HelloFriendControllerFactory, self).__init__()
HttpControllerDescriptor = Descriptor('hello-friend', 'controller', 'http', '*', '1.0') # View 1
CommandableHttpControllerDescriptor1 = Descriptor('hello-friend', 'controller', 'commandable-http1', '*', '1.0') # View 2
CommandableHttpControllerDescriptor2 = Descriptor('hello-friend', 'controller', 'commandable-http2', '*', '1.0') # View 2
ServiceDescriptor = Descriptor('hello-friend', 'service', 'default', '*', '1.0') # Controller
self.register_as_type(HttpControllerDescriptor, HelloFriendRestController) # Controller
self.register_as_type(CommandableHttpControllerDescriptor1, FriendCommandableHttpController1) # Controller
self.register_as_type(CommandableHttpControllerDescriptor2, FriendCommandableHttpController2) # Controller
self.register_as_type(ServiceDescriptor, HelloFriendService) # Service
Process container
Once we have our factory, we define our process container by extending the ProcessContainer class and adding the factories for the controllers and Swagger. Our code will look something like this:
import { ProcessContainer } from "pip-services4-container-node";
import { DefaultSwaggerFactory } from "pip-services4-swagger-node";
import { DefaultHttpFactory } from "pip-services4-http-node";
class HelloFriendProcess extends ProcessContainer {
public constructor() {
super("hello-friend", "HelloFriend microservice");
this._configPath = "./config.yml";
this._factories.add(new HelloFriendServiceFactory());
this._factories.add(new DefaultHttpFactory());
this._factories.add(new DefaultSwaggerFactory());
}
}
from pip_services4_container.container import ProcessContainer
from pip_services4_http.build import DefaultRpcFactory
from pip_services4_swagger.build.DefaultSwaggerFactory import DefaultSwaggerFactory
class HelloFriendProcess(ProcessContainer):
def __init__(self):
super(HelloFriendProcess, self).__init__('hello-friend', 'HelloFriend microservice')
self._config_path = './config35.yaml'
self._factories.add(HelloFriendControllerFactory())
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);
}
}
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 controller
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 controller
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 controller.
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 { ProcessContainer } from "pip-services4-container-node";
import { DefaultSwaggerFactory } from "pip-services4-swagger-node";
import { CommandableHttpController, DefaultHttpFactory, RestController } from "pip-services4-http-node";
import {
ConfigParams, Descriptor, Factory, IConfigurable,
IReferences, IContext, Parameters
} from "pip-services4-components-node";
import { CommandSet, ICommand, Command } from "pip-services4-rpc-node";
import { ObjectSchema } from "pip-services4-data-node";
import { TypeCode } from "pip-services4-commons-node";
export async function main() {
// Runner
try {
let proc = new HelloFriendProcess();
proc.run(process.argv);
} catch (ex) {
console.error(ex);
}
}
// REST controller (Swagger UI from YAML file)
class HelloFriendRestController extends RestController {
private _service: HelloFriendService;
// swagger
private _swaggerContent: string;
private _swaggerPath: string;
public constructor() {
super();
this._baseRoute = "/hello_friend";
let serviceDescriptor = new Descriptor("hello-friend", "service", "*", "*", "1.0");
this._dependencyResolver.put("service", serviceDescriptor);
}
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._service = this._dependencyResolver.getOneRequired<HelloFriendService>("service");
}
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._service.greeting(name);
this.sendResult(req, res, result);
}
}
// Command set
class FriendsCommandSet extends CommandSet {
private _service: HelloFriendService;
public constructor(controller: HelloFriendService) {
super();
this._service = controller;
this.addCommand(this.makeGreeting());
}
private makeGreeting(): ICommand {
return new Command('greeeting',
new ObjectSchema(true).withRequiredProperty('name', TypeCode.String),
async (ctx: IContext, args: Parameters) =>
{
let name = args.getAsString("name");
let res = this._service.greeting(name);
return res;
}
);
}
}
// Commandable REST Controller (Swagger UI automatically generated from command set)
class FriendCommandableHttpController1 extends CommandableHttpController {
private _swaggerPath: string;
public constructor() {
super("commandable_hello_friend1");
this._dependencyResolver.put('service', new Descriptor("hello-friend", "service", "*", "*", "*"));
}
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 controller (Swagger UI generated from YAML file)
class FriendCommandableHttpController2 extends CommandableHttpController {
private _swaggerPath: string;
public constructor() {
super("commandable_hello_friend2");
this._dependencyResolver.put('service', new Descriptor("hello-friend", "service", "*", "*", "*"));
}
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);
}
}
// Servcie
class HelloFriendService implements IConfigurable, ICommand {
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 HttpControllerDescriptor = new Descriptor("hello-friend", "controller", "http", "*", "1.0"); // controller 1
let CommandableHttpControllerDescriptor1 = new Descriptor("hello-friend", "controller", "commandable-http1", "*", "1.0"); // controller 2
let CommandableHttpControllerDescriptor2 = new Descriptor("hello-friend", "controller", "commandable-http2", "*", "1.0"); // controller 2
let ServiceDescriptor = new Descriptor("hello-friend", "service", "default", "*", "1.0"); // Service
this.registerAsType(HttpControllerDescriptor, HelloFriendRestController); // View 1
this.registerAsType(CommandableHttpControllerDescriptor1, FriendCommandableHttpController1); // View 2
this.registerAsType(CommandableHttpControllerDescriptor2, FriendCommandableHttpController2); // View 3
this.registerAsType(ServiceDescriptor, HelloFriendService); // service
}
}
// 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 DefaultHttpFactory());
this._factories.add(new DefaultSwaggerFactory());
}
}
Code Example
Code Example
Code Example
Code Example
from pip_services4_components.refer import Descriptor
from pip_services4_data.validate import Schema
from pip_services4_http.controller import RestController
from pip_services4_rpc.commands import Command, CommandSet, ICommand
from pip_services4_components.exec import Parameters
from pip_services4_data.validate import Schema, ObjectSchema
from pip_services4_commons.convert import TypeCode
from pip_services4_http.controller import CommandableHttpController
from pip_services4_container.container import ProcessContainer
from pip_services4_http.build import DefaultRpcFactory
from pip_services4_swagger.build.DefaultSwaggerFactory import DefaultSwaggerFactory
from pip_services4_rpc.commands import ICommandable
from pip_services4_components.config import IConfigurable
from pip_services4_components.refer import Descriptor
from pip_services4_components.build import Factory
from pip_services4_components.context import IContext
from typing import Optional
import bottle
# REST controller (Swagger UI from YAML file)
class HelloFriendRestController(RestController):
def __init__(self):
super(HelloFriendRestController, self).__init__()
self._base_route = "/hello_friend"
ServiceDescriptor = Descriptor('hello-friend', 'service', '*', '*', '1.0')
self._dependency_resolver.put('service', ServiceDescriptor)
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(HelloFriendRestController, self).set_references(references)
self._service = self._dependency_resolver.get_one_required('service')
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._service.greeting(name)
return self.send_result(result)
# Command set
class FriendsCommandSet(CommandSet):
_service: 'HelloFriendService'
def __init__(self, service):
super().__init__()
self._service = service
self.add_command(self._make_greeting())
def _make_greeting(self) -> ICommand:
def handler(context: Optional[IContext], args: Parameters):
name = args.get_as_string("name")
res = self._service.greeting(name)
return res
return Command(
"greeting",
ObjectSchema(True).with_required_property("name", TypeCode.String),
handler
)
# Commandable REST controller (Swagger UI automatically generated from command set)
class FriendCommandableHttpController1(CommandableHttpController):
def __init__(self):
super().__init__('commandable_hello_friend1')
self._dependency_resolver.put('service', Descriptor('hello-friend', 'service', '*', '*', '*'))
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 controller (Swagger UI generated from YAML file)
class FriendCommandableHttpController2(CommandableHttpController):
def __init__(self):
super().__init__('commandable_hello_friend2')
self._dependency_resolver.put('service', Descriptor('hello-friend', 'service', '*', '*', '*'))
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)
# Service
class HelloFriendService(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} !"
# Factory
class HelloFriendControllerFactory(Factory):
def __init__(self):
super(HelloFriendControllerFactory, self).__init__()
HttpControllerDescriptor = Descriptor('hello-friend', 'controller', 'http', '*', '1.0') # Controller
CommandableHttpControllerDescriptor1 = Descriptor('hello-friend', 'controller', 'commandable-http1', '*', '1.0') # Controller
CommandableHttpControllerDescriptor2 = Descriptor('hello-friend', 'controller', 'commandable-http2', '*', '1.0') # Controller
ServiceDescriptor = Descriptor('hello-friend', 'service', 'default', '*', '1.0') # Service
self.register_as_type(HttpControllerDescriptor, HelloFriendRestController) # Controler
self.register_as_type(CommandableHttpControllerDescriptor1, FriendCommandableHttpController1) # Controller
self.register_as_type(CommandableHttpControllerDescriptor2, FriendCommandableHttpController2) # Controller
self.register_as_type(ServiceDescriptor, HelloFriendService) # Service
# Container
class HelloFriendProcess(ProcessContainer):
def __init__(self):
super(HelloFriendProcess, self).__init__('hello-friend', 'HelloFriend microservice')
self._config_path = './config35.yaml'
self._factories.add(HelloFriendControllerFactory())
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"
# Service
- descriptor: "hello-friend:service: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 controller V1
- descriptor: "hello-friend:controller:http:default:1.0"
swagger:
enable: true
path: './rest_swagger.yml'
- descriptor: "hello-friend:controller:commandable-http1:default:1.0"
swagger:
enable: true
auto: true
route: swagger
name: Friends Service
description: Commandable REST API - Automatic
- descriptor: "hello-friend:controller:commandable-http2:default:1.0"
swagger:
enable: true
auto: false
route: swagger
path: './commandable_swagger.yml'
# Heartbeat controller
- descriptor: "pip-services:heartbeat-controller:http:default:1.0"
# Status controller
- descriptor: "pip-services:status-controller:http:default:1.0"
# Swagger controller
- descriptor: "pip-services:swagger-controller:http:default:1.0"
Code Example
Code Example
Code Example
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"
# Service
- descriptor: "hello-friend:service: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 controller V1
- descriptor: "hello-friend:controller:http:default:1.0"
swagger:
enable: true
path: './rest_swagger.yml'
- descriptor: "hello-friend:controller:commandable-http1:default:1.0"
swagger:
enable: true
auto: true
route: swagger
name: Friends Service
description: Commandable REST API - Automatic
- descriptor: "hello-friend:controller:commandable-http2:default:1.0"
swagger:
enable: true
auto: false
route: swagger
path: './commandable_swagger.yml'
# Heartbeat controller
- descriptor: "pip-services:heartbeat-controller:http:default:1.0"
# Status controller
- descriptor: "pip-services:status-controller:http:default:1.0"
# Swagger controller
- descriptor: "pip-services:swagger-controller:http:default:1.0"
Wrapping up
In this tutorial, we have seen how to create Swagger UIs from a REST controller and a commandable REST controller. First, we created a REST controller 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 controller, 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.