Skip to content
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

Function views are not included in the auto documentation #5343

Closed
hnykda opened this issue Aug 20, 2017 · 12 comments
Closed

Function views are not included in the auto documentation #5343

hnykda opened this issue Aug 20, 2017 · 12 comments

Comments

@hnykda
Copy link
Contributor

hnykda commented Aug 20, 2017

Besides traditional ListCreateAPIView, I also have function based views using @api_view decorator. Unfortunately, these are not picked up in the generated documentation. They are, however, present in the schema.

Steps to reproduce

Write function view, open docs.

Expected behavior

Function views should be present in the generated documentation. DRF docs or Swagger for DRF can pick them as as expected.

Actual behavior

Views are not present.

Or am I missing something? Thanks

@carltongibson
Copy link
Collaborator

@hnykda I need a bit more to go on here. 🙂

What's your URL conf etc? — is the function view nested? — What does, the relevant part of, the schema look like? Can you narrow this down to the smallest example?

Thanks.

@hnykda
Copy link
Contributor Author

hnykda commented Aug 21, 2017

Sorry. Should have be more specific.

URL confs

Main urls in project/urls.py:

from django.conf.urls import url, include
from django.contrib import admin

api_urls = [
    url(r'^campaign/', include('campaign.urls', namespace='campaign')),
]
urlpatterns = [
    url(r'^api/', include(api_urls)),
]

includes these campaign/urls.py

from django.conf.urls import url
from .views import CampaignListCreateAPIView, CampaignDetailAPIView, my_function_view

urlpatterns = [
    url(r'^$', CampaignListCreateAPIView.as_view(), name="list"),
    url(r'^(?P<pk>[0-9]+)/$', CampaignDetailAPIView.as_view(), name="detail"),
    url(r'my_function_view/(?P<cid>[0-9]+)/$', my_function_view.as_view(), name='my_function_view'),
]

Views

and the function view itself is not nested:
campaign/views.py

@api_view(http_method_names=['GET'])
@permission_classes((IsAdminUser,))
def my_function_view(request, cid):
    campaign = Campaign.objects.get(cid=cid)
    datamap = campaign.get_datamap()
    return Response({'datamap': datamap})

@carltongibson
Copy link
Collaborator

They are, however, present in the schema.

But what's the relevant part of the schema? You said my_function_view appears?

If it's nested under campaigns it won't show for 3.6.3, but should for master, and 3.6.4, which is coming today. Can you try running from master?

@hnykda
Copy link
Contributor Author

hnykda commented Aug 21, 2017

Ahh, you mean nested inside an app? Yes, they are under campaigns. I will try master then.

@hnykda
Copy link
Contributor Author

hnykda commented Aug 21, 2017

It displays in master! It is quite weird though.

E.g. here:
image
For admin/configmap endpoint, I am using @api_view(http_method_names=['GET', 'POST']), it is listed as list and create, which is quite confusing, since this view has nothing to do with listing objects or creating them. Also, interaction doesn't work at all (nothing happens after clicking on Send).

Thanks! Is there a way how to override this? What is the proper way of writing non-object related views in DRF?

@carltongibson
Copy link
Collaborator

Well, it's good it shows.

Also, interaction doesn't work at all (nothing happens after clicking on Send).

OK. Can you help diagnose that? Is there an error in the JS console for instance? (@woile: could there be a lingering issue in the JS data-* attribute binding?)

...it is listed as list and create, which is quite confusing, since this view has nothing to do with listing objects or creating them.

This is just to do with how the SchemaGenerator introspects the view. It's designed to handle the ViewSet case, so it's just making assumptions which don't apply here.

Is there a way how to override this?

Well, you can subclass SchemaGenerator, but it's a bit in-flexible at the moment. #5337 will make this easier on a per-view basis.

@woile
Copy link
Contributor

woile commented Aug 21, 2017

I'll check it out. If we had the js errors from the console it would be great.

@carltongibson carltongibson mentioned this issue Aug 21, 2017
13 tasks
@carltongibson
Copy link
Collaborator

OK. I cannot reproduce an issue here.

With a class-based view, nested and displayed using master the interactive API works as expected.

@hnykda — you're dealing with function-based views right. I'm guessing that the introspection doesn't give enough to build the request. i.e. Without a get_serializer the introspection will not know the request fields.

@woile
Copy link
Contributor

woile commented Aug 21, 2017

@carltongibson I tried reproducing with api_view, permission_classes but I don't see any issue, maybe he has cached the assets (js files).

He is right in the naming convention though, I don't know if list, create, etc should be rendered as titles always. There are some (edge) cases in which restful verbs are not used. I'm thinking different approaches to solve this:

  • Define a setting to choose what type of title to use.
    • Represent title like most of the other doc tools: METHOD + URL
      screenshot from 2017-08-21 19-19-13
    • Represent title in a restful way (LIST, CREATE, etc...)
  • Set titles using docstrings, or make everything customizable with docstrings
def my_custom_action(self...):
    """
    get: new title here
    comment for get in method

    post: new title here
    description
    """

@carltongibson
Copy link
Collaborator

@woile: Thanks for the follow-up! (It really helps.)

The rigidity of the naming is known. (e.g. #5165 and others). #5337 should allow flexibility, without settings (shudder 🙂) or the need to parse docstrings. (The strategy will be to use coreapi schema objects directly — it's declarative and precise — but without needing to specify the entire schema by hand.) I'd be grateful if you could follow along there.

@hnykda: Thanks for the report and your follow-up!

I'm going to close this as ultimately I think it's a usage issue rather than anything particular. Yes, there are still teething issues with the schema generation but I think we need to review after the next phase.

Please stay involved: feedback and input is really important. (If it's a usage question the Mailing List is the best place; if it's a bug then here.)

Thanks again.

@hnykda
Copy link
Contributor Author

hnykda commented Aug 23, 2017

Hey! Thank you for such a quick response! Sorry for a delay from my side.

Yes, I am using function views. And yes - after trying in an Chrome anonymous window or Firefox, it works as expected - so it was probably cached somehow. Again, sorry.

I really like @woile idea about settings, where we could just have a METHOD + URL definition instead REST. You mentioned that there are edge cases. I am curious - how else do you do a non-model related API endpoints, e.g. "run a service job which updates some assets somewhere" and so on? AFAIK, class based API views are to rigid for that, hence the function views.

@carltongibson
Copy link
Collaborator

@hnykda Thanks for the follow-up.

I am curious - how else do you do a non-model related API endpoints, e.g. "run a service job which updates some assets somewhere" and so on? AFAIK, class based API views are to rigid for that, hence the function views.

In this case you extend views.APIView rather than generics.GenericAPIView or any of it's subclasses. APIView allows you to provide a get or post (or whatever) without making any of the model based assumptions of GenericAPIView. (Under the hood, the @api_view decorator converts function-based views to APIView subclasses.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants