flask-restplus icon indicating copy to clipboard operation
flask-restplus copied to clipboard

JSON Schema $ref not working (not even the doc example)

Open JenusL opened this issue 8 years ago • 14 comments

Using the JSON Schema example (http://flask-restplus.readthedocs.io/en/stable/marshalling.html#define-model-using-json-schema)

Address object looks like it's recognized but not much more. This is on 0.10.1

model example

This is a stopper for me right now. Any workaround / ideas?

JenusL avatar Apr 24 '17 10:04 JenusL

I haven't found a solution for this yet. Does anyone have a clue?

JenusL avatar May 02 '17 10:05 JenusL

What's the expected behavior? Can you post your full code?

langston-barrett avatar Jun 16 '17 20:06 langston-barrett

Expected behavior would be that 'address' is showing in the Example box. It's completely absent right now. It should also show the fields under Address in the Model box. I have attached a very simple example where the same models are defined with JSON Schema and Fields. They should be identical in swagger doc.

#! /usr/bin/env python
# -*- coding: utf-8 -*-

from flask import Flask
from flask_restplus import Api, Resource, fields

import json


app = Flask(__name__)
api = Api(app)


# Fields model is working as expected.
f_address = api.model('Address_', {
    'road': fields.String()
    })

f_person = api.model('Person_', {
    'name': fields.String(),
    'age': fields.Integer(),
    'birthday': fields.DateTime(),
    'address': fields.Nested(f_address)
    })


# The code below are directly from http://flask-restplus.readthedocs.io/en/stable/marshalling.html#define-model-using-json-schema
address = api.schema_model('Address', {
    'properties': {
        'road': {
            'type': 'string'
        },
    },
    'type': 'object'
})

person = address = api.schema_model('Person', {
    'required': ['address'],
    'properties': {
        'name': {
            'type': 'string'
        },
        'age': {
            'type': 'integer'
        },
        'birthdate': {
            'type': 'string',
            'format': 'date-time'
        },
        'address': {
            '$ref': '#/definitions/Address',
        }
    },
    'type': 'object'
})


# One route for each model
@api.route('/addressfields')
class AddressFields(Resource):
    @api.expect(f_person)
    def get(self):
        return 200

@api.route('/addressjson')
class AddressJson(Resource):
    @api.expect(person)
    def get(self):
        return 200


if __name__ == '__main__':
    app.run(debug=True)

JenusL avatar Jun 19 '17 08:06 JenusL

Is there no solution to this?

I also haven't been able to use JSONschema.

I can't document my nested models, and using @ns.expect fails validation for nested required fields.

theholy7 avatar Feb 26 '18 10:02 theholy7

Same problem. Looks like this issue is a year old at this point. Following the example for complex and nested structures seems to result in this issue. The error is rather cryptic. Can you just drop support for nested and complex structures completely? I'd rather not be lead to believe this is a feature when it doesn't work.

KraftyKai avatar Mar 16 '18 00:03 KraftyKai

This is a long standing problem in Flask-restplus and the only solution is to use JSON schema models instead of trying to use nested flask-restplus models at which point you might as well use another marshalling/validation library altogether.

KpaBap avatar Mar 27 '18 23:03 KpaBap

Anyone has a solution to register the '$ref' for a SchemaModel as another SchemaModel created from JSONSchema? I need to properly display in the Swagger documentation in browser without errors and to show all the models in the list. I'm also looking for workarounds if any: One could be register models in dummy namespace, at least the model will be shown. Another would be to expand the $ref before registering the JsonSchema,

After investigating it looks to me that the issue is in swagger.py function def register_model(self, model) Line 511, it doesn't check the SchemaModel. The fix should be added in the file. register_model and register_field, if I can find a solution, I will gladly share it with you.

I have added a quick fix here: https://github.com/tincumagic/flask-restplus/commit/469e4c063f5362ef16a9ebc505e1223083e2bc17 At least for my cases it works as I want and also for the example in documentation with Address and Person. http://flask-restplus.readthedocs.io/en/stable/marshalling.html#define-model-using-json-schema

tincumagic avatar May 29 '18 09:05 tincumagic

Thanks a lot for the hot fix - works for me!

uniqueg avatar Aug 07 '18 18:08 uniqueg

Guys please help me push my fix inside the library flask-restplus. It realy works and helps documenting, the ref elemets that without the fix only show None

tincumagic avatar Nov 16 '18 11:11 tincumagic

Possible workaround: Use the jsonref library to load and dereference your schemas before passing them to api.schema_model(). I'm using this primarily because I've my json schemas stored in separate files.

import jsonref

jsonref_schema = jsonref.loads('''
    {
        "definitions": {
            "fruit": {
                "type": "string"
            }
        },

        "id": "apple",
        "allOf": [
            { "$ref": "#/definitions/fruit" }
        ]
    }
''')

# copy.deepcopy is a workaround for a problem with jsonref's lazy loading together with flask non-debug (production) mode.
# It would produce a JSON serialisation error otherwise.
apple_input = api.schema_model('Apple POST input', copy.deepcopy(jsonref_schema))

Pay attention to the copy step before using the jsonref object. jsonref lazy laods the references. In flask debug mode this works fine but in production environment the swagger.json generation will fail with 'TypeError: Object of type dict is not JSON serializable'.

jojoob avatar Nov 27 '18 08:11 jojoob

@siddharthist could you merge the fix? if there have something need to do, please comment here. I find some check is error "coverage/coveralls — Coverage decreased (-0.5%) to 96.329% Details"

jinxingf avatar May 05 '19 03:05 jinxingf

I've checked on pr-555. It needs a rebase and tests added for the new functionality. I commented on the PR, and i'm checking things myself as well.

j5awry avatar May 15 '19 15:05 j5awry

After reviewing pr-555, it does not work to solve the case in my setup after a rebase. It fails to do the nested lookup properly on resolution. It appears to still not respect the nesting

I've tried using jsonref as @jojoob mentioned, and this is working for me. It appears to be the best current workaround. This does remove the abstraction, so you lose some nice documentation of the separate models.

I am seeing some oddness with what gets displayed still once i get a few levels deep. I'll need to do some more checking to see what's up.

j5awry avatar May 16 '19 12:05 j5awry

i just had to do the jsonref fix myself. would be nice not to have to go thru the extra step

scphantm avatar Nov 26 '19 19:11 scphantm