Skip to content

Django HttpResponse.data JSON interpreted as bytes object #315

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

Closed
doemski opened this issue Apr 16, 2021 · 2 comments · Fixed by #319
Closed

Django HttpResponse.data JSON interpreted as bytes object #315

doemski opened this issue Apr 16, 2021 · 2 comments · Fixed by #319

Comments

@doemski
Copy link

doemski commented Apr 16, 2021

Hi,
I am trying to evaluate if I can use this lib on a bigger project. I use Django 3 with DRF and want an easy to integrate solution for request/response validation. After some time I got the request validation to work but I'm sorry to say I am stuck on the response validation. This seems to be such a standard use case so I assume that I am doing something wrong.

I would really appreciate a pointer :)

This is my spec:

openapi: '3.0.0'
info:
  version: '0.0.1'
  title: Test Service
paths:
  '/test/{test_id}/':
    get:
      responses:
        '200':
          content:
            application/json;charset=utf-8:
              schema:
                type: object
                properties:
                  test:
                    type: string
                required:
                  - test
      parameters:
        - required: true
          in: path
          name: test_id
          schema:
            type: integer
            minimum: 1

This is the relevant view code:

import yaml
import json
import logging

from rest_framework.views import APIView
from django.http import HttpResponse
from openapi_core import create_spec
from openapi_core.validation.request.validators import RequestValidator
from openapi_core.validation.response.validators import ResponseValidator
from openapi_core.contrib.django import DjangoOpenAPIRequest, DjangoOpenAPIResponse
from config.settings.base import OPENAPI_SPEC_PATH

class TechnicalDrawingView(APIView):
    def get(self, request, technical_drawing_id):
        with open(OPENAPI_SPEC_PATH) as file:
            spec_yaml = file.read()
        spec_dict = yaml.load(spec_yaml)
        spec = create_spec(spec_dict)

        openapi_request = DjangoOpenAPIRequest(request)

        request_validator = RequestValidator(spec)
        result = request_validator.validate(openapi_request)
        result.raise_for_errors()


        test_json = '{"test": "test_val"}'
        django_response = HttpResponse(
            test_json,
            content_type="application/json;charset=utf-8",
        )

        openapi_response = DjangoOpenAPIResponse(django_response)
        validator = ResponseValidator(spec)
        result = validator.validate(openapi_request, openapi_response)
        result.raise_for_errors()

        return django_response

Now when I call the route I get the following error:

openapi_core.unmarshalling.schemas.exceptions.InvalidSchemaValue: Value b'{"test": "test_val"}' not valid for schema of type SchemaType.OBJECT: (<ValidationError: 'b\'{"test": "test_val"}\' is not of type object'>,)

This is the traceback. The routes are different, I tried to clean the example up a little.

django      | 172.24.0.1 - - [16/Apr/2021 14:20:58] "GET /v1/technical_drawing_service/technical_drawings/1/ HTTP/1.1" 500 -
django      | Traceback (most recent call last):
django      |   File "/usr/local/lib/python3.8/site-packages/django/core/handlers/wsgi.py", line 133, in __call__
django      |     response = self.get_response(request)
django      |   File "/usr/local/lib/python3.8/site-packages/django/core/handlers/base.py", line 130, in get_response
django      |     response = self._middleware_chain(request)
django      |   File "/usr/local/lib/python3.8/site-packages/django/core/handlers/exception.py", line 49, in inner
django      |     response = response_for_exception(request, exc)
django      |   File "/usr/local/lib/python3.8/site-packages/django/core/handlers/exception.py", line 103, in response_for_exception
django      |     response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
django      |   File "/usr/local/lib/python3.8/site-packages/django/core/handlers/exception.py", line 138, in handle_uncaught_exception
django      |     return debug.technical_500_response(request, *exc_info)
django      |   File "/usr/local/lib/python3.8/site-packages/django_extensions/management/technical_response.py", line 40, in null_technical_500_response
django      |     raise exc_value.with_traceback(tb)
django      |   File "/usr/local/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
django      |     response = get_response(request)
django      |   File "/usr/local/lib/python3.8/site-packages/django/core/handlers/base.py", line 181, in _get_response
django      |     response = wrapped_callback(request, *callback_args, **callback_kwargs)
django      |   File "/usr/local/lib/python3.8/contextlib.py", line 75, in inner
django      |     return func(*args, **kwds)
django      |   File "/usr/local/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
django      |     return view_func(*args, **kwargs)
django      |   File "/usr/local/lib/python3.8/site-packages/django/views/generic/base.py", line 70, in view
django      |     return self.dispatch(request, *args, **kwargs)
django      |   File "/usr/local/lib/python3.8/site-packages/rest_framework/views.py", line 509, in dispatch
django      |     response = self.handle_exception(exc)
django      |   File "/usr/local/lib/python3.8/site-packages/rest_framework/views.py", line 469, in handle_exception
django      |     self.raise_uncaught_exception(exc)
django      |   File "/usr/local/lib/python3.8/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
django      |     raise exc
django      |   File "/usr/local/lib/python3.8/site-packages/rest_framework/views.py", line 506, in dispatch
django      |     response = handler(request, *args, **kwargs)
django      |   File "/app/technical_drawing_service/technical_drawings/api/views.py", line 80, in get
django      |     result.raise_for_errors()
django      |   File "/usr/local/lib/python3.8/site-packages/openapi_core/validation/datatypes.py", line 11, in raise_for_errors
django      |     raise error
django      |   File "/usr/local/lib/python3.8/site-packages/openapi_core/validation/response/validators.py", line 93, in _get_data
django      |     data = self._unmarshal(media_type, casted)
django      |   File "/usr/local/lib/python3.8/site-packages/openapi_core/validation/response/validators.py", line 114, in _unmarshal
django      |     return super(ResponseValidator, self)._unmarshal(
django      |   File "/usr/local/lib/python3.8/site-packages/openapi_core/validation/validators.py", line 56, in _unmarshal
django      |     return unmarshaller(value)
django      |   File "/usr/local/lib/python3.8/site-packages/openapi_core/unmarshalling/schemas/unmarshallers.py", line 47, in __call__
django      |     self.validate(value)
django      |   File "/usr/local/lib/python3.8/site-packages/openapi_core/unmarshalling/schemas/unmarshallers.py", line 60, in validate
django      |     raise InvalidSchemaValue(
django      | openapi_core.unmarshalling.schemas.exceptions.InvalidSchemaValue: Value b'{"test": "test_val"}' not valid for schema of type SchemaType.OBJECT: (<ValidationError: 'b\'
{"test": "test_val"}\' is not of type object'>,)

Thanks in advance,
Dom

@doemski
Copy link
Author

doemski commented Apr 21, 2021

Alternatively if someone could provide a (full) working example I probably can figure it out myself.

@p1c2u
Copy link
Collaborator

p1c2u commented May 2, 2021

Hi @doemski

I tried your example and it works good. Did you try it with latest version of OpenAPI-core?

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