Code Monkey home page Code Monkey logo

axnsan12 / drf-yasg Goto Github PK

View Code? Open in Web Editor NEW
3.3K 31.0 432.0 22.69 MB

Automated generation of real Swagger/OpenAPI 2.0 schemas from Django REST Framework code.

Home Page: https://drf-yasg.readthedocs.io/en/stable/

License: Other

Python 65.46% JavaScript 32.52% HTML 1.59% Shell 0.17% CSS 0.24% Procfile 0.02%
django-rest-swagger django-rest-framework django swagger swagger-codegen swagger-ui redoc documentation-generator coreapi openapi

drf-yasg's People

Contributors

amoki avatar axnsan12 avatar blueyed avatar brianhelba avatar bryant1410 avatar carlfarrington avatar elliott-omosheye avatar etene avatar grumbling-tom avatar hysios avatar jamim avatar joellefkowitz avatar johnthagen avatar ko-pp avatar mofr avatar mpwang avatar pahaz avatar paulway avatar petrdlouhy avatar quozd avatar rafalolszewski94 avatar rsichnyi avatar terencehonles avatar therefromhere avatar ticosax avatar tijuca avatar tuky avatar xiaohanzhang avatar ychab avatar ymyzk 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  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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 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

drf-yasg's Issues

Add 'tags' in openapi.swagger

Hi,
I want use SwaggerMarkup(https://github.com/Swagger2Markup/swagger2markup-maven-project-template) to convert a Swagger specification into PDF, but it failed when I try to build with the json file which generated via drf-yasg. The failure reason is that the json file has no field 'tags', the specific field list all endpoint names and it is different from a subfield of get/put/patch/delete. It is shown as below.
1

I think adding field β€˜tags’ in openapi.swagger to list all endpoint names is clearer to users and the generated Swagger specification after modified will be satisfied with some SwaggerTools. Some modified codes are shown as below.

  1. Define a new Class Tags in openapi.py
  2. Add a new parameter 'tags' in openapi.Schema
    2
  3. Define a new function to get tags in generators.OpenAPISchemaGenerator
  4. Add tags when calling openapi.Swagger in generators.OpenAPISchemaGenerator.get_schema

Add support for different read/write schemas

A pain point that often exists with automatic swagger specs with DRF is they reuse the same definition for retrieve/list/post endpoints. This leads to painful client side SDKs generated with swagger-codegen as most/all fields on the resulting model will be optional, requiring SDK consumers to litter their code with null checks (or ignore them at their peril).

A motivating example of this problem is the id field that most django models will have. This field is required on reads (the model will always have an id when retrieving/listing) but a read_only field for creates (not required for post requests). Another example would be a field that is derrives from a null=False model field (required at the DB level) but is not required at the API level (perhaps it's generated by the server's business logic).

Can (does) drf-yasg's inspection of serializers find these characteristics and if so, can it be shown in the resulting spec by defining multiple definitions for a serializer and referencing them appropriately in spec paths?

For context, our team generates SDKs for our APIs in many type safe languages and model definitions such as:

MyModel:
    type: object
    required:
        - name
    properties:
        id:
            type: number
        name:
            type: string

are a headache to use because the resulting model will label id as optional, meaning it must be checked before being passed to other SDK methods that expect a value. E.g.

interface MyModel {
    id?: number;
    name: string;
}

// ...

api.updateMyModel({ id: instance.id }) // compilation error because `.id` might be undefined

Schema properties documented as list, but dict can be more suitable

Here, Schema's properties is documented as being a list of child Schemas and SchemaRefs. But using something like properties=[Schema('foo', ...)] results in documentation showing {'0': ...}, as in the property key is an incrementing integer. If you give it a dictionary that goes against the documentation, it works better: properties={'foo': Schema(...)} results in {'foo': ...} in the documentation.

I'm not too knowledgeable on OpenAPI in general but should the documentation show that dict is also acceptable? Or does it work by accident?

JWT Bearer token authentication

I tried setting up my Access token in the Authorize field. It didn't work. When I check the curl request there is no header parameter for Authorization. Can someone tell me how to add Bearer Token Auth?

Add missing tests

  • add tests for all Field types
  • cleanup coverage reports to reduce noise (exclude defensive checks, etc)
  • add tests for settings
  • check for other missing tests

Field with callable default value generates an invalid schema

Hi @axnsan12, cool project! I tried it out in https://github.com/yunity/karrot-backend and stumbled upon this error:

TypeError: Object of type 'CurrentUserDefault' is not JSON serializable
(full stacktrace)

One of our serializers uses DRFs CurrentUserDefault like this:

class FeedbackSerializer(serializers.ModelSerializer):
    class Meta:
        model = FeedbackModel
        fields = ['given_by']
        extra_kwargs = {'given_by': {'default': serializers.CurrentUserDefault()}}

When enabling validation, flex throws this error:

flex.exceptions.ValidationError: 'definitions':
    - 'Feedback':
        - 'properties':
            - 'properties':
                - 'given_by':
                    - 'default':
                        - "The value of `default` must be of one of the declared types for the schema. `CurrentUserDefault()` is not one of `['string']`"
    - 'User':
        - 'default':
            - "The value of `default` must be of one of the declared types for the schema. `CurrentUserDefault()` is not one of `['object']`"

Is it feasible to add support for CurrentUserDefault into drf-yasg?

OpenAPI 3 support

The latest version of the OpenAPI specification has some interesting new features and could be worth implementing. A great overview of new stuff can be found here: https://blog.readme.io/an-example-filled-guide-to-swagger-3-2/

It would enable support for some features we cannot currently represent:

There are also improvements like support for anyOf and oneOf, more complete security schemes, operation links and other goodies.

On the other hand, there are some considerations:

  1. it is significantly more complex than OpenAPI 2.0
  2. it would require non-trivial changes to both public interfaces and internal code
  3. supporting both 2.0 and 3.0 at the same time is a bit complicated, so 2.0 would probably have to be dropped
  4. many tools do not yet support 3.0 - the spec itself was just released in September 2017

So, as of now, this is mostly a statement of intent and personal observations - I do not have any plans of starting work on this in the foreseeable future, and certainly not until the tooling situation improves.

Strange Behavior of class docstrings

Hi,

i get to see a strange behavior when it comes to the display of a class docstring in the swagger UI.

The first Docstring where it occurs looks like this :
"""
This is a Filter Endpoint. It allows to filter it's Resource according to the
databasefields an their values.
Providing a field and it's value to filter by just use the common GET syntax.

This Means :
    * url\?\<first_fieldname\>\=value1\&\<second_fieldname\>\=value2

Resource:
    * MineralType

Fields available for this Resource are:
    trivial_name, systematics, variety, minerals,
    mohs_scale, density, streak, normal_color,
    fracture, cleavage, lustre, chemical_formula,
    other, resource_mindat, resource_mineralienatlas

Note to filter for systematics one needs this 'translations':
   * EL = Elements
   * SF = Sulfides & Sulfosalts
   * HG = Halogenides
   * OH = Oxides and Hydroxides
   * CN = Carbonates and Nitrates
   * BR = Borates
   * SL = Sulfates
   * PV = Phosphates, Arsenates & Vanadates
   * SG = Silicates & Germanates
   * OC = Organic Compounds

"""

When this Docstring gets converted only the last enumeration gets rendered, by markdown, with the normal "dots"

like this.

BUT: The first two do not get converted which looks quite strange. Am I doing anything wrong here ?

The next point is : The blank lines are ignored ?!

Thanks in advance.

Questions re: DRF renderer_classes

We use djangorestframework-camel-case and set our views' renderer_classes to CamelCaseJSONRenderer.

Because of this our Swagger/OpenAPI output differs from the actual output; a field specified as staff_member is represented as staffMember in the view output but incorrectly as staff_member in the Swagger output.

What's the best way to remedy this, and are you interested in remedying it within this project? (If not, I could always post-process the output myself).

ImportError raised when using DRF 3.7.3.

import drf_yasg.generators raises following ImportError when the version of Django Rest Framework is 3.7.3.

/usr/lib/python3.6/site-packages/drf_yasg/generators.py in <module>()
      7 from django.utils.encoding import force_text
      8 from rest_framework import versioning
----> 9 from rest_framework.compat import URLPattern, URLResolver, get_original_route
     10 from rest_framework.schemas.generators import EndpointEnumerator as _EndpointEnumerator
     11 from rest_framework.schemas.generators import SchemaGenerator, endpoint_ordering

ImportError: cannot import name 'URLPattern'

To solve this, you must use DRF>=3.7.4.

Assertion error when trying to visit the page

Hello

Thanks for the great project! I am trying to get it working with my current setup but am running into the following error

AssertionError at /redoc/
#/definitions/Nested already exists

I think the error has got something to do with how I have defined my ViewSets because it goes away when I remove some of my viewsets from the router.register() option in urls.py

I hope I have explained this well enough?

Problem adding Model to definitions

Using a simplified serializer for a list view with a limited set of fields does not get a model added to definitions. We get this error instead.

Resolver error at paths./customers-search/.get.responses.200.schema.items.$ref
Could not resolve reference because of: Could not resolve pointer: /definitions/SimpleCustomerSerializerV1 does not exist in document

    @swagger_auto_schema(
        manual_parameters=[search_query_param],
        responses={
            status.HTTP_200_OK: openapi.Response(
                'Customers found.',
                serializers.SimpleCustomerSerializerV1(many=True)),
            status.HTTP_404_NOT_FOUND: 'No matching customers found.',
            status.HTTP_429_TOO_MANY_REQUESTS: 'Rate limit exceeded.',
            status.HTTP_500_INTERNAL_SERVER_ERROR: 'Internal error.',
            status.HTTP_504_GATEWAY_TIMEOUT: 'Request timed out.',
        })
    def list(self, request, *args, **kwargs):

If we remove the custom response for 200, the default behavior works as expected and does generate the model in definitions. The code is very hard to trace to figure out what is going on here.

Cannot manually represent a Response without setting a schema?

Not sure if this is a bug, or if I'm just not reading the docs correctly:

I have a view that returns a '204 No Content' status, with a header that returns some relevant information, and no response body. I want to correctly represent this in my API documentation, so I'm doing something like this:

class MyView(APIView):
    @swagger_auto_schema(
        responses={
            "204": openapi.Response(
                description="Your request was accepted, perform status queries using the value of the X-Query-ID header for updates",
                 headers={
                     "X-Query-ID": {
                         "description": "The ID of the accepted query",
                         "type": openapi.TYPE_STRING
                     }
                 }
             )
         }
    )
    def post(self, request, ...):

However this fails with the following trace:

Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/drf_yasg/openapi.py", line 99, in __getattr__
    return self[make_swagger_name(item)]
KeyError: 'schema'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner
    response = get_response(request)
  File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 187, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 185, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/local/lib/python3.6/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
    return view_func(*args, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/django/views/generic/base.py", line 68, in view
    return self.dispatch(request, *args, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/rest_framework/views.py", line 494, in dispatch
    response = self.handle_exception(exc)
  File "/usr/local/lib/python3.6/site-packages/rest_framework/views.py", line 454, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/usr/local/lib/python3.6/site-packages/rest_framework/views.py", line 491, in dispatch
    response = handler(request, *args, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/drf_yasg/views.py", line 88, in get
    schema = generator.get_schema(request, self.public)
  File "/usr/local/lib/python3.6/site-packages/drf_yasg/generators.py", line 203, in get_schema
    paths, prefix = self.get_paths(endpoints, components, request, public)
  File "/usr/local/lib/python3.6/site-packages/drf_yasg/generators.py", line 317, in get_paths
    operations[method.lower()] = self.get_operation(view, path, prefix, method, components, request)
  File "/usr/local/lib/python3.6/site-packages/drf_yasg/generators.py", line 357, in get_operation
    operation = view_inspector.get_operation(operation_keys)
  File "/usr/local/lib/python3.6/site-packages/drf_yasg/inspectors/view.py", line 38, in get_operation
    responses = self.get_responses()
  File "/usr/local/lib/python3.6/site-packages/drf_yasg/inspectors/view.py", line 161, in get_responses
    responses=self.get_response_schemas(response_serializers)
  File "/src/lib/ucee-django-utils/ucee_django_utils/schema.py", line 25, in get_response_schemas
    resp_schemas = super().get_response_schemas(response_serializers)
  File "/usr/local/lib/python3.6/site-packages/drf_yasg/inspectors/view.py", line 224, in get_response_schemas
    if not isinstance(response.schema, openapi.Schema.OR_REF):
  File "/usr/local/lib/python3.6/site-packages/drf_yasg/openapi.py", line 102, in __getattr__
    raise AttributeError("object of class " + type(self).__name__ + " has no attribute " + item)
AttributeError: object of class Response has no attribute schema
[22/Feb/2018 13:45:45] "GET /_internal/auth/schema HTTP/1.0" 500 17194

It works if I set the schema kwarg on the Response (either with a serializer or a manually created Schema instance; setting it to no_body doesn't work). As far as I can tell I should be able to specify a Response without a Schema (I can if I set the value of the responses dict to a string)?

Parameters should use description instead of title

The drf-yasg generates object definitions, where the parameters use "title" attribute (example shown below). I believe this goes against the swagger v2 specification and it should be called "description" instead.

"Login": {
      "required": [
        "password"
      ],
      "type": "object",
      "properties": {
        "username": {
          "title": "Username",
          "type": "string"
        },
        "email": {
          "title": "Email",
          "type": "string",
          "format": "email"
        },
        "password": {
          "title": "Password",
          "type": "string"
        }
      }
    },

Provide consumes and produces at the root of the schema

Hey,

I would like to provide a list of types that the API consumes and produces at the root of the schema but I didn't find the way to achieve it...

The only way I found is to modify the get_schema method of OpenAPISchemaGenerator se it looks like this:

consumes = ['application/vnd.api+json']
produces = ['application/vnd.api+json']
return openapi.Swagger(
    info=self.info, paths=paths,
    _url=url, _prefix=prefix, _version=self.version,
    consumes=consumes, produces=produces,
    **dict(components)
)

Is there a way to achieve it without modifying the code, as a setting for example ?

Update README and add real docs

  • update README and setup.py descriptions
  • add sphinx documentation
  • upload to readthedocs
  • add docs build target
  • add source code documentation to classes and methods where possible

Write some tests

The test project is very simplistic and there are currently no automated tests.

Should probably fix that.

"type" mismatch with "enum" contents

I'm attempting to generate a go client based on an openapi spec for the open source netbox API using drf-yasg. Some fields are ending up with a mismatch between their type fields and enum fields in the generated spec.

The effected fields all use the choices keyword param to map non-string values to a list of labels. There are several examples, some with integer as the underlying type and some with boolean:
InterfaceTemplate.form_factor
PowerPort.connection_status
Rack.width

netbox makes use of serializers to have three different projections of each Django model, the standard model, a nested model when it appears in another object and a writable model for PUTs, POSTs and PATCHes. This means that each of the above fields could appears in multiple places in the generated swagger, normally at least the writable and standard models.

For example:
standard rack
writable rack

In practice, the standard model includes a small sub-object with both the integer and string values:

      "width": {
        "value": 19,
        "label": "19 inches"
      }

While the writable model expects only the value for the field. Width becomes a flat integer:

      "width": 19

Would support for this style of usage be possible?

Path parameter is not overrided

In the viewset, I add swagger_auto_schema decorator to destroy(self, request, pk=None) method, to override the id path parameter and add descriptions. But in the swagger UI, both of them are showing as path parameters.

@swagger_auto_schema(manual_parameters=[ openapi.Parameter('id', openapi.IN_PATH, description="Instrument Id to be removed from watchlist, if exist", type=openapi.TYPE_STRING, required=True), ])
image

KeyError: 'title' on schema generation

Hi and thank you for this nice lib!

When I follow the basic startup tuto, the doc pages (swagger, json and redoc) fail with the following error

  File "/home/amoki/.../.v_env/lib/python3.6/site-packages/drf_yasg/inspectors/field.py", line 100, in field_to_swagger_object                                                               
    return make_schema_definition()                
  File "/home/amoki/.../.v_env/lib/python3.6/site-packages/drf_yasg/inspectors/field.py", line 96, in make_schema_definition                                                                 
    del result.title                               
  File "/home/amoki/.../.v_env/lib/python3.6/site-packages/drf_yasg/openapi.py", line 109, in __delattr__                                                                                    
    del self[make_swagger_name(item)]              
KeyError: 'title'     

A simple try/except around the failing line works without problem

    def __delattr__(self, item):
        if item.startswith('_'):
            super(SwaggerDict, self).__delattr__(item)
            return
        try:
            del self[make_swagger_name(item)]
        except:
            for key in self.keys():
                print(key)
            print(self)
            print(item)

And the output is

required
type
properties
Schema([('required', ['checker']), ('type', 'object'), ('properties', OrderedDict([('id', Schema([('title', 'ID'), ('type', 'integer'), ('readOnly', True)])), ('error_detail', Schema([('title', 'Error det
ail'), ('type', 'string')])), ('status', Schema([('title', 'Status'), ('type', 'string'), ('enum', ['C', 'P', 'E'])])), ('result', Schema([('title', 'Result'), ('type', 'string')])), ('collisions', Schema
([('title', 'Collisions'), ('type', 'string')])), ('created_at', Schema([('title', 'Created at'), ('type', 'string'), ('format', 'date-time'), ('readOnly', True)])), ('updated_at', Schema([('title', 'Upda
ted at'), ('type', 'string'), ('format', 'date-time'), ('readOnly', True)])), ('checker', Schema([('title', 'Checker'), ('type', 'integer')]))]))])
title
[django] INFO 2018-03-05 15:48:35,551 basehttp "GET /doc?format=openapi HTTP/1.1" 200 131602

Is there a problem with my view/serializer/model?

Thanks!

Second request to docs fails with AttributeError

Steps to reproduce:

  1. Create django project with manage.py startproject, add "drf_yasg" to INSTALLED_APPS.
  2. urls.py:
from django.conf.urls import url
from django.contrib import admin
from drf_yasg import openapi
from drf_yasg.views import get_schema_view
from rest_framework import permissions

urlpatterns = [
    url(r'^admin/', admin.site.urls),
]

schema_view = get_schema_view(
    openapi.Info(
        title="Snippets API",
        default_version='v1'
    ),
    public=True,
    permission_classes=(permissions.AllowAny,)
)

urlpatterns += [
    url(r'swagger/$', schema_view.with_ui('swagger', cache_timeout=None), name='schema-swagger-ui'),
    url(r'redoc/$', schema_view.with_ui('redoc', cache_timeout=None), name='schema-redoc'),
]
  1. Start a server with manage.py runserver, first page request correctly shows docs UI, second one fails with AttributeError (trace below)
[15/Dec/2017 11:26:52] "GET /redoc/?format=openapi HTTP/1.1" 200 219
Internal Server Error: /redoc/
Traceback (most recent call last):
  File "/code/mkurnikov/.virtualenvs/project_name/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner
    response = get_response(request)
  File "/code/mkurnikov/.virtualenvs/project_name/lib/python3.6/site-packages/django/core/handlers/base.py", line 187, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/code/mkurnikov/.virtualenvs/project_name/lib/python3.6/site-packages/django/core/handlers/base.py", line 185, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/code/mkurnikov/.virtualenvs/project_name/lib/python3.6/site-packages/drf_yasg/views.py", line 33, in _wrapped_view_func
    response = view_func(request, *args, **kwargs)
  File "/code/mkurnikov/.virtualenvs/project_name/lib/python3.6/site-packages/django/utils/decorators.py", line 141, in _wrapped_view
    result = middleware.process_request(request)
  File "/code/mkurnikov/.virtualenvs/project_name/lib/python3.6/site-packages/django/middleware/cache.py", line 137, in process_request
    response = self.cache.get(cache_key)
  File "/code/mkurnikov/.virtualenv/sproject_name/lib/python3.6/site-packages/django/core/cache/backends/locmem.py", line 54, in get
    return pickle.loads(pickled)
  File "/code/mkurnikov/.virtualenvs/project_name/lib/python3.6/site-packages/drf_yasg/openapi.py", line 190, in __init__
    self.info.version = _version or info._default_version
AttributeError: 'NoneType' object has no attribute '_default_version'

Django 1.11.7, Python 3.6.3, DRF 3.7.3

Request parameters example not changing for custom urls in ModelViewset

Hello

Sorry not sure if this is a bug or intended this way!

Basically I have a ModelViewSet which I set schema = AutoSchema()

However when I try add a custom function within the ModelViewSet, it does not update to the correct request input parameters in the docs.

class UploadViewSet(viewsets.ModelViewSet):
    """
    Model ViewSet handling user api calls
    """
    schema = AutoSchema()
    permission_classes = (UploadPermissions,)
    queryset = Upload.objects.all()
    serializer_class = UploadSerializer

    @list_route(
        methods=['POST'],
        schema=ManualSchema(fields=[
            coreapi.Field(
                "conditions",
                required=True,
                location="query",
                schema=coreschema.Object(),
                description='Conditions field',
                type='string',
                example='123'
            ),
            coreapi.Field(
                "expiration",
                required=True,
                location="query",
                schema=coreschema.String(),
                description='Expiration field',
                type='string',
                example='123'
            )
        ]),
        permission_classes=[],
        authentication_classes=[]
    )
    def handle_upload_request(self, request):
          ## Handle request here ###

In the swagger / redoc docs it shows all the urls correctly:

image

The default model viewset models show the request input data as

{started: 'string', name: 'string', type: 'string', priority: integer}

However when I check the request input data for my custom url it is the same as above. Instead I would expect it to be something along the lines of:

{condtions: 'string', expiration: 'string'}

Perhaps I am doing something wrong or this is not supported?

I hope I have explained this problem well. Thanks so much for the help!

For GET request, parsed parameters from request_body are presented as response body

View code

from drf_yasg.utils import swagger_auto_schema
from rest_framework import serializers
from rest_framework.views import APIView


class IndexViewSerializer(serializers.Serializer):
    username = serializers.CharField()


class IndexView(APIView):
    @swagger_auto_schema(request_body=IndexViewSerializer)
    def get(self, request):
        pass

swagger spec generated

{
    "swagger":"2.0",
    "info":{
        "title":"Snippets API",
        "version":"v1"
    },
    "host":"localhost:8000",
    "schemes":[
        "http"
    ],
    "basePath":"/",
    "paths":{
        "/index/":{
            "get":{
                "operationId":"index_list",
                "description":"",
                "parameters":[

                ],
                "responses":{
                    "200":{
                        "description":"",
                        "schema":{
                            "type":"array",
                            "items":{
                                "$ref":"#/definitions/IndexView"
                            }
                        }
                    }
                },
                "consumes":[
                    "application/json"
                ],
                "tags":[
                    "index"
                ]
            },
            "parameters":[

            ]
        }
    },
    "definitions":{
        "IndexView":{
            "required":[
                "username"
            ],
            "type":"object",
            "properties":{
                "username":{
                    "type":"string"
                }
            }
        }
    },
    "securityDefinitions":{
        "basic":{
            "type":"basic"
        }
    }
}

As a workaround, I assume, one should specify parameters as openapi.Parameter objects, like

username_param = openapi.Parameter('username', in_=openapi.IN_QUERY, description='Username',
                                   type=openapi.TYPE_STRING)


class IndexView(APIView):
    @swagger_auto_schema(manual_parameters=[username_param])
    def get(self, request):
        pass

which works just fine.

Management command?

It would be great to have a management command for generating the Swagger/OpenAPI JSON output so that I could do e.g. ./manage.py generate_swagger swagger.json.

I use the output from drf-yasg as the input to swagger-to-flowtype and this would make that process a little easier.

If you give me a pointer to how I might accomplish it I can take a stab at this myself and send a PR, assuming you're open to having it in drf-yasg. :)

Data object for request_body

Is it possible to get rid of "data" node in case when request structure is defined using "request_body" attribute?

screen shot 2018-01-15 at 16 04 04

oauth2 flow

Hi!

Thank you for this amazing package :).

We are implementing an oauth2 flow with Google and after converting token to our application. For that, we are using django-rest-framework-social-oauth2.

This is our SWAGGER_SETTINGS:

SWAGGER_SETTINGS = {
    "USE_SESSION_AUTH": False,
    "SECURITY_DEFINITIONS": {
        "api_key": {
            "type": "apiKey",
            "name": "access_token",
            "in": "header"
        },
        "google_oauth": {
            "type": "oauth2",
            "authorizationUrl": "http://127.0.0.1:8000/auth/login/google-oauth2",
            "flow": "implicit",
            "scopes": {
                "write:admin": "You are God",
                "read:customer": "You are a simple human"
            }
        }
    }
}

So when we click con "Authorize" button we introduce the client_id and the scope. After that, we are redirected to Google for login and then we are back to our swagger page but we are not authenticated. After Google authorization we need to convert token in order to be authenticated with our application but i don't know how to do that.

The flow is
GET /auth/login/google-oauth2/
GET /auth/login/google-oauth2/
GET /auth/complete/google-oauth2/
GET /

Can you please help me?

Thanks in advance :).

Hiding APIs that require authentication

I've setup DRF-YASG but it seems not able to hide APIs that require Authentication.

Below is the configuration.

public_apis = [ 
    # sample-end-point
    url(f'{URL_VERSION}/sample-end-point/', include(sample_end_point.urls)),  # requires authentication
]

  schema_view = get_schema_view(
      openapi.Info(
        title="Swagger Doc",
        default_version='v1',
        description="Test description",
        terms_of_service="https://www.google.com/policies/terms/",
        contact=openapi.Contact(email="[email protected]"),
        license=openapi.License(name="BSD License"),
      ),
      validators=['flex', 'ssv'],
      permission_classes=(permissions.AllowAny,), 
      public=False,
      patterns=public_apis,
  )

urlpatterns = public_apis + [

    url(r'^swagger(?P<format>.json|.yaml)$', schema_view.without_ui(cache_timeout=None), name='schema-json'),
    url(r'^swagger/$', schema_view.with_ui('swagger', cache_timeout=None), name='schema-swagger-ui'),
    url(r'^redoc/$', schema_view.with_ui('redoc', cache_timeout=None), name='schema-redoc'),
]

With the above configuration, the sample-end-point does not appear on the SwaggerUi. It only shows the Authorize Button and text that says No operations defined in spec!. But if I change thepublic=False to public=True setting, the sample-end-point appears. But that is not what I want as this URL should be accessible only after one logs in.

Is there something am not understanding or a setting am missing?

My Swagger settings are as below:

SWAGGER_SETTINGS = {
    'USE_SESSION_AUTH': False,
    'SECURITY_DEFINITIONS': {
        'api_key': {
            'type': 'apiKey',
            'in': 'header',
            'name': 'Authorization'
        }
    },
    'APIS_SORTER': 'alpha',
    'SUPPORTED_SUBMIT_METHODS': ['get', 'post', 'put', 'delete', 'patch'],
    'OPERATIONS_SORTER': 'alpha'
}

I'd posted the issue on Stack Overflow

Validation error on serializer used only for responses

Note: This may be what #51 was trying to get at...

Trying to do this, but getting a validation error ("... 'ssv': "Unresolvable JSON pointer: 'definitions/Detail'")

class DetailSerializer(serializers.Serializer):
    detail = serializers.CharField()

class ManufacturerViewSet(viewsets.ModelViewSet):

    serializer_class = ManufacturerSerializer
    model = Manufacturer
    queryset = Manufacturer.objects.all()

    @swagger_auto_schema(responses={404: openapi.Response("Not found or Not accessible", DetailSerializer,
                                                          examples={
                                                              'Not found': DetailSerializer({'detail':'Not found'}).data,
                                                              'Not accessible': DetailSerializer({'detail':'Not accessible'}).data,
                                                          },
                                                          )})
    def retrieve(self, request, *args, **kwargs):
        return super().retrieve(self, request, *args, **kwargs)

However, if I add the serializer to recognized model, it does work, e.g.,

class ManufacturerSerializer(serializers.ModelSerializer):

    status = DetailSerializer(many=False)

    class Meta:
        model = Manufacturer
        fields = '__all__'

Full text of validation error...

{'flex': "'paths':\n"
         "    - '/manufacturers/{id}/':\n"
         "        - 'get':\n"
         "            - 'responses':\n"
         "                - '404':\n"
         "                    - 'referenceObject':\n"
         "                        - 'additionalProperties':\n"
         '                            - "When `additionalProperties` is False, '
         'no unspecified properties are allowed. The following unspecified '
         "properties were found:\\n\\t`{'headers', 'description', 'examples', "
         '\'schema\'}`"\n'
         "                        - 'required':\n"
         "                            - '$ref':\n"
         "                                - 'This value is required'\n"
         "                    - 'responseObject':\n"
         "                        - 'schema':\n"
         "                            - '$ref':\n"
         "                                - 'The $ref `#/definitions/Detail` "
         "was not found in the schema'",
 'ssv': "Unresolvable JSON pointer: 'definitions/Detail'"}

Calling .get_object() inside .get_serializer_class() raises AssertionError

Tested on the example project "testproj".
Steps:

  1. In view SnippetDetail, commented out serializer_class.
  2. Added a method get_serializer_class, calling self.get_object() inside it
  3. Opened http://localhost:8000/swagger/
  4. AssertionError raised.
    Exception Type: AssertionError at /swagger/
    Exception Value: Expected view SnippetDetail to be called with a URL keyword argument named "pk". Fix your URL conf, or set the .lookup_field attribute on the view correctly.

TypeError: Decimal

getting this:
"TypeError: Object of type 'Decimal' is not JSON serializable"

for a model with such field:
rate = models.DecimalField(_('Rate'), max_digits=6, decimal_places=3, default=Decimal('0.0'), validators=[MinValueValidator(Decimal('0.0'))])

ReDoc failed to render this spec

if i add 'USE_SESSION_AUTH': False or 'SHOW_REQUEST_HEADERS': True to SWAGGER_SETTINGS i get page that said

Oops... ReDoc failed to render this spec can't assign to property "_displayType" on false: not an object

just want to ask, is this something that should not appear or its normal?

Allow declarative schema customization via decorators

Allow declarative customization via decorators for:

  • Path Item - View/ViewSet level
  • Operation object - method level
  • Parameter objects - method level
  • Response objects - method level
  • Schema objects - Serializer level

How to set headers on response returning an array

I have a custom pagination class MyPagination subclassed from PageNumberPagination that puts the count and links to the first, prev, next and last pages in headers on the response. The end point returns an array without an envelope object. I would like to include this in the swagger docs. This is as far as I've gotten:

class MyPaginatorInspector(inspectors.PaginatorInspector):
    def get_paginated_response(self, paginator, response_schema):
        assert response_schema.type == openapi.TYPE_ARRAY, "array return expected for paged response"
        paged_schema = None
        if isinstance(paginator, (MyPagination)):
            paged_schema = openapi.Schema(
                type=openapi.TYPE_ARRAY,
                items=response_schema,
                # The properties worked as long as type was openapi.TYPE_OBJECT
                properties=OrderedDict((
                    ('count', openapi.Parameter('number of elements in result',
                                                openapi.IN_HEADER, type=openapi.TYPE_INTEGER)),
                    ('first', openapi.Parameter('url to the first page in the result',
                                                openapi.IN_HEADER, type=openapi.TYPE_STRING)),
                    ('prev', openapi.Parameter('url to the previous page in the result',
                                               openapi.IN_HEADER, type=openapi.TYPE_STRING)),
                    ('next', openapi.Parameter('url to the next page in the result',
                                               openapi.IN_HEADER, type=openapi.TYPE_STRING)),
                    ('last', openapi.Parameter('url to the last page in the result',
                                               openapi.IN_HEADER, type=openapi.TYPE_STRING)),
                ))
            )

        return paged_schema

def get_list_schema_decorator():
    # ... snip
    return swagger_auto_schema(operation_description=operation_description,
                               manual_parameters=manual_parameters,
                               responses=responses,
                               paginator_inspectors=[MyPaginatorInspector]
                               )

but I get the error that "AssertionError at /swagger/: only object Schema can have properties".

Any pointers would be appreciated

Output Schemas into definitions

Allow Schemas to be output into the definitions sections of the Swagger object, and generate definition references instead of inline models.

  • Automatically output a single schema definition per serializer class
  • Allow forcing inline output

Rendering of nested routers in GUI

I stumbled upon this project when searching for documentation tools with support for nested routers. The example that you supply with the articles/{slug}/image is exactly what we use a lot in one of our API's.

In our case, we have several of these endpoints and in most cases each endpoint accepts 4 or 5 HTTP methods. So in the GUI, this is rendered as a huge list of endpoints, which is hard to work with.

Is there a way to group these endpoints as nested collections? So in your example, the image would get it's own heading, just like articles and snippets, but with a title like articles > images.

I hope my question makes sense. If you need more info please let me know.

Urls not correctly "currled"

Hi,

i encountered the following:

when clicking "try it out!" in one of my GET Endpoints the curl prompt beneath it states a wrong statement :curl -X GET "localhost://localhost:8000/api/myendpoint/(P101[0-9]+)" -H "accept: application/json" -H "X-CSRFToken: x4bdC0d9Chl2ZThQEpJCi1WzadO0NTIPVa5FXSqkIRvjJ9xvJvBzvZWZLvQ3viDC"

This is obviously a wrong behavior. The correct, and succesfull, curl should look like this :
curl -X GET "localhost:8000/api/myendpoint/101" -H "accept: application/json" -H "X-CSRFToken: x4bdC0d9Chl2ZThQEpJCi1WzadO0NTIPVa5FXSqkIRvjJ9xvJvBzvZWZLvQ3viDC"

my urls.py looks like this :

[...] url(r'^myendpoint/(?P<pk>[0-9]+)', myendpoint.as_view) [...]
This might be an "localhost" problem (I can not validate the issue for the production system, docs aren't online till now) , but still shouldn't ouccur.

Detect url scheme when behind proxy

I'm running Django behind a nginx-ingress as a proxy which also handles HTTPS termination. This leads to the problem that drf-yasg autodetecs HTTP scheme as the connection between Django and nginx is HTTP. Therefore the generated swagger file points to the HTTP scheme and the swagger-ui is not correctly working as the browser blocks mixed content requests.

Mixed Content: The page at 'https://www.example.com/api/swagger/' was loaded over HTTPS, but requested an insecure resource 'http:///www.example.com/api/user/'. This request has been blocked; the content must be served over HTTPS.

I don't want to set DEFAULT_API_URL as Django runs inside a container and this container does not and should not know the hostnames it serves or the upstream protocol behind proxy.

This could be resolved by using the X-Forwarded-Proto HTTP header, which is set by the upstream proxy, in the OpenAPISchemaGenerator class.

Can't use Serializer as Schema's object property

My APIView returns following object:

out = {
    "foo": FooSerializer(foo, many=True).data,
    "bar": BarSerializer(bar, many=True).data
}

Trying to represent that object by using Serializer references fails with TypeError: Object of type 'SerializerMetaclass' is not JSON serializable:

@swagger_auto_schema(responses={
    200: openapi.Response('OK', openapi.Schema(type=openapi.TYPE_OBJECT, properties={
        'foo': FooSerializer,
        'bar': BarSerializer
    })),
})

Additionally, I don't have these Serializers used anywhere else, so they don't register themselves as definitions, so following fails too:

@swagger_auto_schema(responses={
    200: openapi.Response('OK', openapi.Schema(type=openapi.TYPE_OBJECT, properties={
        'foo': openapi.SchemaRef(openapi.ReferenceResolver('definitions'), 'Foo'),
        'bar': openapi.SchemaRef(openapi.ReferenceResolver('definitions'), 'Bar')
    })),
})

Seems that in such case, defining the whole response structure is the only option, or am I missing some trick here?

Thanks!

Identically named serializers seem to confuse drf-yasg

We had two PatientSerializers defined in our project; one of them was used for both views in the Swagger output when in fact each view used a different PatientSerializer; my workaround was to rename one of them (probably best that they are not identically named, but still an issue that might bite someone else)

Schema default value not used

Trying to set a default value for a Schema inside of a Parameter. It does not seem to be getting picked up in Swagger when I use the "Try it out" functionality.

My schema looks like this:

    @swagger_auto_schema(
            operation_id="Get a mission plan",
            responses={
                200: 'test'},
            manual_parameters=[
                openapi.Parameter(
                    name='Organization',
                    in_=openapi.IN_HEADER,
                    description="Organization name",
                    required=True,
                    schema=openapi.Schema(
                        type=openapi.TYPE_STRING,
                        default="Organization 1",
                    )
                )
            ]
        )

Perhaps providing a more in depth example in testproj, that uses more of the OpenApi parameters, would be helpful. From what I read here it seems the example field should be used rather than default, but it does not seem to be an available field in the Schema class?

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.