Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flask-Restplus: how to model string or object?

In Flask-Restplus, I need to model an attribute value that maybe either a list of strings or a list of objects.

That is it can look like this:

{
    'my_attribute': [
         'value1',
          'value2'
     ]
}

or it can look like the following:

{
    'my_attribute': [
        {
             'name': 'value1',
              'foo': 'something'
         },
         {
              'name': 'value2',
               'foo': 'something else'
          }
     ]
}

How should I model that in Flask-Restplus’ api.model?

like image 841
adib Avatar asked Apr 12 '18 09:04

adib


People also ask

What is Marshal_with in Flask?

marshal_with() is a convenience decorator, that is functionally equivalent to: class Todo(Resource): def get(self, **kwargs): return marshal(db_get_todo(), model), 200. The @api. marshal_with decorator add the swagger documentation ability.

What is namespace in Flask-RESTPlus?

namespace is from the Flask-RESTPlus and Blueprint is from flask to organize your app. the namespaces modules (specific to Flask-RESTPlus) are reusable namespaces designed like you would do with Flask's Blueprint. Follow this answer to receive notifications.

Which of the following modules is used to format and filter the response data?

With the fields module, you can use whatever objects (ORM models/custom classes/etc.) you want in your resource. fields also lets you format and filter the response so you don't have to worry about exposing internal data structures.


1 Answers

I've just figured this out myself. In short, create a custom field class that emits its own JSON schema. In turn the schema uses the oneOf type to specify that this is either a string or an object.

from flask_restplus import fields

element_object = api.model('Element_Object', {
    'name': fields.String(),
    'foo': fields.String()
})

class StringOrObjectElement(fields.Nested):
    __schema_type__ = ['string','object']

    def output(self, key, obj):
        if isinstance(obj, str):
            if key == 'name':
                return obj
            else:
                return 'default_value'
        return super().output(key, obj)

    def schema(self):
        schema_dict = super().schema()
        schema_dict.pop('type')
        nested_ref = schema_dict.pop('$ref')
        schema_dict['oneOf'] = [
            {
                'type': 'string'
            },
            {
                '$ref': nested_ref
            }
        ]
        return schema_dict

root_object = api.model('Root_Object', {
    'my_attribute': fields.List(fields.StringOrObjectElement(element_object))
like image 77
adib Avatar answered Sep 20 '22 03:09

adib