-
Notifications
You must be signed in to change notification settings - Fork 265
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature Request: Support for custom versioning classes #650
Comments
Hi @TauPan
not quite sure why it is at the end of the page. query/accept versioning should not impact the endpoint ordering afaik. there are 3 ways to achieve versioning with spectacular:
redoc has no mechanics for this i think so you are stuck with path('api/schema-v1/', SpectacularAPIView.as_view(), name='schema-v1'),
path('api/schema/redoc-v1/', SpectacularRedocView.as_view(url_name='schema-v1'), name='redoc'),
path('api/schema-v2/', SpectacularAPIView.as_view(), name='schema-v2'),
path('api/schema/redoc-v2/', SpectacularRedocView.as_view(url_name='schema-v2'), name='redoc'), for SwaggerUI thinks are way better: SPECTACULAR_SETTINGS = {
"SWAGGER_UI_SETTINGS": """{
deepLinking: true,
displayOperationId: true,
persistAuthorization: true,
urls: [{url: "/api/schema/?version=v1", name: "version 1"}],
presets: [SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset],
layout: "StandaloneLayout",
}""",
} Just use the topbar layout like that and add more entries to
why is that? I have not followed though because the OP was happy with it. Is it a bug? can you provide more context here?
i think we can relax the condition if that helps, i.e. |
Thanks for your hints. They do help a great deal! In fact if I derive my Versioning class from AcceptHeaderVersioning directly and use QueryParameterVersioning as an aggregate it just works so I can continue customising the replies. With b535caa the "Try out" button would even work, I guess. (Currently it doesn't.) And since the version is set via urls.py or swagger, respectively, I don't need my workaround for the default version either, since in that case there will always be an explicit version. In summary there doesn't seem to be a need to support custom version classes beyond what is already possible for me. Sorry for being confused. |
As a posterity note: Since I wanted to keep the way of passing version in the query parameters at least in the redoc view, I decided to override from drf_spectacular.plumbing import get_relative_url, set_query_parameters
from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView
from drf_spectacular.utils import extend_schema
from rest_framework.response import Response
from rest_framework.reverse import reverse
class MyRedocView(SpectacularRedocView):
@extend_schema(exclude=True)
def get(self, request, *args, **kwargs):
schema_url = self.url or get_relative_url(reverse(self.url_name, request=request))
schema_url = set_query_parameters(schema_url, lang=request.GET.get('lang'), version=request.GET.get('version'))
return Response(
data={
'title': self.title,
'dist': self._redoc_dist(),
'schema_url': schema_url,
},
template_name=self.template_name
)
urlpatterns += [
path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
# Optional UI:
path('doc/', MyRedocView.as_view(url_name='schema'), name='doc'),
] I'm still deciding if I want to keep redoc or swagger so I might do something similar to adapt |
nice one. that should work. you could do that for imho swagger-ui is superior to redoc. more customization options, a lot more features and finally it's also easier to read. |
I think I may have overlooked the "schema" tab in the endpoint. At least with b535caa it's there. All schemas are repeated again at the end of the page. Also I came up with a more terse version of the code from #650 (comment) (boilerplate omitted): class MyRedocView(SpectacularRedocView):
@extend_schema(exclude=True)
def get(self, request, *args, **kwargs):
ret = super().get(request, *args, **kwargs)
ret.data['schema_url'] = set_query_parameters(
ret.data['schema_url'],
version=request.GET.get('version'))
return ret And this won't break things if a later version of drf-spectacular adds more parameters to the schema url. (I'd personally still prefer adding a method |
eases subclassing redoc/swagger views with custom behavior
django will escape & if used without filter and thus breaks url params concat inside JS contexts. For HTML this is not an issue. "safe" filter ignored this but is likely too broad, which was the reason for the change. "escapejs" is specifically for this usecase.
should never happen. maybe you have custom hooks that duplicate stuff? factoring out this probably makes your custom view obsolete I suppose. |
I'm migrating slowly to drf-spectacular in a branch and I still have several schemas from drf_yasg in place as well as JSONSchema which was added by hand (but was ignored by drf-yasg) so it's likely that there is still some duplicate stuff. I'll know when I've gone through the tedious manual work of converting all the annotations to drf-spectacular, which is feasible thanks to your detailed migration guide.
It does, thanks! :) I've noticed that the swagger view also gets the version passed through, but it seems to be ignored by swagger ui if I add |
our yasg migration was rather easy since the decorators are very closely related, but I can see that it takes longer the first time doing it. When more tricks from the yasg feature-set were used it makes this more complicated of course.
yes. swagger-ui ignores our prepared parameter also make sure that the parameters (?) precede the fragment (#):
I have tested both cases with the master branch and it works as expected for me. |
ok small clarification: you can use the topbar. you just cannot pass |
Woah! That definitely works and the links to the versions I put in my description also work... Excellent! 🥳 |
I have an application that uses AcceptHeaderVersioning in production but it has been migrated from no versioning at all.
In order to not break existing clients, we have the following
REST_FRAMEWORK
settings:Some endpoints are available in version 1 and 2 and some are only available in version 1 (or no version given) and if the client always sends version 2, it will receive version 1 for endpoints that only support version 1. (And yes, since you'll be asking, the plan is to migrate those version 1 views directly to version 3 in case we want to change them... So each client expects "their" api version.)
I've tried to migrate that application from drf-yasg to drf-spectacular, since we already use JSONSchema for some views so support for openapi 3 would be a definite win for us. (Our JSON Schemata are even displayed in the swagger ui with drf-spectacular, but at the end of the page, and not at all in redoc... I think some other issue points that out as well.)
Unfortunately setting
DEFAULT_VERSION
is not compatible with the fix for #637, as the OP has pointed out.Since giving an Accept Header is pretty inconvient in the browser (in redoc as well as the browsable DRF API), we have a custom versioning class that accepts
QueryParameterVersioning
as well asAcceptHeaderVersioning
although the latter is required in production. This just works indrf_yasg
(although we had problems customising the documentation for other parts of the api which may be easier in drf-spectacular).If I disable the custom class and just use
AcceptHeaderVersioning
, I can generate the correct schema for each version on the command line and in the schema view, if I monkey-patchmodify_media_types_for_versioning
to change the media type for the default version as well, however it's not clear to me how to switch versions in swagger or redoc. (But maybe I simply overlooked something.)Also probably being able to override a workflow method on a subclass would be a cleaner approach than having to monkey patch a function in
plumbing.py
.So what are your thoughts on this?
The text was updated successfully, but these errors were encountered: