Code Monkey home page Code Monkey logo

falcon-apispec's Introduction

falcon-apispec

Build Status codecov PyPI License: MIT

apispec plugin that generates OpenAPI specification (aka Swagger) for Falcon web applications.

Apispec uses three sources of information. Basic information is directly given to APISpec(). The plugin reads information about paths from the Falcon app. Information about an object could be given by marshmallow specification

Installation

pip install falcon-apispec

Optionaly:

pip install marshmallow

Works with apispec v1.0+.

Example Application

from apispec import APISpec
from apispec.ext.marshmallow import MarshmallowPlugin
import falcon
from falcon_apispec import FalconPlugin
from marshmallow import Schema, fields


# Optional marshmallow support
class CategorySchema(Schema):
    id = fields.Int()
    name = fields.Str(required=True)

class PetSchema(Schema):
    category = fields.Nested(CategorySchema, many=True)
    name = fields.Str()


# Create Falcon web app
app = falcon.API()

class RandomPetResource:
    def on_get(self, req, resp):
        """A cute furry animal endpoint.
        ---
        description: Get a random pet
        responses:
            200:
                description: A pet to be returned
                schema: PetSchema
        """
        pet = get_random_pet()  # returns JSON
        resp.media = pet

# create instance of resource
random_pet_resource = RandomPetResource()
# pass into `add_route` for Falcon
app.add_route("/random", random_pet_resource)


# Create an APISpec
spec = APISpec(
    title='Swagger Petstore',
    version='1.0.0',
    openapi_version='2.0',
    plugins=[
        FalconPlugin(app),
        MarshmallowPlugin(),
    ],
)

# Register entities and paths
spec.components.schema('Category', schema=CategorySchema)
spec.components.schema('Pet', schema=PetSchema)
# pass created resource into `path` for APISpec
spec.path(resource=random_pet_resource)

Generated OpenAPI Spec

spec.to_dict()
# {
#   "info": {
#     "title": "Swagger Petstore",
#     "version": "1.0.0"
#   },
#   "swagger": "2.0",
#   "paths": {
#     "/random": {
#       "get": {
#         "description": "A cute furry animal endpoint.",
#         "responses": {
#           "200": {
#             "schema": {
#               "$ref": "#/definitions/Pet"
#             },
#             "description": "A pet to be returned"
#           }
#         },
#       }
#     }
#   },
#   "definitions": {
#     "Pet": {
#       "properties": {
#         "category": {
#           "type": "array",
#           "items": {
#             "$ref": "#/definitions/Category"
#           }
#         },
#         "name": {
#           "type": "string"
#         }
#       }
#     },
#     "Category": {
#       "required": [
#         "name"
#       ],
#       "properties": {
#         "name": {
#           "type": "string"
#         },
#         "id": {
#           "type": "integer",
#           "format": "int32"
#         }
#       }
#     }
#   },
# }

spec.to_yaml()
# definitions:
#   Pet:
#     enum: [name, photoUrls]
#     properties:
#       id: {format: int64, type: integer}
#       name: {example: doggie, type: string}
# info: {description: 'This is a sample Petstore server.  You can find out more ', title: Swagger Petstore, version: 1.0.0}
# parameters: {}
# paths: {}
# security:
# - apiKey: []
# swagger: '2.0'
# tags: []

Contributing

Setting Up for Local Development

  1. Fork falcon-apispec on Github
  2. Install development requirements. Virtual environments are highly recommended
pip install -r requirements.txt

Running Tests

pytest

falcon-apispec's People

Contributors

alysivji avatar catherinedevlin avatar dillonco avatar henryh9n avatar jitka avatar synapticarbors avatar theghosthucodes avatar xakiy avatar xtaje avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

falcon-apispec's Issues

Can this be used with py2swagger?

Hello,

I'm very unaware and my question might actually be quite stupid, but is this usable with py2swagger or do I need to implement the creation of the apispec in my python code?

Thanks in advance !

TypeError: unhashable type

Hi,

when I pass my Falcon resource to apispec I got this error:

    loginResource = LoginResource(user_service)
    deviceResource = DeviceResource()
    api.add_route('/api/login', loginResource)
    api.add_route('/api/devices', deviceResource)

    # Create an APISpec
    from apispec import APISpec
    from apispec.ext.marshmallow import MarshmallowPlugin
    from falcon_apispec import FalconPlugin

    spec = APISpec(
        title='Swagger Backend API',
        version='1.0.0',
        openapi_version='2.0',
        plugins=[
            FalconPlugin(api),
            MarshmallowPlugin(),
        ],
    )

    # pass created resource into `path` for APISpec
    spec.path(resource=deviceResource)
$ python -u test.py
Traceback (most recent call last):
  File "test.py", line 214, in <module>
    spec.path(resource=deviceResource)
  File "C:\Work\Analytics\git\test\falcon-test\.venv\lib\site-packages\apispec\core.py", line 347, in path
    path=path, operations=operations, parameters=parameters, **kwargs
  File "C:\Work\Analytics\git\test\falcon-test\.venv\lib\site-packages\falcon_apispec\falcon_plugin.py", line 30, in path_helper
    resource_uri_mapping = self._generate_resource_uri_mapping(self._app)
  File "C:\Work\Analytics\git\test\falcon-test\.venv\lib\site-packages\falcon_apispec\falcon_plugin.py", line 23, in _generate_resource_uri_mapping
    mapping[resource] = uri
TypeError: unhashable type: 'LoginResource'

which is not on the resource I have added...
Any idea ?

Thanks!

Always getting: One or more HTTP methods are invalid

apispec.exceptions.APISpecError: One or more HTTP methods are invalid: connect, update, websocket, move, copy, checkout, propfind, trace, lock, report, uncheckin, version-control, proppatch, mkcol, checkin, unlock

code

class HealthCheck:
    def on_get(self, req, resp):
        """A cute furry animal endpoint.
        ---
        description: Get a random pet
        responses:
            200:
                description: A pet to be returned
                schema: PetSchema
        """
        resp.status = falcon.HTTP_200
        resp.body = json.dumps({"status": resp.status, "message": "healthy"})

Fixed http invalid

apispec.exceptions.APISpecError: One or more HTTP methods are invalid: unlock, report, copy, move, trace, checkout, update, lock, websocket, mkcol, checkin, connect, propfind, proppatch, uncheckin, version-control
Fixed by chaning method_handler.dict.get("module") to "falcon.responders": method_handler.module == "falcon.responders":

Add support for suffix="collection" routes

Falcon allows defining one resource class that provides multiple routes:

  suffix (str): Optional responder name suffix for this
                route. If a suffix is provided, Falcon will map GET
                requests to ``on_get_{suffix}()``, POST requests to
                ``on_post_{suffix}()``, etc. In this way, multiple
                closely-related routes can be mapped to the same
                resource. For example, a single resource class can
                use suffixed responders to distinguish requests for
                a single item vs. a collection of those same items.
                Another class might use a suffixed responder to handle
                a shortlink route in addition to the regular route for
                the resource.

Is there a way to have these routes appear in the generated spec?

Does this work with falcon 3.0.0?

I recently upgraded from falcon 2.0.0 to 3.0.0 and started getting a bunch of errors thrown from the apispec library.

For comparison, without touching my code, this environment works without issue:

falcon 2.0.0
falcon-apispec 0.4.0
apispec 4.4.0

...and this environment produces the errors shown below:

falcon 3.0.0
falcon-apispec 0.4.0
apispec 4.4.0
src/my_service/app.py:246: in create_app
    spec.path(resource=falcon_resource)
.tox/py38/lib/python3.8/site-packages/apispec/core.py:304: in path
    self.clean_operations(operations)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <apispec.core.APISpec object at 0x7f444c404ca0>
operations = OrderedDict([('get', {'summary': 'Get whether the service is alive or not.', 'parameters': [], 'responses': {200: {}}}...', {}), ('report', {}), ('uncheckin', {}), ('unlock', {}), ('update', {}), ('version-control', {}), ('websocket', {})])

    def clean_operations(self, operations):
        """Ensure that all parameters with "in" equal to "path" are also required
        as required by the OpenAPI specification, as well as normalizing any
        references to global parameters. Also checks for invalid HTTP methods.
    
        See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#parameterObject.
    
        :param dict operations: Dict mapping status codes to operations
        """
        operation_names = set(operations)
        valid_methods = set(VALID_METHODS[self.openapi_version.major])
        invalid = {
            key for key in operation_names - valid_methods if not key.startswith("x-")
        }
        if invalid:
>           raise APISpecError(
                "One or more HTTP methods are invalid: {}".format(", ".join(invalid))
            )
E           apispec.exceptions.APISpecError: One or more HTTP methods are invalid: lock, websocket, mkcol, proppatch, move, uncheckin, unlock, checkin, propfind, version-control, checkout, connect, copy, report, update

Autogenerate method respoces.

Hi,

I am using this library and I am happy whit it, but I would like to propose an improvement.

My doc strings become quite long and see two ways to shorten them.

  1. I use a lot of parameters across many functions. I do not like copy-pasting:
      - in: query
        name: deleted
        description: Filter active or deleted authors
        required: false
        type: boolean

Is there any way how to put this information to variable and use it in that docstring?

  1. Responses could be read in code.
    I would like to search source code of function for falcon.HTTP_404 and similar and add it too responses read form function docstring. This probably don't cover all cases since this error could be renamed but I believe this could help. Would you accept a pull request with it?

POST vs. GET Schema

Is there a way to provide different schemas, 1 for POST and 1 for GET
for instance there maybe a case when you want to POST without ids
and when you GET, you get an object with an ID or some other internal fields like date_created

Add support for suffix="collection" routes (Ref #18)

@hharutyunyan the issue now is that only one path per resource is mapped. All paths should be mapped for a given resource since that's why suffixes were added to Falcon in the first place.

I'm thinking calls to spec.path for multiple paths should look like:

spec.path('/accounts', resource=accounts)
spec.path('/accounts/{account_id}', resource=accounts)

And the plugin should be more like:

class FalconPlugin(BasePlugin):
    """APISpec plugin for Falcon"""

    def __init__(self, app):
        super(FalconPlugin, self).__init__()
        self._app = app

    @staticmethod
    def _generate_resource_uri_mapping(app):
        routes_to_check = copy.copy(app._router._roots)

        mapping = {}
        for route in routes_to_check:
            uri = route.uri_template
            resource = route.resource
            if resource not in mapping:
                mapping[resource] = {}
            if uri not in mapping[resource]:
                mapping[resource][uri] = {}

            if route.method_map:
                for method_name, method_handler in route.method_map.items():
                    if method_handler.__dict__.get("__module__") == "falcon.responders":
                        continue
                    mapping[resource][uri][method_name.lower()] = method_handler

            routes_to_check.extend(route.children)
        return mapping

    def path_helper(self, path, operations, resource, base_path=None, **kwargs):
        """Path helper that allows passing a Falcon resource instance."""
        resource_uri_mapping = self._generate_resource_uri_mapping(self._app)
        if resource not in resource_uri_mapping:
            raise APISpecError("Could not find endpoint for resource {0}".format(resource))
        if path not in resource_uri_mapping[resource]:
            raise APISpecError("Could not find path {0} for resource {1}".format(path, resource))

        operations.update(yaml_utils.load_operations_from_docstring(resource.__doc__) or {})

        if base_path is not None:
            # make sure base_path accept either with or without leading slash                            
            # swagger 2 usually come with leading slash but not in openapi 3.x.x                         
            base_path = '/' + base_path.strip('/')
            path = re.sub(base_path, "", path, 1)

        methods = resource_uri_mapping[resource][path]

        for method_name, method_handler in methods.items():
            docstring_yaml = yaml_utils.load_yaml_from_docstring(method_handler.__doc__)
            operations[method_name] = docstring_yaml or dict()
        return path

Originally posted by @chretienmn in #18 (comment)

example not working - missing dependency

Hi,

I am using Fedora 31, Python 3.7.7

I install falcon-apispec by pip

$ pip install falcon-apispec
Requirement already satisfied: falcon-apispec in /home/jitka/.env/taxonomy/lib/python3.7/site-packages (0.4.0)
Requirement already satisfied: falcon in /home/jitka/.env/taxonomy/lib/python3.7/site-packages (from falcon-apispec) (2.0.0)
Requirement already satisfied: apispec>=1.0 in /home/jitka/.env/taxonomy/lib/python3.7/site-packages (from falcon-apispec) (3.3.0)
Requirement already satisfied: PyYAML>=3.10 in /home/jitka/.env/taxonomy/lib/python3.7/site-packages (from falcon-apispec) (5.3)

and run example from readme and got:

Traceback (most recent call last):
  File "swagger.py", line 2, in <module>
    from apispec.ext.marshmallow import MarshmallowPlugin
  File "/home/jitka/.env/taxonomy/lib64/python3.7/site-packages/apispec/ext/marshmallow/__init__.py", line 74, in <module>
    from .common import resolve_schema_instance, make_schema_key, resolve_schema_cls
  File "/home/jitka/.env/taxonomy/lib64/python3.7/site-packages/apispec/ext/marshmallow/common.py", line 7, in <module>
    import marshmallow
ModuleNotFoundError: No module named 'marshmallow'

I add it manually pip install marshmallow and it solves the problem and example is working.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.