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

Add test when simple view is interpreted as list view #20

Merged
merged 1 commit into from
Apr 8, 2020

Conversation

tsouvarev
Copy link
Contributor

@tsouvarev tsouvarev commented Apr 1, 2020

Spectacular uses is_list_view to determine whether view is listing or not. If it is then response is wrapped in array and operation ID has suffix _list.

is_list_view has some heuristics, and the last of them is to explode route and check if the last part is dynamic parameter like {id}.

So, if you have APIView with route that doesn't end with such parameter, you will end up with response serializer wrapped with array just because of the failed heuristic.

Thing is, spectacular uses 'is_list_view'
to determine whether view is listing or not.
If it is then response is wrapped in array
and operation ID has suffix '_list'.

'is_list_view' has some heuristics,
and the last of them is to explode route
and check if the last part is dynamic parameter like {id}.

So, if you have APIView with route
that doesn't end with such parameter,
you will end up with response serializer wrapped with array
just because of the failed heuristic!
@tsouvarev tsouvarev force-pushed the bug-with-list-view branch from 2ca6ced to f499dc4 Compare April 1, 2020 17:24
@tsouvarev
Copy link
Contributor Author

tsouvarev commented Apr 1, 2020

Diff of generated schema with reference file is the following:

 openapi: 3.0.3
  info:
    title: ''
    version: 0.0.0
  paths:
    /{id}/test/:
      get:
-       operationId: test_list
?                         ^ ^^
+       operationId: test_retrieve
?                         ^^^^ ^^^
        description: ''
        parameters:
        - in: path
          name: id
          schema:
            type: integer
          required: true
        tags:
        - test
        security:
        - {}
        responses:
          '200':
            content:
              application/json:
                schema:
-                 type: array
-                 items:
-                   $ref: '#/components/schemas/Alpha'
? --
+                 $ref: '#/components/schemas/Alpha'
            description: ''
- components:
    schemas:
      Alpha:
        type: object
        properties:
          field_a:
            type: string
          field_b:
            type: integer
        required:
        - field_a
        - field_b

@tfranzel tfranzel added the bug Something isn't working label Apr 1, 2020
@tfranzel
Copy link
Owner

tfranzel commented Apr 1, 2020

yes indeed that is a bug from the old code. i knew that was gonna pop up eventually. i already marked the spot with a todo that this is probably not gonna cover all cases. so now we have it. i'll have a look and refactor that broken heuristic.

@MissiaL
Copy link
Contributor

MissiaL commented Apr 3, 2020

Now I have stopped switching the schema to the 3.0 due to this problem :-(

I learned a little how the drf_yasg handles this situation.
One could look at this code
https://github.com/axnsan12/drf-yasg/blob/master/src/drf_yasg/inspectors/view.py#L216

@tfranzel
Copy link
Owner

tfranzel commented Apr 3, 2020

hi @MissiaL, thanks for the info. i had a look at yasg and they are also using a heuristic in the end: https://github.com/axnsan12/drf-yasg/blob/9ccf24c27ad46db4f566170553d49d687b6d21d6/src/drf_yasg/utils.py#L211

but apparently a slightly better one. however, this heuristic also breaks down occasionally. we have seen that in our own usage of yasg.

i'm actively on it and almost have a "as good as it gets" solution. by tomorrow i will have something to look at.

@tfranzel tfranzel merged commit f499dc4 into tfranzel:master Apr 8, 2020
@tfranzel
Copy link
Owner

tfranzel commented Apr 8, 2020

sry for the delay but i couldn't find the time earlier. so i tried something different here. this is really one of the more tricky parts.

  • viewsets: more or less easy via introspection
  • apiviews: there are no actions so no clue there. only thing you can rely on are annotation. the indication for list view is intialize serilizer like @extend_schema(responses=FooSerializer(many=True)). i believe this is also more consise than FooSerializer() for list=False

default for the new is_list_view is False as it makes more sense imho. i think it is still not 100% satisfactory but I don't see how to make it significantly better.

@tsouvarev i refactored the test into 2 separate test that explicitly only check this as the other test was already quite large.

@MissiaL let me know if that works for you now.

@MissiaL
Copy link
Contributor

MissiaL commented Apr 9, 2020

It works perfect! Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants