ristoh
ristoh

Reputation: 41

how to use marshal_with in flask_restful for attributes that can be of different types

I'm using flask_restful.marshal_with to sanitize my entities:

class Domain(db.Model):

    __tablename__ = 'domain'

    id = db.Column(db.BigInteger, primary_key=True)
    domain_name = db.Column(db.String(253), unique=True)
    user_id = db.Column(db.BigInteger, db.ForeignKey('user.id'), nullable=True)
    .... # bunch of other sensitive fields I don't want to output

Here's my handler:

class Domains(Resource):
    domain_fields = {
        'id': fields.Integer,
        'user_id': fields.Integer,
        'domain_name': fields.String
        }

    @marshal_with(domain_fields)
    def get(self, domain_id):
        """return domain details"""
        entity = domain.Domain.query.get(domain_id)

        return entity 

The user_id attribute can be either None or an Integer.

What's a a good say to setup the domain_fields to output either Bool or Int instead of just limited to Int?

Upvotes: 4

Views: 1888

Answers (2)

juanrossi
juanrossi

Reputation: 305

You could put a default in user_id that will be returned if user_id is None, or you could create a custom field for user_id to handle properly.

domain_fields = {
    'id': fields.Integer,
    'user_id': fields.Integer(default=False),
    'domain_name': fields.String
}

or

class CustomField(fields.Raw):
    def output(self, key, obj):
        return obj.user_id or False

domain_fields = {
    'id': fields.Integer,
    'user_id': CustomField,
    'domain_name': fields.String
}

Upvotes: 3

Sanna Keller-Heikkila
Sanna Keller-Heikkila

Reputation: 2594

There isn't a good way to have 1 field be 2 data types. In fact, I'd highly recommend not doing that at all. Stick with Int.

Here is how I'd approach it:

class Domains(Resource):
    def __init__(self):
        self.domain_fields = {
            'id': fields.Integer,
            'user_id': fields.Integer,
            'domain_name': fields.String
        }

    def get(self, domain_id):
        """return domain details"""
        entity = domain.Domain.query.get(domain_id)
        return marshal(entity, self.domain_fields), 200

This will return user_id as an int if it's set, and if it's None the response will be null, which is valid for a JSON Int field.

Example response returned by marshal(): If user_id = integer:

{"id": 1234, "user_id": 1, "domain_name": "example.com"}

If user_id = None:

{"id": 1234, "user_id": null, "domain_name": "example.com"}

Upvotes: 0

Related Questions