How to add example in swagger field

5k Views Asked by At

I am currently using following libraries of django -

Django==2.2.4
django-pdb==0.6.2
django-rest-swagger==2.2.0
django-service-objects==0.5.0
django-timezone-field==3.0
django-windows-tools==0.2.1
djangorestframework==3.10.2
djongo==1.2.33

It is running on Python version 3.7.4

The problem that I am facing is I can able to generate body part of API using corapi.Field in Autoschema.

class SwaggerSchemaView(APIView):
    permission_classes = [AllowAny]
    renderer_classes = [
        renderers.OpenAPIRenderer,
        renderers.SwaggerUIRenderer
    ]

    def get(self, request):
        generator = SchemaGenerator()
        schema = generator.get_schema(request=request)

        return Response(schema)
class ParseResume(APIView):
    permission_classes = [AllowAny]
    schema = AutoSchema(
        manual_fields=[
            coreapi.Field(
                "data",
                required=True,
                location="body",
                description='Send Json Data',
                type="string",
                schema=coreschema.Object(),

            )
        ]
    )

    def post(self, request):
        data = request.data
        response_data = SetConnections.parse_resume(data)
        return Response(response_data)

Now, I can able to generate Swagger view like as follows -

enter image description here

But I want to add a sample data inside this body part through coreapi.Field like as follows -

{
      "id": "56-df-pt",
      "fname": "John",
      "lname": "Doe",
      "experience": {
          "employee": "Company X",
          "period": "1996 - 2002",
          "engaged_in": [
                {
                   "work": "Jr. Manager",
                   "team_size": 5,
                   "time": "Sep. 1996 - Dec. 1998"
                },
                {
                   "work": "Sr. Manager",
                   "team_size": 5,
                   "time": "Jan. 1999 - Dec. 2002"
                },
           ]
  }

How can I add that? I can't change any version of Django or Python at this moment now.

2

There are 2 best solutions below

6
Manuel Lazo On

After long days of being looking for a solution about how to display the nested objects on swagger, I find out that the following python package:

django-rest-swagger

Does not display nested objects if the serializer contains nested fields ( relations ), how did I find out about it?, checking in the rest-framework website about schema generator :

https://www.django-rest-framework.org/coreapi/schemas/#third-party-packages

There is a line that mention another package called :

drf-yasg

https://drf-yasg.readthedocs.io/en/stable/index.html

This package has improved features such as : nested schemas, named models, response bodies, enum/pattern/min/max validators, form parameters, etc. In that way I decided to install the package with the following steps :

pip install -U drf-yasg

Once the package is been installed you have to add the module on the modules list in settings.py and some additional configuration that I considered appropiate:

....
THIRD_APPS = [
    'rest_framework',
    'rest_framework_swagger',
    'django_filters',
    'django_celery_beat',
    'drf_yasg',
]

INSTALLED_APPS += THIRD_APPS

# Django restframework
REST_FRAMEWORK = {
    # Use Django's standard `django.contrib.auth` permissions,
    # or allow read-only access for unauthenticated users.
    'DEFAULT_PERMISSION_CLASSES': [
        # 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly',
        # 'rest_framework.permissions.IsAuthenticated',
        # 'rest_framework.permissions.IsAuthenticatedOrReadOnly',
        'rest_framework.permissions.AllowAny',
    ],
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.BasicAuthentication',
    ],
    'DEFAULT_FILTER_BACKENDS': [
        'django_filters.rest_framework.DjangoFilterBackend',
    ],
    'COERCE_DECIMAL_TO_STRING': False,
}

SWAGGER_SETTINGS = {
    'USE_SESSION_AUTH': True,
    'LOGIN_URL': 'rest_framework:login',
    'LOGOUT_URL': 'rest_framework:logout',
    'DEFAULT_PARSER_CLASSES': [
        'rest_framework.parsers.FormParser',
        'rest_framework.parsers.MultiPartParser',
        'rest_framework.parsers.JSONParser',
    ],
    'JSON_EDITOR': False,
}

then proceed to go to my urls.py and add the following lines to generate the schema view :

  • Import the necessary modules on apps/dol/urls.py
from rest_framework import permissions
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
  • configure the initial parameters of the function on apps/dol/urls.py, in order to does not display all the API urls, I created the variable dol_patterns to store the urls required to be displayed :
app_name = 'module_dol'
dol_patterns = [
    url(r'^dol/api/?', include('apps.dol.api.urls')),
]

SchemaView = get_schema_view(
    openapi.Info(
        title="API Interface Dol",
        default_version='v1',
        description="API REST",
        # terms_of_service="https://www.google.com/policies/terms/",
        # contact=openapi.Contact(email="[email protected]"),
        license=openapi.License(name="BSD License"),
    ),
    patterns=dol_patterns,
    public=True,
    permission_classes=(permissions.AllowAny,),
)
  • My main settings/urls.py file :
urlpatterns = [
    url(r'^api-auth/?',
        include('rest_framework.urls', namespace='rest_framework'),),
    url(r'^admin/?', admin.site.urls),
    ....
    ....
    url(r'^dol/', include('apps.dol.urls', namespace='dol'),),
]
  • Here, my registered urls apps/dol/urls.py :
urlpatterns = [
    ......
    ......
    url(r'^swagger(?P<format>\.json|\.yaml)$',
        SchemaView.without_ui(cache_timeout=0), name='schema-json'),
    url(r'^swagger/$',
        SchemaView.with_ui('swagger', cache_timeout=0),
        name='schema-swagger-ui'),
    url(r'^redoc/$',
        SchemaView.with_ui('redoc', cache_timeout=0),
        name='schema-redoc'),
    url(r'^api/', include('apps.dol.api.urls')),
]
  • the class based view endpoints were created with the following generics :
from rest_framework.generics import (
    CreateAPIView, UpdateAPIView, DestroyAPIView,
)
  • in addition, this is how looks my apps/dol/api/urls.py :
....
....
urlpatterns = [
    re_path(r"^registration/?$",
            v.ApiDolRegistration.as_view(), name='api-registration'),
    re_path(r"warranty/(?P<coupon_number>[0-9]{5,6})/?$",
            v.ApiDolWarranty.as_view(), name='api-warranty'),
    re_path(r"rejection/(?P<coupon_number>[0-9]{5,6})/?$",
            v.ApiDolRejection.as_view(), name='api-removal'),
]

  • finally, once it is been properly configured, u will be able to see a GUI like the following :

enter image description here

  • When ure ready to test the API from the GUI, u will see that the data layer will be editable to modify the json tree :

enter image description here

  • A last observation about the nested objects, in order to display the nested objects u have to be sure that the serializer field has the property read_only=False, otherwise the field will not appear in the GUI.
    ....
    ....
    owner_user = ClientesSerializers(
        fields=Client.FIELDS,
        read_only=False,
    )

    class Meta:
       ....
       ....

I really hope the information provided would be helpful for somebody.

Greetings,

0
Manuel Lazo On

This is an update based on the query of Kiran Kumar Kotari. For setting a default value or help text can be achieved in the serializer object and in addition also set a default response, the previous mentioned can be achieved following the next steps :

  • Set the default value in the serializer field, as you can see the serializer field inherits from Field and it has a parameter default.

enter image description here

enter image description here

  • for setting a default response, do the following import :
from drf_yasg.utils import swagger_auto_schema
  • In your view add something like this :
class YourViewName(ListAPIView):
    """ description of your view """
    permission_classes = [permissions.IsAuthenticated, ]
    authentication_classes = [authentication.BasicAuthentication, ]
    serializer_class = SerializerOfYourView

    @swagger_auto_schema(**apiutl.swagger_coupon_type_get())
    def get(self, request, *args, **kwargs):
        ....
        ...
  • In example above you will see a function called swagger_coupon_type_get, right ? this will contain the following code:
def swagger_coupon_type_get():
    """ params for swagger decorator http method GET """
    return {
        "operation_description": """
        Get all the Coupon Type records, filters that support:
        * /dol/api/bases/tipo_cupon/?descripcion__icontains=VENTA%20A%20CLIENTE
        * /dol/api/bases/tipo_cupon?id=2
        """,
        "operation_summary": 'Coupon type list',
        "responses": {
            200: rsc.RSP_COUPON_TYPE,
            500: rsc.RSP_INTERNAL_ERROR,
        },
    }
  • Finally, in the previous example you will see a variable / object with the following description RSP_COUPON_TYPE which will contain the following code:

from rest_framework import status
from drf_yasg import openapi

class TipoCuponVentaSerializer(srlcommon.DynamicFieldsModelSerializer):
    """ Ćoupon Type serializer """
    class Meta:
        model = mdlcat.TipoCuponVenta
        fields = [
            'id', 'descripcion',
        ]
        # reserved for swagger
        ref_name = 'CouponType'

class ResponseSerializer(serializers.Serializer):
    """ default response schema """
    ok = serializers.IntegerField(
        help_text="Request state 0:Error, 1:Ok",
    )
    result = serializers.CharField(
        help_text="Request outcome or Error Message",
    )
    status = serializers.IntegerField(
        help_text="Http code status",
    )

class ResponseCouponType(ResponseSerializer):
    """ default response schema """
    result = TipoCuponVentaSerializer(
        help_text="List of items", many=True,
    )

    class Meta:
        ref_name = 'ResponseCouponType'


EXAMPLE_COUPON_TYPE = {
    "application/json": {
        "ok": 1,
        "result": [
            {"id": 1, "descripcion": "VENTA A CLIENTE FINAL"},
            {
                "id": 2,
                "descripcion": "VENTA A CLIENTE DIRECTO POR EL IMPORTADOR"
            },
            {"id": 3, "descripcion": "VENTA DE ACTIVOS POR EL IMPORTADOR"},
        ],
        "status": status.HTTP_200_OK,
    },
}

RSP_COUPON_TYPE = openapi.Response(
    description='Ok',
    schema=ResponseCouponType,
    examples=EXAMPLE_COUPON_TYPE,
)

In that way a when you display a specific endpoint