2

I am currently trying to build an api using connexion. However, I am having some issues using relative local module imports through the connexion module, which modifies the underlying flask app. Here is a simplified overview of my file structure:

  • hall_of_fame_api
    • controller
      • ____init____.py
      • routes.py
    • model
      • ____init____.py
      • routes.py
    • ____init____.py
    • config.py
    • create_db.py
    • swagger.yml

I am getting an error when I try to run 'python config.py' in my terminal. Here is config.py:

import os
import connexion
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow

basedir = os.path.abspath(os.path.dirname(__file__))

# Create the Connexion application instance
connex_app = connexion.App(__name__, specification_dir=basedir)

# Get the underlying Flask app instance
app = connex_app.app
connex_app.add_api('swagger.yml')

# Configure the SQLAlchemy part of the app instance
app.config['SQLALCHEMY_ECHO'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://doadmin:password@nba-player-db-do-user-7027314-0.db.ondigitalocean.com:25060/nba_test_1?sslmode=require'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

# Create the SQLAlchemy db instance
db = SQLAlchemy(app)

# Initialize Marshmallow
ma = Marshmallow(app)

And here is the error it gives:

Failed to add operation for GET /api/players
Failed to add operation for GET /api/players
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/connexion/apis/abstract.py", line 209, in add_paths
self.add_operation(path, method)
  File "/usr/local/lib/python3.7/site-packages/connexion/apis/abstract.py", line 173, in add_operation
    pass_context_arg_name=self.pass_context_arg_name
  File "/usr/local/lib/python3.7/site-packages/connexion/operations/__init__.py", line 8, in make_operation
    return spec.operation_cls.from_spec(spec, *args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/connexion/operations/swagger2.py", line 137, in from_spec
    **kwargs
  File "/usr/local/lib/python3.7/site-packages/connexion/operations/swagger2.py", line 96, in __init__
    pass_context_arg_name=pass_context_arg_name
  File "/usr/local/lib/python3.7/site-packages/connexion/operations/abstract.py", line 96, in __init__
    self._resolution = resolver.resolve(self)
  File "/usr/local/lib/python3.7/site-packages/connexion/resolver.py", line 40, in resolve
    return Resolution(self.resolve_function_from_operation_id(operation_id), operation_id)
  File "/usr/local/lib/python3.7/site-packages/connexion/resolver.py", line 66, in resolve_function_from_operation_id
    raise ResolverError(str(e), sys.exc_info())
connexion.exceptions.ResolverError: <ResolverError: module 'controller.routes' has no attribute 'read_all'>

This error comes specifically from line 12 where connexion is trying to add the swagger.yml file, here is that for reference as well:

swagger: "2.0"
info:
  description: This is the swagger file that goes with our server code
  version: "1.0.0"
  title: Swagger REST Article
consumes:
  - "application/json"
produces:
  - "application/json"

basePath: "/api"

# Paths supported by the server application
paths:
  /players:
    get:
      operationId: "controller.routes.read_all"
      tags:
        - "People"
      summary: "The people data structure supported by the server application"
      description: "Read the list of people"
      responses:
        200:
          description: "Successful read people list operation"
          schema:
            type: "array"
            items:
              properties:
                fname:
                  type: "string"
                lname:
                  type: "string"
                timestamp:
                  type: "string"

Now here is where I am confused, because my routes.py file does have a function defined as read_all(), here is that file:

from model.models import Regseason, RegSchema, Playoffs, PlayoffSchema

def read_all():

    return Regseason.query.all()

I have been racking my brain over this bug for almost 24 hours, any guidance would be greatly appreciated. Thanks in advance!

Kevin Martins
  • 590
  • 7
  • 20
Henry Bowe
  • 21
  • 1
  • I could not reproduce your problem but I believe it happens due to the PYTHONPATH. Try execute: `PYTHONPATH=. yourCommand` – Kevin Martins Jan 29 '20 at 19:27
  • Can you link the routes? You set a base path "/api" in the swagger file but the Get request drop for "/api/players". If your flask route looks like "/api/players", the result will be the endpoint being "/api/api/players". – Dylan Jan 29 '20 at 18:39
  • I haven't actually added any routes yet, but I do see what you are saying! I probably shouldn't have named that file routes.py I will fix the naming convention, but the last bit of code you see is the routes.py – Henry Bowe Jan 29 '20 at 18:46
  • @KevinMartins what exactly am I replacing the yourCommand with? The directory's path? – Henry Bowe Jan 30 '20 at 05:10
  • @HenryBowe `PYTHONPATH=. python config.py` – Kevin Martins Jan 30 '20 at 11:52
  • @KevinMartins when i executed the command it returned the same error – Henry Bowe Jan 30 '20 at 18:44
  • @HenryBowe could you try change operationId in your swagger to `hall_of_fame_api .controller.routes.read_all`. If it doest work try execute the `PYTHONPATH=. python config.py` with this change to – Kevin Martins Jan 31 '20 at 19:14

1 Answers1

1

Please add a extra field x-openapi-router-controller below operationid. It is used by Connexion to map which module to send requests to. It is combined together with OperationId to go to correct module and function.

Ajay
  • 11
  • 1
  • 2