Coder Social home page Coder Social logo

ergo / pyramid_apispec Goto Github PK

View Code? Open in Web Editor NEW
23.0 3.0 9.0 98 KB

Pyramid plugin for openapi spec generation (using ApiSpec)

License: BSD 3-Clause "New" or "Revised" License

Python 69.66% HTML 30.34%
pyramid-framework python swagger openapi openapi-specification rest-api restful-api

pyramid_apispec's Introduction

pyramid_apispec

pyramid_apispec allows you to create an OpenAPI specification file using apispec and an online OpenAPI explorer using the Swagger UI project for your Pyramid application and its marshmallow schemas.

Installation

pip install pyramid_apispec

Basic usage

Check out the demo folder and minimal application example by running:

pip install -e '.[demo]'
python demo/app.py

You can then visit your API explorer page at http://0.0.0.0:6543/api-explorer.

Or visit generated documentation here for an example of the demo site. (please note that actual REST API is not working in GitHub pages)

Note: The demo site is using OpenAPI/Swagger v2.0. OpenAPI 3.0 is supported as well, it just uses a different YAML schema so pay attention to examples online.

Example

This example is based on apispec, adapted for Pyramid and pyramid_apispec (updated as of apispec v5.1.0).

This example is using OpenAPI 3.0.2

Hinting a route and its view:

Add the OpenAPI YAML to the view docstring. Optionally use Marshmallow schemas to define the inputs and outputs.

import uuid

from marshmallow import Schema, fields
from pyramid.view import view_config

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

class PetSchema(Schema):
    categories = fields.List(fields.Nested(CategorySchema))
    name = fields.Str()

@view_config(route_name="random_pet", renderer="json")
def random_pet(request):
    """A cute furry animal endpoint.
    ---
    get:
      description: Get a random pet
      security:
        - ApiKeyAuth: []
      responses:
        200:
          description: Return a pet
          content:
            application/json:
              schema: PetSchema
    """
    # Hardcoded example data
    pet_data = {
        "name": "sample_pet_" + str(uuid.uuid1()),
        "categories": [{"id": 1, "name": "sample_category"}],
    }
    return PetSchema().dump(pet_data)

For more details on how to document the API, see the OpenAPI specification.

Rendering the spec as JSON response:

from apispec import APISpec
from apispec.ext.marshmallow import MarshmallowPlugin
from pyramid.view import view_config
from pyramid_apispec.helpers import add_pyramid_paths

@view_config(route_name="openapi_spec", renderer="json")
def api_spec(request):
    """View to generate the OpenAPI JSON output."""
    spec = APISpec(
        title="Some API",
        version="1.0.0",
        openapi_version="3.0.2",
        plugins=[MarshmallowPlugin()],
    )

    # Optional security scheme support
    api_key_scheme = {"type": "apiKey", "in": "header", "name": "X-API-Key"}
    spec.components.security_scheme("ApiKeyAuth", api_key_scheme)

    # Optionally register Marshmallow schema for more flexibility
    spec.components.schema("Pet", schema=PetSchema)

    # inspect the `random_pet` route and generate operations from docstring
    add_pyramid_paths(spec, 'random_pet', request=request)

    return spec.to_dict()

Adding the API Explorer View

To complement the specification file generation, this package can also provide an API explorer for your application's API via the Swagger UI project:

config.include("pyramid_apispec.views")
config.add_route("openapi_spec", "/openapi.json")
config.pyramid_apispec_add_explorer(spec_route_name="openapi_spec")

By default you need to pass the route name of the view that serves the OpenAPI specification in your application. If needed you can specify a Pyramid permission or custom callable (script_generator argument) to override the default JavaScript configuration of Swagger UI.

The default URL for the explorer is /api-explorer. This setting is controlled via the explorer_route_path argument - the route is registered as pyramid_apispec.api_explorer_path.

Running tests

pip install -e '.[dev]'
tox

pyramid_apispec's People

Contributors

debonzi avatar ergo avatar jellonek avatar pagenoare avatar smsearcy avatar stevepiercy avatar timgates42 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

Watchers

 avatar  avatar  avatar

pyramid_apispec's Issues

Redoc UI

Is it possible to change the UI of default swagger and use Redoc?

Does this SwaggerUI supports swagger format 3.0.0?

I have a situation where I need to user swagger format 3.0.0, can I still use this SwaggerUI integration? Because a valid file(compiles fine in the swagger editor) is not being compiled in my pyramid application SwaggerUI. I'm missing some configuration?

Unable to generate API specification using marshmallow schema containing field having type as list/array of String eg. myfield = [“str1”,”str2”]. My Marshmallow version=3.6.1

I am unable to create / generate API specification using marshmallow schema containing field having type as list/array of String.

Details : My local version details -

"pyramid_apispec==0.3.3", "marshmallow==3.6.1 , pyramid==1.10.4 , python == 3.7.3"

My code looks like :

import marshmallow
from marshmallow import fields, validate

class BaseSchema(marshmallow.Schema):
class Meta:
strict = True
ordered = True

class MyCustomSchema(BaseSchema) :
app_ids = fields.List(fields.String())

Here when I tried to access api specification http://localhost:8080/api-explorer . I got following error –

File "d:\saurabh\june-venv\lib\site-packages\apispec\core.py", line 143, in schema
ret.update(plugin.schema_helper(name, component, **kwargs) or {})
File "d:\saurabh\june-venv\lib\site-packages\apispec\ext\marshmallow_init_.py", line 169, in schema_helper
json_schema = self.openapi.schema2jsonschema(schema_instance)
File "d:\saurabh\june-venv\lib\site-packages\apispec\ext\marshmallow\openapi.py", line 657, in schema2jsonschema
jsonschema = self.fields2jsonschema(fields, partial=partial, ordered=ordered)
File "d:\saurabh\june-venv\lib\site-packages\apispec\ext\marshmallow\openapi.py", line 681, in fields2jsonschema
property = self.field2property(field_obj)
File "d:\saurabh\june-venv\lib\site-packages\apispec\ext\marshmallow\openapi.py", line 433, in field2property
ret["items"] = self.field2property(field.container)
AttributeError: 'List' object has no attribute 'container'

Example in README doesn't work with apispec >= 2.0.0

The docstring example for the response schema in README.md does not work with the current master branch because apispec changed how to reference schemas in apispec 2.0. When using the example format of $ref: "#/definitions/BarBodySchema" I get the following error:

Could not resolve reference because of: Could not resolve pointer: /definitions/BarBodySchema does not exist in document".

Per the upgrade docs (and my testing) I think the docstring should look like this:

@view_config(route_name='foo_route', renderer='json')
def foo_view():
    """A greeting endpoint.

    ---
    x-extension: value
    get:
        description: some description
        responses:
            200:
                description: response for 200 code
                content:
                    application/json:
                        schema: BarBodySchema
    """
    return 'hi'

Support routes with regular expression

pyramid_apispec don't handle routes with regular expression. For example:

config.add_route('resource.item', '/api/resource/{id:\d+}')

Swagger UI produces the following curl:

curl -X DELETE "http://localhost:6544/api/resource/{id:\d+}" -H "accept: application/json"

Different views based on match_param predicates are not documented separately

When a route pattern includes placeholders that are used as predicates in a view's match_param, this means there can be multiple view functions with different documentation and unique URLs, however currently only one view's documentation is loaded and the path documented with APISpec includes placeholders the end user likely does not know about.

For example, the following route and views would currently only document as a single endpoint (/foo/{id}/{view}) when I think it should document two endpoints (/foo/{id}/bar and /foo/{id}/baz).

config.add_route("foo", "/foo/{id}/{view}")

@view_config(route_name="foo", match_param="view=bar")
def foo_bar(request):
    """
    ---
    description: bar a foo
    """

@view_config(route_name="foo", match_param="view=baz")
def foo_baz(request):
    """
    ---
    description: baz a foo
    """

Edit: Grammar/clarity

Schema exemple render not working properly

Hi,

I'm having trouble with the schema example rendering, where I have a field that is a Oneof type of schema, the json generation is working properly, because in the swagger editor it is being rendered properly, however in the api-explorer is not working as should be. I'm using the latest version of the project.

The Schema:

Screenshot from 2021-03-10 09-42-04

The example rendered:

Screenshot from 2021-03-10 09-42-34

The example rendered in the swagger editor:

Screenshot from 2021-03-10 09-42-58

The json generated:

{"paths": {"/api/v1/state/{session}": {"put": {"parameters": [{"name": "session", "in": "path", "required": true, "schema": {"type": "string"}, "description": "session parameter"}], "tags": ["Browser Remote Storage"], "summary": "Session Put", "description": "\n    Inserts the payload into a section\n    for the logged user.\n    ", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/BaseLoanRequestSchema"}}}}, "responses": {"400": {"description": "", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/BaseResponseErrors"}}}}, "200": {"description": "Json return without any schema pattern", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/JsonResponse"}}}}}}}}, "info": {"title": "Browser Remote Storage", "version": "4.0.0", "description": "\n        Storage for non structured data separated by sessions and by the user id inside auth_tkt\n        cookie.\n        "}, "openapi": "3.0.2", "components": {"schemas": {"Company": {"type": "object", "properties": {"type": {"type": "string", "default": "type: company"}, "cnpj": {"type": "string"}}, "required": ["cnpj", "type"]}, "Person": {"type": "object", "properties": {"type": {"type": "string", "default": "type: person"}, "cpf": {"type": "string"}}, "required": ["cpf", "type"]}, "Borrower": {"type": "object", "properties": {}, "oneOf": [{"$ref": "#/components/schemas/Company"}, {"$ref": "#/components/schemas/Person"}], "discriminator": {"propertyName": "type", "mapping": {"company": "#/components/schemas/Company", "person": "#/components/schemas/Person"}}}, "BaseLoanRequestSchema": {"type": "object", "properties": {"borrower": {"$ref": "#/components/schemas/Borrower"}, "uuid": {"type": "string", "format": "uuid", "readOnly": true}, "requestor": {"$ref": "#/components/schemas/Person"}}}, "BaseResponseErrors": {"type": "object", "properties": {"errors": {"type": "array", "items": {"type": "object"}}, "status": {"type": "string"}}}, "JsonResponse": {"type": "object", "properties": {}}}, "securitySchemes": {"AuthTkt": {"type": "cookie", "in": "header"}}}, "servers": [{"url": "http://0.0.0.0:8080"}]}

New release?

Can you create a new release? That way I don't have to maintain a vendored copy of the match_param changes. :)

As an aside, are you agreeable to dropping Python 2.x support?

apispec beta tag issue

It looks like most versions of pyramid_apispec are pulling the latest build of apispec which is (in this particular case) causing code to break even if bound to a specific version of pyramid_apispec.

Specifically the replacement of spec.definition() to spec.components.schema()
and
spec.add_path() to spec.path().

In relation to the current documentation and APISpec object.

Could you bind to a specific stable version of apispec to correct the issue?

Overwriting paths in the spec

Hey there! 😊
I wondered whether it would be possible to overwrite the paths that are currently taken from the decorator to something self-defined..

My problem is that my path is path='/api/exercises/{exercise_id:\d+}/{user_id:(\d+)+\/?}' but that should be kinda internal and I would like to overwrite this with path='/api/exercises/{exercise_id}/{user_id}' so I do not need to show my regex matches to the API user.

From the OpenAPI 2.0 standard:

paths:
  /users: <-- this 
    get:
      summary: Returns a list of users.

Currently this does not seem to be possible, atleast not from what I have tried... 😄
I would therefore suggest adding interpretion for the parameter path like this:

"""
---
path: 
  /api/exercises/{exercise_id}/{user_id}:
     get:
      tags:
        - "My API"
      summary: "return an exercise for given student"
      description: ""
      operationId: "exercise_student_get"
      produces:
        - "application/json"
      responses:
        200:
          description: successfull return of the exercise
          schema:
            $ref: "#/definitions/ExerciseStudent"
"""

Would that be possible?
All the best
Chris

Integration with Cornice

Hi @ergo ,

thank you very much for that lib. I integrated it nicely working into a playground project, rendered it with a different yaml lib

    # this requires `apispec==1.0.0b3`
    spec = APISpec(title="Some API", version="1.0.0", openapi_version='3.0.0', plugins=[MarshmallowPlugin()])
    # you can further mutate the spec dict to include things like security definitions
    my_spec = spec.to_dict()
    return Response(pyaml.dump(my_spec, safe=False, force_embed=False, vspacing=[2, 1], string_val_style='"'))

convert that output via widdershins

widdershins \
				--headings 4 \
				--resolve true \
				--search false \
				--language_tabs \
					'shell:Bash' \
					'javascript:JavaScript' \
					'python:Python' \
					'ruby:Ruby' \
					'java:Java' \
				--outfile var/index.html.md \
				--verbose \
				--expandBody true \
				var/openapi_direct.yaml

and put that index.html.md into Slate. Much wow ;)

Now I integrated it into my real project, which is using Cornice. Unfortunately this does not seem as an easy pick.

# Cornice `service.name` becomes `route_name` of Pyramid
c1_login_service = Service(name='c1_login',
                           path='/auth',
                           description='Validate a JWT and create a session for us.')

@c1_login_service.post(accept='application/json',
                       schema=PostJwtSchema,
                       validators=(body_validator,),
                       require_csrf=False)
def checkout_authentication(request):
    """
    Validate a JWT and create a session for us

    ---
    x-extension: value
    post:
      # headline/name of the resource (renders as `h2`)
      ...

I can register that route, but the docblock is not being read.

Do you have any guess, or hint where to go?

Cheers

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.