noirbizarre / flask-restplus

Fully featured framework for fast, easy and documented API development with Flask
http://flask-restplus.readthedocs.org
Other
2.73k stars 508 forks source link

Nested Fields not getting registrated into swagger #643

Open bsparaujo opened 5 years ago

bsparaujo commented 5 years ago

I'm trying to create a nested field to a response model. I'm no understanding why the generated swagger.json is aware of the nested field but do not register it under $/definitions

This is my Model HypervisorResponse = ns.model('HypervisorResponse', { 'name': fields.String(required=True, example='hypervisor01.xx.com'), 'ip_addr': fields.String(required=True, example='192.168.0.0'), 'provider': fields.String(required=True), 'runtime': fields.Nested( ns.model('RuntimeResponse', { 'uptime': fields.Integer(attribute='uptime'), 'last_boot': fields.String(attribute='last_boot'), 'memory_total': fields.Integer(attribute='memory_total'), 'memory_used': fields.Integer(attribute='memory_used') }) ) })

The outputted swagger.json is "HypervisorResponse": { "required": [ "ip_addr", "name", "provider" ], "properties": { "name": { "type": "string", "example": "hypervisor01.xx.com" }, "ip_addr": { "type": "string", "example": "192.168.0.0" }, "provider": { "type": "string" }, "runtime": { "$ref": "#/definitions/RuntimeResponse" } }, "type": "object" }

j5awry commented 5 years ago

please provide the version of flask-restplus you're using, version of Python, and any other pertinent information. A quick check using

Python: 3.6.8 flask-restplus: 0.12.1

Yielded the proper results. I'm wondering if there's a formatting issue causing a problem? I cleaned up the formatting as follows

HYPERVISOR_RESPONSE = ns.model(
    'HypervisorResponse',
    {
        'name': fields.String(
            required=True, example='hypervisor01.xx.com'),
        'ip_addr': fields.String(
            required=True, example='192.168.0.0'),
        'provider': fields.String(required=True),
        'runtime': fields.Nested(
            ns.model(
                'RuntimeResponse',
                {
                    'uptime': fields.Integer(attribute='uptime'), 
                    'last_boot': fields.String(attribute='last_boot'),
                    'memory_total': fields.Integer(attribute='memory_total'),
                    'memory_used': fields.Integer(attribute='memory_used')
                }
            )
        )
    }
)
j5awry commented 5 years ago

Couple screengrabgs

Screen Shot 2019-05-17 at 8 59 41 AM Screen Shot 2019-05-17 at 8 59 36 AM
j5awry commented 5 years ago

and the generated JSON blob from swagger.json

{
    "swagger": "2.0",
    "basePath": "/",
    "paths": {
        "/closet/model": {
            "post": {
                "responses": {
                    "200": {
                        "description": "Success"
                    }
                },
                "description": "Some skeletons were models",
                "operationId": "post_skeleton_model",
                "parameters": [
                    {
                        "name": "payload",
                        "required": true,
                        "in": "body",
                        "schema": {
                            "$ref": "#/definitions/HypervisorResponse"
                        }
                    }
                ],
                "tags": [
                    "closet"
                ]
            }
        }
    },
    "info": {
        "title": "Testing API",
        "version": "1.0",
        "description": "Skeleton for Testing Basic Changes"
    },
    "produces": [
        "application/json"
    ],
    "consumes": [
        "application/json"
    ],
    "tags": [
        {
            "name": "closet",
            "description": "Skeletons live in the closet"
        }
    ],
    "definitions": {
        "HypervisorResponse": {
            "required": [
                "ip_addr",
                "name",
                "provider"
            ],
            "properties": {
                "name": {
                    "type": "string",
                    "example": "hypervisor01.xx.com"
                },
                "ip_addr": {
                    "type": "string",
                    "example": "192.168.0.0"
                },
                "provider": {
                    "type": "string"
                },
                "runtime": {
                    "$ref": "#/definitions/RuntimeResponse"
                }
            },
            "type": "object"
        },
        "RuntimeResponse": {
            "properties": {
                "uptime": {
                    "type": "integer"
                },
                "last_boot": {
                    "type": "string"
                },
                "memory_total": {
                    "type": "integer"
                },
                "memory_used": {
                    "type": "integer"
                }
            },
            "type": "object"
        }
    },
    "responses": {
        "ParseError": {
            "description": "When a mask can't be parsed"
        },
        "MaskError": {
            "description": "When any error occurs on mask"
        }
    }
}
lena-kuhn commented 5 years ago

I have the same issue using Python 3.7.3 and flask-restplus 0.12.1 grafik

j5awry commented 5 years ago

Please provide more information. Specifically, we need to know what the models and nestings look like to provide support.

We're tracking various issues regarding swagger and the generated jsonschema. But we need to know what the models look like to be able to provide support. The basic case working is illustrated above after fixing various formatting.

arabidopsis commented 5 years ago

Check you are not using an ordered=True in your namespace see the PR: https://github.com/noirbizarre/flask-restplus/pull/616

j5awry commented 5 years ago

I've identified some other times when fields.Nested may fail to get registered. PR #616 actually fixes those as well. I'll bring this up on Gitter

bsparaujo commented 5 years ago

@arabidopsis got it right. Setting the ordered parameter of the namespace to False fixed it.