Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple classes wrap #6

Open
vstkl opened this issue Jun 2, 2022 · 5 comments
Open

Multiple classes wrap #6

vstkl opened this issue Jun 2, 2022 · 5 comments

Comments

@vstkl
Copy link

vstkl commented Jun 2, 2022

Hi, I use InstantAPI for my work, it would be lovely to be able to wrap multiple classes around it with user-defined endpoints. Flasgger library does have problem with that, will you be willing to accept PR eventually?

@alexmojaki
Copy link
Owner

Hi, I use InstantAPI for my work

Awesome!

it would be lovely to be able to wrap multiple classes around it with user-defined endpoints

Can you explain this more? What code do you want to be able to write?

Flasgger library does have problem with that

What's the problem?

will you be willing to accept PR

Probably, I'd just like to understand the problem better.

@vstkl
Copy link
Author

vstkl commented Jun 2, 2022

As far as I know, I can't make endpoint like /api1/endpoint1 and /api2/endpoint2
If I'm wrong it would be delight if you could document it, but main issue is flasgger complaining about being used already when I try to decorate more than one class.
So I would probably make changes that would allow multiple methods being decorated or to create <class; url> for each class wrapped with InstantAPI. The easiest way would be to allow user to wrap each method with different endpoint and go from there.
This would be perfect for use:

@InstantAPI(app=app, path="/api1")
class Methods1():
    pass
@InstantAPI(app=app, path="api2")
class Methods2()

However as mentioned above, such syntax produces following error:

  File "server/server.py", line 105, in <module>
    @InstantAPI(app=app, path="/api",) 
  File "/Users/vojta/code/sep-adminweb-api/env/lib/python3.9/site-packages/instant_api/instant_api.py", line 132, in __init__
    self.swagger = Swagger(app, **(swagger_kwargs or {}))
  File "/Users/vojta/code/sep-adminweb-api/env/lib/python3.9/site-packages/flasgger/base.py", line 217, in __init__
    self.init_app(app)
  File "/Users/vojta/code/sep-adminweb-api/env/lib/python3.9/site-packages/flasgger/base.py", line 230, in init_app
    self.register_views(app)
  File "/Users/vojta/code/sep-adminweb-api/env/lib/python3.9/site-packages/flasgger/base.py", line 613, in register_views
    app.register_blueprint(blueprint)
  File "/Users/vojta/code/sep-adminweb-api/env/lib/python3.9/site-packages/flask/scaffold.py", line 56, in wrapper_func
    return f(self, *args, **kwargs)
  File "/Users/vojta/code/sep-adminweb-api/env/lib/python3.9/site-packages/flask/app.py", line 1028, in register_blueprint
    blueprint.register(self, options)
  File "/Users/vojta/code/sep-adminweb-api/env/lib/python3.9/site-packages/flask/blueprints.py", line 305, in register
    raise ValueError(
ValueError: The name 'flasgger' is already registered for a different blueprint. Use 'name=' to provide a unique name.```

@alexmojaki
Copy link
Owner

I looked into the flasgger source code and found the blueprint name being set here to self.config.get('endpoint', 'flasgger'). This can be configured in InstantAPI using swagger_kwargs:

InstantAPI(app, path="/api1/", swagger_kwargs={"config": {"endpoint": "foo"}, "merge": True})

The "merge": True means to merge our custom config with the default, otherwise it complains about missing values.

Then I got this error:

Traceback (most recent call last):
  File "/home/alex/.config/JetBrains/PyCharm2022.1/scratches/scratch_2086.py", line 36, in <module>
    InstantAPI(app, path="/api2/")(Methods2)
  File "/home/alex/work/instant_api/instant_api/instant_api.py", line 133, in __init__
    self._add_view(
  File "/home/alex/work/instant_api/instant_api/instant_api.py", line 393, in _add_view
    self.app.add_url_rule(
  File "/home/alex/.pyenv/versions/3.8.5/lib/python3.8/site-packages/flask/scaffold.py", line 56, in wrapper_func
    return f(self, *args, **kwargs)
  File "/home/alex/.pyenv/versions/3.8.5/lib/python3.8/site-packages/flask/app.py", line 1090, in add_url_rule
    raise AssertionError(
AssertionError: View function mapping is overwriting an existing endpoint function: InstantAPI

Here the problem was that it's calling _add_view with view_name set to type(self).__name__ (i.e. InstantAPI) for the generic JSON RPC endpoint for both instances of InstantAPI, and they conflict. So I made a subclass with a different name. So finally my code looks like this:

class InstantApi2(InstantAPI):
    pass

InstantAPI(app, path="/api1/", swagger_kwargs={"config": {"endpoint": "foo"}, "merge": True})(Methods)
InstantApi2(app, path="/api2/")(Methods2)

That seems to work 😄 Does it work for you?

But of course that's confusing and inconvenient and difficult to figure out, instead of instant. A PR making this easier for other users would be good.

@vstkl
Copy link
Author

vstkl commented Jun 2, 2022

Yeah works for me too! Thank you! anyway I might try to make it more obvious for other users, the merge true was the thing I was missing! I haven't figured out how to get apidocs with multiple endpoints, I assume it will be merged somehow?

@alexmojaki
Copy link
Owner

http://127.0.0.1:5000/apidocs/ shows everything combined in one page for me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants