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 extension blueprint for drf-extra-fields Base64FileField #579

Closed
johnthagen opened this issue Oct 18, 2021 · 8 comments · Fixed by #583
Closed

Add extension blueprint for drf-extra-fields Base64FileField #579

johnthagen opened this issue Oct 18, 2021 · 8 comments · Fixed by #583

Comments

@johnthagen
Copy link
Contributor

johnthagen commented Oct 18, 2021

The drf-extra-fields Base64FileField / Base64ImageField provide a to define a file field in which files are sent as requests as base64 string instead of binary blobs, and can be pulled down as responses as base64 string or URL.

Out of the box drf-spectacular seems to treat them as normal file fields (e.g. that binary should be pushed up). I'd like to contribute an extension blueprint for how to properly model these in drf-spectacular.

Here is a PR for how this was done in drf-yasg: axnsan12/drf-yasg#445

        swagger_schema_fields = {
            'type': 'string',
            'title': 'File Content',
            'description': 'Content of the file base64 encoded',
            'read_only': False 
        }

This simply sets the type as a string and also sets read_only to False (I think the read_only part is drf-yasg specific and has to do with OpenAPI 2 not being able to split request and response).

The best I've been able to come up with so far is:

@extend_schema_field(OpenApiTypes.STR)
class SpectacularBase64ImageField(Base64ImageField):
    ...

But in theory we could do better. Ideally we'd want OpenAPI 3 something like:

Request: string($base64)
Response: string($uri)

And then for fields defined like:

image = Base64ImageField(represent_in_base64=True)

To annotate OpenAPI 3 like:

Request: string($base64)
Response: string($base64)

Is there a way to accomplish dual-sided schema generation with @extend_schema_field?

@johnthagen
Copy link
Contributor Author

johnthagen commented Oct 18, 2021

@johnthagen
Copy link
Contributor Author

What drf-spectacular does out of the box for Base64ImageFileField:

Request: string($binary)
Response: string($uri)

@tfranzel
Copy link
Owner

Hey,

you are referencing the wrong spec (3.0.1).. this changed for 3.0.3

https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#data-types

binary for binary
byte for base64

The output is likely because that field is derived from DRF's FileField, for which the schema is indeed correct like that. Note that the output is dependent on DRF's settings. Also note that DRF's FileField only works with multi-part (MultiPartParser) and so the input is in fact binary. docs

Is there a way to accomplish dual-sided schema generation with @extend_schema_field

Nope, you would need to create a OpenApiSerializerFieldExtension to override the behavior for that modified subclass. This is the preferred way to "annotate" functionality that originates from inaccessible library code. The whole point of extensions is so that you don't need to do this:

@extend_schema_field(OpenApiTypes.STR)
class SpectacularBase64ImageField(Base64ImageField):

@johnthagen
Copy link
Contributor Author

johnthagen commented Oct 19, 2021

@tfranzel Reading the Extensions guide, how does one register an Extension? Or do they get automatically discovered?

@tfranzel
Copy link
Owner

It works similar to celery tasks. They get registered once they are seen by the interpreter.

It's in the blueprint docs but should also be mentioned there again probably

@johnthagen
Copy link
Contributor Author

It's in the blueprint docs but should also be mentioned there again probably

@johnthagen
Copy link
Contributor Author

@tfranzel Would you be able to advise which plumbing function to use to overwrite the Base64ImageField with the following schema within an OpenApiSerializerFieldExtension?

Request: string($byte)
Response: string($uri)

I will also need to control the Required field as well.

I plan to submit this as a blueprint PR for others once completed.

@johnthagen
Copy link
Contributor Author

PR for this in #583

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

Successfully merging a pull request may close this issue.

2 participants