Skip to content

Avoid inlined responses in schema for paginated results in AutoSchema #7299

@l0rn

Description

@l0rn

Checklist

  • I have verified that that issue exists against the master branch of Django REST framework.
  • I have searched for similar issues in both open and closed tickets and cannot find a duplicate.
  • This is not a usage question. (Those should be directed to the discussion group instead.)
  • This cannot be dealt with as a third party library. (We prefer new functionality to be in the form of third party libraries where possible.)
  • I have reduced the issue to the simplest possible case.
  • I have included a failing test as a pull request. (If you are unable to do so we can still accept the issue.)

Context

Currently AutoSchema will call get_paginated_response_schema from any configured Paginator. Not having access to the components section of the schema the behavior of the included paginators is just to create an inline response like so:

def get_paginated_response_schema(self, schema):
return {
'type': 'object',
'properties': {
'count': {
'type': 'integer',
'example': 123,
},
'next': {
'type': 'string',
'nullable': True,
'format': 'uri',
'example': 'http://api.example.org/accounts/?{page_query_param}=4'.format(
page_query_param=self.page_query_param)
},
'previous': {
'type': 'string',
'nullable': True,
'format': 'uri',
'example': 'http://api.example.org/accounts/?{page_query_param}=2'.format(
page_query_param=self.page_query_param)
},
'results': schema,
},
}

Inlined responses cause bad developer experiences if you plan to use automatic client type generators like this. It'd create types like InlinedResponse000. So a better solution would be to a new component of your new paginated component response and reference that.

I have a local solution for this below, generating the paginated component in AutoSchema.get_components and referencing it in AutoSchema.get_responses, but i am not sure whether this holds as a generalized solution. I'd like to hear a word from maintainers if this is something they'd accept as PR before I will make the effort.

My solution:
https://github.com/l0rn/django-minutes/blob/9cf2b85bb48f7f4af7d7f9a07753dc4bde95b8d3/minutes/schema.py#L6-L61

Steps to reproduce

  • Create a paginated ListView
  • generate schema using AutoSchema

Expected behavior

Paginated responses are also references to components:

        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MeetingSeriesResponse"
                }
              }
            },
            "description": ""
          }
        },
[...]
	"components": {
		"schemas": {

			"MeetingSeriesResponse": {
				"type": "object",
				"properties": {
					"count": {
						"type": "integer",
						"example": 123
					},
					"next": {
						"type": "string",
						"nullable": true,
						"format": "uri",
						"example": "http://api.example.org/accounts/?offset=400&limit=100"
					},
					"previous": {
						"type": "string",
						"nullable": true,
						"format": "uri",
						"example": "http://api.example.org/accounts/?offset=200&limit=100"
					},
					"results": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/MeetingSeries"
						}
					}
				}
			}
		}
	}

Actual behavior

Paginated responses look like this (inlined):

"responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer",
                      "example": 123
                    },
                    "next": {
                      "type": "string",
                      "nullable": true,
                      "format": "uri",
                      "example": "http://api.example.org/accounts/?offset=400&limit=100"
                    },
                    "previous": {
                      "type": "string",
                      "nullable": true,
                      "format": "uri",
                      "example": "http://api.example.org/accounts/?offset=200&limit=100"
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/User"
                      }
                    }
                  }
                }
              }
            },
            "description": ""
          }
        },

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions