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

Can't create servers object using APISpec class #534

Closed
dariofaccin opened this issue Feb 4, 2020 · 13 comments · Fixed by #628
Closed

Can't create servers object using APISpec class #534

dariofaccin opened this issue Feb 4, 2020 · 13 comments · Fixed by #628
Labels

Comments

@dariofaccin
Copy link

As per specification, the "servers" object type should be an array/list. This is an example:

servers:
- url: https://localhost

To translate this in apispec, I should add the following parameter to the class:

servers=[{
    "url": "https://localhost"
}]

However, the class APISpec only allows objects of type dictionary for **options.
In any IDE this results in a warning about wrong type.
I solved the issue modifying line 184 of core.py in this way:

:param dict|list options: Optional top-level keys
@lafrech
Copy link
Member

lafrech commented Feb 4, 2020

I don't get it. options is a dict, not a list.

options = {
    "servers": [{"url": "https://localhost"}, ]
}

Unless the type provided for kwargs should be understood as the type of the arguments, not of the kwargs dict itself?

On one hand, kwargs is always a dict, so specifying the type is not so useful. On the other hand, you can't really specify the type of the kwargs themselves since each argument can have its own type.

Is this documented anywhere?

@dariofaccin
Copy link
Author

Using

options = {
"servers": [{"url": "https://localhost"}, ]
}

the generated yaml contains the following:

options:
  servers:
  - url: https://localhost

which is obviously not correct, since there should not be the options key.

@lafrech
Copy link
Member

lafrech commented Feb 4, 2020

Can you please paste here the instantiation of APISpec in your code?

@dariofaccin
Copy link
Author

Here it is.

def gen_spec():
    spec = APISpec(
        title="My API Documentation",
        version="1.0.0",
        openapi_version="3.0.2",
        info={
            'description': 'A description',
            'x-logo': dict(url="images/test.png"),
        },
        servers=[{
            "url": "https://localhost",
        }]
    )

@lafrech
Copy link
Member

lafrech commented Jul 10, 2020

Can't reproduce.

Here's what I get with your code:

{'info': {'description': 'A description',
          'title': 'My API Documentation',
          'version': '1.0.0',
          'x-logo': {'url': 'images/test.png'}},
 'openapi': '3.0.2',
 'paths': OrderedDict(),
 'servers': [{'url': 'https://localhost'}]}

Closing for now. Please comment if you want to add clarification.

@lafrech lafrech closed this as completed Jul 10, 2020
@vigen-b
Copy link

vigen-b commented Jan 14, 2021

Question remains unanswered. Do you have clean solution for this?

@vigen-b
Copy link

vigen-b commented Jan 14, 2021

Seems more cleaner way is this

import yaml
from apispec import APISpec
from apispec.ext.marshmallow import MarshmallowPlugin
from apispec.utils import validate_spec

OPENAPI_SPEC = """
openapi: 3.0.2
info:
  description: Server API document
  title: Server API
  version: 1.0.0
servers:
- url: http://localhost:{port}/
  description: The development API server
  variables:
    port:
      enum:
      - '3000'
      - '8888'
      default: '3000'
"""

settings = yaml.safe_load(OPENAPI_SPEC)
# retrieve  title, version, and openapi version
title = settings["info"].pop("title")
spec_version = settings["info"].pop("version")
openapi_version = settings.pop("openapi")

spec = APISpec(
    title=title,
    version=spec_version,
    openapi_version=openapi_version,
    plugins=(MarshmallowPlugin(),),
    **settings
)

source is here

@lafrech
Copy link
Member

lafrech commented Jan 14, 2021

Which part of the question is unanswered? I get the correct result with the code the OP posted.

What's wrong with this code and how is yours cleaner? You seem to prefer the YAML form, which is fine. I don't use YAML and I'm happy with the dict form. Both are acceptable. What's the issue?

@vigen-b
Copy link

vigen-b commented Jan 14, 2021

the question is how to pass the settings as an array (because from the spec it should be an array) if the APISpec expects dictionary. With your example inspection tools show warning Expected type 'dict', got 'List[Dict[str, str]]' instead

@vigen-b
Copy link

vigen-b commented Jan 14, 2021

and yes, results are the same

@lafrech
Copy link
Member

lafrech commented Jan 14, 2021

OK so my understanding is that when documenting kwargs, we wrote

:param dict options: Optional top-level keys

because options is a dict (by nature, since it is kwargs). This is not really helpful since kwargs are always dicts.

It seems that the type applies not to options but to its elements, which would only make sense if all elements were of the same type. Or if we specified all possible types as suggested in OP but then that wouldn't be very precise either because not all options can be lists or dicts.

I guess our best move is to just remove the type indication, isn't it?

:param options: Optional top-level keys

And check we didn't do the same elsewhere in the code.

I searched a bit on the Internet and didn't find any definitive answer.

@sloria @Bangertm any opinion about this?

@lafrech lafrech reopened this Jan 14, 2021
@Bangertm
Copy link
Collaborator

I don't have any specific thoughts, but tend to agree with you that removing the type indication is the best way to go.

@lafrech
Copy link
Member

lafrech commented Jan 16, 2021

Should be fixed in #628.

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

Successfully merging a pull request may close this issue.

4 participants