Open cocochepeau opened 6 years ago
Assuming you configured drf-json-api as outlined here, you could probably get it done by modifying the response using a PaginatorInspector as described here.
Otherwise, for a more general implementation you could modify responses by overriding SwaggerAutoSchema.get_response_schemas.
If you do manage to get it working, I wouldn't mind merging a pull request for an integration with django-rest-framework-json-api
😄
Hi again,
I made some more research. It appears that Swagger / OA2 doesn't fully support the JSON API spec (or in other words, the two are different). I'm not sure if that's even a good idea to try something or if it sounds right?
still learning.
I'm not sure I see how the two specs relate. JSON API is a way of structuring JSON bodies of HTTP requests and responses of an API, while Swagger is a way of programatically describing the structure of said response (a meta-API, if you will).
The only part of JSON API that couldn't really be represented by Swagger is the hyperlinkling part (i.e. link.first
is a URL vs links.first
is a URL that points to a page of entities). The request/response structure of individual endpoints, though, should be fully describable using Swagger as far as I can tell.
@cocochepeau hey you can write your own field and pagination Inspectors something similar to this: You can probably write it way better, but it is working and doing it's work
from rest_framework_json_api import serializers
class ResourceRelatedFieldInspector(FieldInspector):
def field_to_swagger_object(
self, field, swagger_object_type, use_references, **kwargs
):
if isinstance(field, serializers.ResourceRelatedField):
return None
return NotHandled
class ModelSerializerInspector(FieldInspector):
def process_result(self, result, method_name, obj, **kwargs):
if (
isinstance(obj, serializers.ModelSerializer) and
method_name == 'field_to_swagger_object'
):
model_response = self.formatted_model_result(result, obj)
if obj.parent is None and self.view.action != 'list':
# It will be top level object not in list, decorate with data
return self.decorate_with_data(model_response)
return model_response
return result
def generate_relationships(self, obj):
relationships_properties = []
for field in obj.fields.values():
if isinstance(field, serializers.ResourceRelatedField):
relationships_properties.append(
self.generate_relationship(field)
)
if relationships_properties:
return openapi.Schema(
title='Relationships of object',
type=openapi.TYPE_OBJECT,
properties=OrderedDict(relationships_properties),
)
def generate_relationship(self, field):
field_schema = openapi.Schema(
title='Relationship object',
type=openapi.TYPE_OBJECT,
properties=OrderedDict((
('type', openapi.Schema(
type=openapi.TYPE_STRING,
title='Type of related object',
enum=[get_related_resource_type(field)]
)),
('id', openapi.Schema(
type=openapi.TYPE_STRING,
title='ID of related object',
))
))
)
return field.field_name, self.decorate_with_data(field_schema)
def formatted_model_result(self, result, obj):
return openapi.Schema(
type=openapi.TYPE_OBJECT,
required=['properties'],
properties=OrderedDict((
('type', openapi.Schema(
type=openapi.TYPE_STRING,
enum=[get_resource_type_from_serializer(obj)],
title='Type of related object',
)),
('id', openapi.Schema(
type=openapi.TYPE_STRING,
title='ID of related object',
read_only=True
)),
('attributes', result),
('relationships', self.generate_relationships(obj))
))
)
def decorate_with_data(self, result):
return openapi.Schema(
type=openapi.TYPE_OBJECT,
required=['data'],
properties=OrderedDict((
('data', result),
))
)
and pagination:
class DjangoRestJsonApiResponsePagination(PaginatorInspector):
def get_paginator_parameters(self, paginator):
return [
openapi.Parameter(
'limit', in_=IN_QUERY, type=openapi.TYPE_INTEGER
),
openapi.Parameter(
'offset', in_=IN_QUERY, type=openapi.TYPE_INTEGER
),
]
def get_paginated_response(self, paginator, response_schema):
paged_schema = None
if isinstance(paginator, LimitOffsetPagination):
paged_schema = openapi.Schema(
type=openapi.TYPE_OBJECT,
properties=OrderedDict((
('links', self.generate_links()),
('data', response_schema),
('meta', self.generate_meta())
)),
required=['data']
)
return paged_schema
def generate_links(self):
return openapi.Schema(
title='Links',
type=openapi.TYPE_OBJECT,
required=['first', 'last'],
properties=OrderedDict((
('first', openapi.Schema(
type=openapi.TYPE_STRING, title='Link to first object',
read_only=True, format=openapi.FORMAT_URI
)),
('last', openapi.Schema(
type=openapi.TYPE_STRING, title='Link to last object',
read_only=True, format=openapi.FORMAT_URI
)),
('next', openapi.Schema(
type=openapi.TYPE_STRING, title='Link to next object',
read_only=True, format=openapi.FORMAT_URI
)),
('prev', openapi.Schema(
type=openapi.TYPE_STRING, title='Link to prev object',
read_only=True, format=openapi.FORMAT_URI
))
))
)
def generate_meta(self):
return openapi.Schema(
title='Meta of result with pagination count',
type=openapi.TYPE_OBJECT,
required=['count'],
properties=OrderedDict((
('count', openapi.Schema(
type=openapi.TYPE_INTEGER,
title='Number of results on page',
)),
))
)
Hi,
Sorry for the late answer.
@axnsan12 Indeed, you're right. @kujbol Thanks for sharing this. I'll try in the coming days.
Hey!
I have just released package integrating django-rest-framework-json-api
with drf-yasg
. It's based on my code that I have been using for some time in couple of projects. Easily integrable into the codebase if you already use drf-yasg
.
You can see it at https://github.com/glowka/drf-yasg-json-api
BTW
Since it's the very first time I write anything in this repo: I'd like to thanks you @axnsan12 for development of this very nice tool which drf-yasg
absolutely is!
Hello,
I'm pretty new to the python/django world so please forgive me in advance for my mistakes!
I wanna use drf-yasg with django-rest-framework-json-api. The "default" installation seems to work as expected - except for one little thing, the swagger response samples are not accurate.
For example, this is what's currently provided in the Swagger UI response sample for
http://localhost:8080/v1/entities/
(I guess this is the default drf response schema):What I expect (more like json api spec):
For information, here is what my renderer classes settings looks like:
My question is: How can I achieve such thing?
Thanks!