## drf-yasg-json-api - ***drf-yasg*** meets ***JSON API***

[![build-status-image]][travis]
[![coverage-status-image]][codecov]
[![pypi-version]][pypi]

Automated generation of Swagger/OpenAPI 2.0 ***JSON API*** specifications from Django Rest Framework endpoints.

This package makes [drf-yasg Yet Another Swagger Generator](https://github.com/axnsan12/drf-yasg) and 
[Django REST framework JSON API](https://github.com/django-json-api/django-rest-framework-json-api) play together.

#### Table of Contents
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->


- [Compatibility](#compatibility)
- [Installation](#installation)
- [Quickstart](#quickstart)
  - [Extending drg-yasg configuration](#extending-drg-yasg-configuration)
  - [Renderers and parsers](#renderers-and-parsers)
- [Features](#features)
  - [Main request/response JSON API schema support:](#main-requestresponse-json-api-schema-support)
  - [`data` field with `id`, `type`, `relationships`, `attributes` structure](#data-field-with-id-type-relationships-attributes-structure)
    - [`included` field and `include` query param](#included-field-and-include-query-param)
    - [`filter` query param](#filter-query-param)
    - [pagination](#pagination)
  - [Additional](#additional)
    - [Support for `swagger_auto_schema` decorator of `drf-yasg`](#support-for-swagger_auto_schema-decorator-of-drf-yasg)
    - [Stripping `write_only` fields from response and `read_only` from request](#stripping-write_only-fields-from-response-and-read_only-from-request)
    - [Extra `x-writeOnly` and `x-readOnly` properties](#extra-x-writeonly-and-x-readonly-properties)
- [Coexistence of JSON API views with pure REST API views](#coexistence-of-json-api-views-with-pure-rest-api-views)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->


### Compatibility

- Django REST Framework JSON API: `2.8`, `3.0`, `3.1`, `3.2`, `4.0`, `4.1`, `4.2`, `4.3`, `5.0`
- Drf-yasg: `1.16`, `1.17.0`, `1.17.1`, `1.20`


- Django REST Framework: `3.8`, `3.9`, `3.10`, `3.11`, `3.12`, `3.13`
- Django: `2.0`, `2.1`, `2.2`, `3.0`, `3.1`, `3.2`, `4.0`
- Python: `3.6`, `3.7`, `3.8`, `3.9`

### Installation

```
pip install -U drf-yasg-json-api
```

### Quickstart

First follow [drf-yasg quickstart](https://github.com/axnsan12/drf-yasg#1-quickstart),
then extend the configuration in following way.

#### Extending drg-yasg configuration
Assuming you are using drf-yasg configuration like below (which is drf-yasg default):
```

SWAGGER_SETTINGS = {
    'DEFAULT_AUTO_SCHEMA_CLASS': 'drf_yasg.inspectors.SwaggerAutoSchema',

    'DEFAULT_FIELD_INSPECTORS': [
        'drf_yasg.inspectors.CamelCaseJSONFilter',
        'drf_yasg.inspectors.RecursiveFieldInspector',
        'drf_yasg.inspectors.ReferencingSerializerInspector',
        'drf_yasg.inspectors.ChoiceFieldInspector',
        'drf_yasg.inspectors.FileFieldInspector',
        'drf_yasg.inspectors.DictFieldInspector',
        'drf_yasg.inspectors.JSONFieldInspector',
        'drf_yasg.inspectors.HiddenFieldInspector',
        'drf_yasg.inspectors.RelatedFieldInspector',
        'drf_yasg.inspectors.SerializerMethodFieldInspector',
        'drf_yasg.inspectors.SimpleFieldInspector',
        'drf_yasg.inspectors.StringDefaultFieldInspector',
    ],
    'DEFAULT_FILTER_INSPECTORS': [
        'drf_yasg.inspectors.CoreAPICompatInspector',
    ],
    'DEFAULT_PAGINATOR_INSPECTORS': [
        'drf_yasg.inspectors.DjangoRestResponsePagination',
        'drf_yasg.inspectors.CoreAPICompatInspector',
    ],
}
```

Apply following changes:
```
SWAGGER_SETTINGS = {
    'DEFAULT_AUTO_SCHEMA_CLASS': 'drf_yasg_json_api.inspectors.SwaggerAutoSchema',  # Overridden

    'DEFAULT_FIELD_INSPECTORS': [
        'drf_yasg_json_api.inspectors.NamesFormatFilter',  # Replaces CamelCaseJSONFilter
        'drf_yasg.inspectors.RecursiveFieldInspector',  
        'drf_yasg_json_api.inspectors.XPropertiesFilter',  # Added 
        'drf_yasg_json_api.inspectors.JSONAPISerializerSmartInspector',  # Added
        'drf_yasg.inspectors.ReferencingSerializerInspector',
        'drf_yasg_json_api.inspectors.IntegerIDFieldInspector',  # Added
        'drf_yasg.inspectors.ChoiceFieldInspector',
        'drf_yasg.inspectors.FileFieldInspector',
        'drf_yasg.inspectors.DictFieldInspector',
        'drf_yasg.inspectors.JSONFieldInspector',
        'drf_yasg.inspectors.HiddenFieldInspector',
        'drf_yasg_json_api.inspectors.ManyRelatedFieldInspector',  # Added
        'drf_yasg_json_api.inspectors.IntegerPrimaryKeyRelatedFieldInspector',  # Added 
        'drf_yasg.inspectors.RelatedFieldInspector',
        'drf_yasg.inspectors.SerializerMethodFieldInspector',
        'drf_yasg.inspectors.SimpleFieldInspector',
        'drf_yasg.inspectors.StringDefaultFieldInspector',

    ],
    'DEFAULT_FILTER_INSPECTORS': [
        'drf_yasg_json_api.inspectors.DjangoFilterInspector',  # Added (optional), requires django_filter 
        'drf_yasg.inspectors.CoreAPICompatInspector',
    ],
    'DEFAULT_PAGINATOR_INSPECTORS': [
        'drf_yasg_json_api.inspectors.DjangoRestResponsePagination',  # Added
        'drf_yasg.inspectors.DjangoRestResponsePagination',
        'drf_yasg.inspectors.CoreAPICompatInspector',
    ],
}
```

#### Renderers and parsers

JSON API schema of your view's response or request will be generated if you use `django-rest-framework-json-api`'s
 `JSONAPIRenderer` or `JSONAPIParser` respectively. 

But since you have already used them to *render* or *parse*, not just to *generate schema* (haven't you?), 
you probably only need to alter the configuration as described above.    
 
That's it!

### Features

Fields and query params extraction follows Django REST framework JSON API.

#### Main request/response JSON API schema support:
    
- ##### `data` field with `id`, `type`, `relationships`, `attributes` structure

    Schema based on view's main serializer. It accessed through view's `get_serializer` method, 
    *the same way `drf-yasg` does it*.
    
    Use `GenericAPIView` or `APIView` and define `get_serializer` manually. 
    
    Fields and their source: 
    - `id` – `id` field **or** other serializer field that matches the model `pk` 
    field **or** in-the-fly generated serializer field for model `pk`
    - `type` – serializer's model JSON API resource name **or** view's resource name,
     *the same way Django REST framework JSON API does it* 
    - `relationships` – all serializer fields of  `RelatedField` and `ManyRelatedField` class
    - `attributes` – all other serializer fields

- ##### `included` field and `include` query param
   
    Schema based on serializers defined in `included_serializer` attribute of view's main serializer where each one is 
    treated in the same way as view's main serializer (`data` field).
  
- ##### `filter` query param

    If view uses `django_filters.DjangoFilterBackend` as filter backend,
    schema of `filter[]` query param will be generated based on view's `filterset_fields` attribute.   
  
- #####  pagination

    If view uses `JsonApiPageNumberPagination` or `JsonApiLimitOffsetPagination` as `pagination_class`, 
    schema of `links` and `meta`, consistent with those pagination types, will be generated.    

#### Additional

##### Support for `swagger_auto_schema` decorator of `drf-yasg`

JSON API schema is also generated for success responses (statuses 2XX) defined manually using `responses` argument
 of `swagger_auto_schema` decorator.   

##### Stripping `write_only` fields from response and `read_only` from request

`drf_yasg_json_api.inspectors.InlineSerializerSmartInspector` strips fields inaccessible in request/response to
 provide view of fields that are **really** available to use.

You can revert to traditional `drf-yasg` view of all serializer fields in both response and request by replacing this
inspector with `drf_yasg_json_api.inspectors.InlineSerializerInspector` 


##### Extra `x-writeOnly` and `x-readOnly` properties

`drf_yasg_json_api.inspectors.XPropertiesFilter` uses:
 - `x-readOnly` to mark read only fields even if they are nested
 - `x-witeOonly` adds missing support for write only fields

### Coexistence of JSON API views with pure REST API views

JSON API docs will be generated by `drf_yasg_json_api.inspectors.JSONAPISerializerInspector`, 
**non** JSON API views are ignored by this inspector.

Pure REST API docs will be generated by `drf-yasg` inspectors – either 
`drf_yasg.inspectors.ReferencingSerializerInspector` or `drf_yasg.inspectors.InlineSerializerInspector` depending on
which one you prefer to use.

#### RecursiveField

RecursiveField follows different approach from JSON API, so it cannot be used with 
`JSONAPISerializerInspector`, but you can still have pure REST API views that will be documented 
using `ReferencingSerializerInspector`.

Alternatively, instead of `RecursiveField` you can use [`included_serializers`](https://github.com/django-json-api/django-rest-framework-json-api/blob/9c49b65894a38a185b34737f569785d720eccc67/docs/usage.md#included) 
with `self` (e.g. `included_serializers = {'related-obj': 'self'}`) to implement limited in depth recursion 
the JSON API way.   


[build-status-image]: https://secure.travis-ci.org/glowka/drf-yasg-json-api.svg?branch=master
[travis]: https://travis-ci.org/glowka/drf-yasg-json-api?branch=master
[coverage-status-image]: https://img.shields.io/codecov/c/github/glowka/drf-yasg-json-api/master.svg
[codecov]: https://codecov.io/github/glowka/drf-yasg-json-api?branch=master
[pypi-version]: https://img.shields.io/pypi/v/drf_yasg_json_api.svg
[pypi]: https://pypi.org/project/drf_yasg_json_api/

