axnsan12 / drf-yasg Goto Github PK
View Code? Open in Web Editor NEWAutomated generation of real Swagger/OpenAPI 2.0 schemas from Django REST Framework code.
Home Page: https://drf-yasg.readthedocs.io/en/stable/
License: Other
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
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!
Allow Schemas to be output into the definitions sections of the Swagger object, and generate definition references instead of inline models.
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
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.
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?
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. :)
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.
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!
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.
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.
Allow declarative customization via decorators for:
Hi, It seems that drf-yasg doesn't support hiding serializers.HiddenField's yet? A hidden field in my serializer is showing up in the example data and model docs.
It looks like this is a known issue due to this TODO -
drf-yasg/src/drf_yasg/inspectors/field.py
Line 472 in 9ad55ba
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)?
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?
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
?
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).
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'))])
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 :).
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), ])
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?
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.
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.
SlugRelatedField format isn't detected for readonly fields - see original_group in dd16247.
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.
I was wondering is there anyway to add an Example Object to the Response Object? I also see it is in the openapi.py.
I looked through the code and when I manually set Responses it's generate an Open API response at https://github.com/axnsan12/drf-yasg/blob/master/src/drf_yasg/inspectors/view.py#L234
Is there anyway to get it to set the example? If not I am willing to figure out how to get it working.
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?
Steps to reproduce:
manage.py startproject
, add "drf_yasg"
to INSTALLED_APPS
.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'),
]
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
How I set to get response and request from serializer_class not model?
All my endpoints is showing from the models.
Firstly, this is incredibly hard to debug, as no info about where this happens, one has to use a debugger to find out.
Secondly, this is just wrong. It shouldn't be up to the swagger generator to decide whether a regular expression will end up being correct. And, even if it was, it should be, at best, a warning.
The test project is very simplistic and there are currently no automated tests.
Should probably fix that.
See http://django-rest-swagger.readthedocs.io/en/stable-0.3.x/yaml.html
Sometimes it can be easier to specify overrides in docstrings rather than code - for example, complex Schema
, Parameter
or Response
objects. It could be worth looking into also being able to supply swagger_auto_schema
overrides as YAML in view docstrings.
We had two PatientSerializer
s 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)
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:
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!
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
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 ?
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.
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.
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?
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"
}
}
},
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'"}
Marshmallow is a Schema module for django rest framework.
It can be used instead of DRF Serializers but is not supported by drf-yasg.
It'd be nice to have it.
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
Please share detailed License information.
Tested on the example project "testproj".
Steps:
.lookup_field
attribute on the view correctly.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?
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:
write_only
and allow_null
serializer fields via new Schema propertiesThere 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:
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.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.