Invoking Zato Python microservices with OpenAPI
One of the exciting additions of the upcoming Zato 3.2 release is the ability to invoke services through OpenAPI endpoints without a need for creation of REST channels explicitly - read more for details.
Supposing we have a service such as below - note that it is uses SimpleIO and that each of its input/output attributes is documented in the docstring - we would like to invoke it from an external application while delegating to Zato as much effort involved in it as possible.
# -*- coding: utf-8 -*- # Zato from zato.server.service import Service class GetUserAccount(Service): """ Returns user account details based on user ID and type. """ name = 'api.get.user.account' class SimpleIO: """ * account_id - ID of the user account to return * user_type - Type of the user the account belongs to * user_name - Name of the user to whom account_id belongs * needs_review - A flag indicating whether the account needs to be reviewed """ input_required = 'account_id', 'user_type' output_required = 'account_name', 'needs_review' def handle(self): # Local aliases account_id = self.request.input.account_id user_type = self.request.input.user_type # In reality, additional work would be carried out here first .. self.logger.info('Returning data for `%s` (%s)', account_id, user_type ) # .. produce the output now. self.response.payload.user_name = 'my.user' self.response.payload.needs_review = True
We will not pursue this path in this article but, in other circumstances, we could just create a REST channel for the service. This is great and it works perfectly fine, always letting one adjust many options, such as caching or rate-limiting.
However, today, we will auto-create API definitions using OpenAPI.
Creating OpenAPI specifications
Documentation, including OpenAPI specifications, can be created from the command line, as below:
$ zato apispec /path/to/server \ --dir /my/output/directory \ --include api.* \ --tags public \ --verbose
What we will find in the output directory is a Sphinx project with human-readable documentation, which is nice in itself, along with formal specifications, including OpenAPI.
Inspecting the OpenAPI specification
Upon downloading the openapi.yaml file we can confirm that it is a formal specification of the APIs exposed - including request and response schemas as well as endpoint addresses.
Note that, because we are using SimpleIO, the specification includes description of parameters and the parameters have expected data types, e.g. account_id is an integer while needs_review is a boolean.
components: schemas: request_api_get_user_account: properties: account_id: description: ID of the user account to return format: int32 type: integer user_type: description: Type of the user the account belongs to format: string type: string required: - account_id - user_type title: Request object for api.get.user.account type: object response_api_get_user_account: properties: needs_review: description: A flag indicating whether the account needs to be reviewed format: boolean type: boolean user_name: description: Name of the user to whom account_id belongs format: string type: string required: - user_name - needs_review title: Response object for api.get.user.account type: object paths: /zato/api/invoke/api.get.user.account: post: consumes: - application/json operationId: post__zato_api_invoke_api_get_user_account requestBody: content: application/json: schema: $ref: '#/components/schemas/request_api_get_user_account' required: true responses: '200': content: application/json: schema: $ref: '#/components/schemas/response_api_get_user_account' info: title: API spec version: '1.0' openapi: 3.0.2 servers: - url: http://localhost:11223
With the specification downloaded, we can start to invoke our service immediately - in this case, we will use Postman. Essentially, import a definition, choose the desired service, provide input data and click the “Send” button.
Afterwards, we can also confirm in Zato server logs that the request was processed correctly.
Even more protocols
The above suffices for external clients to invoke your services purely based on their Python definitions with endpoints, documentation and specifications auto-generated by Zato.
But there is more. Have you noticed that nothing in the service used is specific to REST, OpenAPI or HTTP for that matter?
That is one of the benefits of using Zato - such a service is completely reusable across a range of other protocols, which means that it can exposed as-is through other channels, e.g. IBM MQ, AMQP, SOAP, WebSockets, Publish/Subscribe topics, Scheduler, File transfer and many more.
Be sure to check the Zato documentation for more details!