Search code examples
python-3.xyamlswaggerpypiconnexion

Swagger-UI generated python server not starting due to 'no module named' error


I'm working with an OpenAPI 3.0.1 yaml and it's unable to get the API webserver started due to the below error. I tried almost everything that is under my knowledge but I'm very new at OpenAPI and the documentation was followed as it is. Any thoughts on what could be wrong here?

This is the error on loading up the server:

Failed to add operation for GET /v2/catalog
Traceback (most recent call last):
  File "C:\Programs\Python\Python38\lib\site-packages\connexion\apis\abstract.py", line 209, in add_paths
    self.add_operation(path, method)
  File "C:\Programs\Python\Python38\lib\site-packages\connexion\apis\abstract.py", line 162, in add_operation
    operation = make_operation(
  File "C:\Programs\Python\Python38\lib\site-packages\connexion\operations\__init__.py", line 8, in make_operation
    return spec.operation_cls.from_spec(spec, *args, **kwargs)
  File "C:\Programs\Python\Python38\lib\site-packages\connexion\operations\openapi.py", line 128, in from_spec
    return cls(
  File "C:\Programs\Python\Python38\lib\site-packages\connexion\operations\openapi.py", line 75, in __init__
    super(OpenAPIOperation, self).__init__(
  File "C:\Programs\Python\Python38\lib\site-packages\connexion\operations\abstract.py", line 96, in __init__
    self._resolution = resolver.resolve(self)
  File "C:\Programs\Python\Python38\lib\site-packages\connexion\resolver.py", line 40, in resolve
    return Resolution(self.resolve_function_from_operation_id(operation_id), operation_id)
  File "C:\Programs\Python\Python38\lib\site-packages\connexion\resolver.py", line 64, in resolve_function_from_operation_id
    raise ResolverError(msg, sys.exc_info())
connexion.exceptions.ResolverError: <ResolverError: Cannot resolve operationId "catalog.get"! Import error was "No module named 'catalog'">

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Programs\Python\Python38\lib\runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "C:\Programs\Python\Python38\lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "D:\API\swagger_server\__main__.py", line 25, in <module>
    main()
  File "D:\API\swagger_server\__main__.py", line 18, in main
    app.add_api('D:\API\swagger_server\swagger\swagger.yaml', arguments={'title': 'GPI API Broker'}, pythonic_params=True)
  File "C:\Programs\Python\Python38\lib\site-packages\connexion\apps\flask_app.py", line 57, in add_api
    api = super(FlaskApp, self).add_api(specification, **kwargs)
  File "C:\Programs\Python\Python38\lib\site-packages\connexion\apps\abstract.py", line 141, in add_api
    api = self.api_cls(specification,
  File "C:\Programs\Python\Python38\lib\site-packages\connexion\apis\abstract.py", line 111, in __init__
    self.add_paths()
  File "C:\Programs\Python\Python38\lib\site-packages\connexion\apis\abstract.py", line 216, in add_paths
    self._handle_add_operation_error(path, method, err.exc_info)
  File "C:\Programs\Python\Python38\lib\site-packages\connexion\apis\abstract.py", line 231, in _handle_add_operation_error
    raise value.with_traceback(traceback)
  File "C:\Programs\Python\Python38\lib\site-packages\connexion\resolver.py", line 61, in resolve_function_from_operation_id
    return self.function_resolver(operation_id)
  File "C:\Programs\Python\Python38\lib\site-packages\connexion\utils.py", line 110, in get_function_from_name
    module = importlib.import_module(module_name)
  File "C:\Programs\Python\Python38\lib\importlib\__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 973, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'catalog'

The startup command is basically: python -m swagger_server

Finally, this is part of my YAML where the operationId is mentioned:

openapi: 3.0.1
info:
  title: Open Service Broker API
  description: The Open Service Broker API defines an HTTP(S) interface between Platforms
    and Service Brokers.
  contact:
    name: Open Service Broker API
    url: https://www.openservicebrokerapi.org/
    email: [email protected]
  license:
    name: Apache 2.0
    url: http://www.apache.org/licenses/LICENSE-2.0.html
  version: master - might contain changes that are not yet released
externalDocs:
  description: The offical Open Service Broker API specification
  url: https://github.com/openservicebrokerapi/servicebroker/
servers:
- url: http://localhost:80/
- url: https://localhost:80/
security:
- basicAuth: []
paths:
  /v2/catalog:
    get:
      tags:
      - Catalog
      summary: get the catalog of services that the service broker offers
      operationId: 'catalog.get'
      parameters:
      - name: X-Broker-API-Version
        in: header
...

Thank you all in advance!


Solution

  • The operationId must be relative to where your app is running.

    swagger_server
    |-- app.py
    |-- __init__.py
    |-- OpenAPI
    |   |-- openapi.yml
    |-- models
    |   |-- catalog.py
    

    Given the above folder structure, you start the app in the directory swagger_server. Consequently, the path of app.py is in your sys.path. Relative to this path you need to specify the operationId in your openapi.yml:

    paths:
      /v2/catalog:
        get:
          tags:
          - Catalog
          summary: get the catalog of services that the service broker offers
          operationId: 'models.catalog.get'
    

    The file catalog.py must contain a function def get(name). Here you can define your service/handler for the endpoint. It must include the parameter name because you have specified the parameter in your YAML file.