Skip to content

codectl/apispec-plugins

Repository files navigation

apispec-plugins

PyPI version CI codecov OpenAPI Specification 2/3 compatible Python compatibility code style: black license: MIT

APISpec plugins for easy integration with different components (web frameworks, packages, etc).

Features

  • Support for the OpenAPI Specification (versions 2 and 3)
  • Support for frameworks/plugins which include:
    • apispec_plugins.webframeworks.flask
    • apispec_plugins.ext.pydantic

Installation

Install the package directly from PyPI (recommended):

$ pip install apispec-plugins

Plugin dependencies like flask and pydantic are not installed with the package by default. To have flask and pydantic installed, run:

$ pip install apispec-plugins[flask,pydantic]

Example Usage

from typing import Optional

from apispec import APISpec
from apispec_plugins.base.mixin import RegistryMixin
from apispec_plugins.ext.pydantic import PydanticPlugin
from apispec_plugins.webframeworks.flask import FlaskPlugin
from flask import Flask
from pydantic import BaseModel


# set APISpec plugins
spec = APISpec(
    title="Pet Store",
    version="1.0.0",
    openapi_version="3.0.3",
    info=dict(description="A minimal pet store API"),
    plugins=(FlaskPlugin(), PydanticPlugin()),
)


# optional Flask support
app = Flask(__name__)


# optional pydantic support
class Pet(BaseModel, RegistryMixin):
    id: Optional[int]
    name: str


@app.route("/pet/<petId>")
def pet(petId):
    """Find pet by ID.
    ---
    get:
        parameters:
            - in: path
              name: petId
        responses:
             200:
                 description: display pet data
                 content:
                     application/json:
                         schema: Pet
    """
    return f"Display pet with ID {petId}"

    # register `path` for the Flask route
    with app.test_request_context():
        spec.path(view=pet)

Alternatively, to Flask routes, MethodView can be used:

from flask.views import MethodView


class PetAPI(MethodView):
    def get(self, petId):
        # get pet by ID
        pass


app.add_url_rule("/pet/<petId>", view_func=PetAPI.as_view("pet_view"))

Dynamic specs

As seen so far, specs are specified in the docstring of the view or class. However, with the spec_from decorator, one can dynamically set specs:

from apispec_plugins import spec_from


@spec_from(
    {
        "parameters": {"in": "path", "name": "petId"},
        "responses": {200: {"description": "display pet data"}},
    }
)
def pet(petID):
    """Find pet by ID."""
    pass

Why not apispec-webframeworks?

The conceiving of this project was based on apispec-webframeworks. While that project is focused on integrating web frameworks with APISpec, this project goes a step further in providing the best integration possible with the APISpec standards. Some limitations on that project were also addressed, like:

  • a path cannot register no more than 1 single rule per endpoint;
  • limited docstring spec processing;

Tests & linting 🚥

Run tests with tox:

# ensure tox is installed
$ tox

Run linter only:

$ tox -e lint

Optionally, run coverage as well with:

$ tox -e coverage

License

MIT licensed. See LICENSE.