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

Allow per-view Schema Generation customisation #5337

Closed
2 of 3 tasks
carltongibson opened this issue Aug 17, 2017 · 4 comments · Fixed by #5354
Closed
2 of 3 tasks

Allow per-view Schema Generation customisation #5337

carltongibson opened this issue Aug 17, 2017 · 4 comments · Fixed by #5354

Comments

@carltongibson
Copy link
Collaborator

carltongibson commented Aug 17, 2017

A recurring issue is the need to slightly customise the Schema Generation. The default behaviour is correct in the main; what we’re missing is the ability to customise the behaviour for specific views.

For full control it is possible to write schemas by hand, but we want to be able to keep the automatic generation, in the main, whilst tweaking the aspects that are not correct (for our project).

Some proposals involve adopting a specific markdown syntax in order to encode (ever) more complex data structures in docstrings. We would then parse these, using Sphinx or pyparsing or a custom parser.

This is not the way to go. (External dependencies, fragility, and so on.) Better is to use Core Schema to clearly/precisely/etc specify the details we require.

The current implementation is Top Down — the generator inspects each view in turn to create the schema. Its limitation is that it does not (easily) allow customisation on a per-view/serialiser/etc basis.

In order to avoid adding more API to the APIView class, we will move the bulk of the generator’s introspection logic to a descriptor class that will be attached to the view. It will be accessed from the view and perform the necessary schema generation:

view.schema.get_schema()

(Or such)

The descriptor class will expose the required hooks to allow per-view customisation of the schema generation.

For example, it is not currently possible to provide a description for a non-model path parameter on a URL. An implementation of (the equivalent to the current) get_path_fields adding this would go something like:

fields = super().get_path_fields(...)
extra_field = coreapi.Field(...)
fields.append(extra_field)
return fields

i.e. We take the default implementation and make the (small) changes we want.

Users would be free to take whatever steps were needed to keep this DRY in their own projects.

The top-level schema generator will be maintained. It’s responsibilities will be reduced to accepting the patterns to be processed and gathering the resulting schema document.

Tasks

  • Migrate introspection logic from SchemaGenerator to descriptor class for APIView.
    • Make sure it still works.
  • Document interface and usage.

Related Issues

(There are others.)

Related PRs

@tomchristie
Copy link
Member

I'm wondering if in addition to the programmatic overrides, we might want to support a fields or schema_fields attribute on views that allows users to set a list of fields to use, declaratively, but without having to write any method code. We'd hook that into the existing behavior https://github.com/encode/django-rest-framework/blob/master/rest_framework/schemas.py#L445 by checking for any explicitly declared fields, and then replacing the automatically generated one (if there was a field with the same name) or extending the list.

The benefit of doing that is that we'd be able to meet he "extend the list, or override a field" case without having to override methods, and it'd also be extensible to FBVs where we could apply it as an attribute.

@Place1
Copy link

Place1 commented Aug 20, 2017

Will this also work as a solution to documenting 3rd party endpoints? Say I've included a reusable app in my project and i've included some API endpoints from it (urls) but the generator doesn't correctly detect the inputs/outputs. Would I be able to dynamically add a .schema to the view before I add it to my urlconf to manually define the endpoint?

@carltongibson
Copy link
Collaborator Author

@tomchristie: Yep. That sounds good. I'd rather pass kwargs to the descriptor class than add attributes to APIView (or children) but the idea is 👍. I guess it will look something like:

class MyView(SomeSuperView):
  schema = SchemaDescriptor(       # Name Pending but this would be the provided class
     fields = {
      "my_extra": coreapi.Field( ... ), 
    },
    ...
  )

There's an extra line here but it keeps all the schema logic in the descriptor class and out of the view. If it gets too big inline it's very easy to extract and refactor to a subclass.

@Place1:

Would I be able to dynamically add a .schema to the view before I add it to my urlconf to manually define the endpoint?

Yeah, I think so: it's Python 🙂

@carltongibson
Copy link
Collaborator Author

I've opened #5354 which addresses this.

It's fully functional (I think 😀) so do try it and feedback if you're wanting to customise the schema generation.

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

Successfully merging a pull request may close this issue.

3 participants