P
P
Philip Bondarev2018-10-20 18:38:28
Python
Philip Bondarev, 2018-10-20 18:38:28

How to avoid code duplication in a project using Flask-RESTplus + Marsmallow?

I'm starting to slowly figure out how to implement a REST API on Flask using Flask-RESTplus. Now I'm looking at articles and videos in which the authors use the Marshmallow de/serializer in addition to Flask-RESTplus. One of the first questions that confronted me was whether it is really necessary to duplicate the model description code?
Now I’ll explain, here we have a description of the models (de facto description of the tables in the database and their relationships) SQLAlchemy, but this, as I understand it, will not help us in any way, because the models received via api.model() for use in @api. expect() (maybe somewhere else, I don't know yet), it's more like describing forms from a Flask-WTF module, right? But if we also want to use Marshmallow as a bite, then we will have to implement a duplicate description through Schema. Here is an example:

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

from flask_restplus import Resource, fields
from marshmallow import Schema, post_load, fields as ma_fields

from application import api


class MyModel(object):
    def __init__(self, egg, spam):
        self.egg = egg
        self.spam = spam
    
    def __repr__(self):
        return 'Egg -> {} ; Spam -> {}'.format(self.egg, self.spam)


class MyModelSchema(Schema):
    egg = ma_fields.String()
    spam = ma_fields.String()
    
    @post_load
    def create_mymodel(self, data):
        return MyModel(**data)


my_model = api.model('MyModel', {
    'egg': fields.String('Put egg here'), 
    'spam': fields.String('Put spam here')})

fs = []
f1 = MyModel('egg1', 'spam1')
fs.append(f1)


@api.route('/hello')
class MyResource(Resource):
    def get(self):
        schema = MyModelSchema(many=True)
        return schema.dump(fs)
    
    @api.expect(my_model)
    def post(self):
        schema = MyModelSchema()
        a = schema.load(api.payload)
        fs.append(a.data)
        return {'ok': 'all is fine'}, 201


And another question, there is a flask-marshmallow module, maybe it's better to use it?

Answer the question

In order to leave comments, you need to log in

2 answer(s)
X
xSkyFoXx, 2018-10-20
@xSkyFoXx

In continuation to the comments:
I think you are overcomplicating the application.
At the initial stage of development, you can abstract away from authorization and think in terms of API design and coding. Your API methods will "enrich" the result of a fetch from the database, for which you can write yourself exactly one small helper that will convert the response from the database into a dictionary and then return this dictionary wrapped in jsonify.
The next step is Token-Based Authentication. For it, you define separate handles that issue or do not issue a token to your client. Ideally, the required modification to your core API is an authorization decorator to a class or functions.
Documentation is a separate issue. I am against the swager, as it makes my Python code look like JavaScript code.

D
domanskiy, 2020-10-16
@domanskiy

The use of the SQLAlchemyAutoSchema method in the latest version of flask-marshmallow helped a lot
. It generates the schema itself)

class DieCutSchema(ma.SQLAlchemyAutoSchema):
    class Meta:
        model = DieCut

@api.route('/diecuts')
def index():
    items = DieCut.query.all()
    items_schema = DieCutSchema(many=True)
    result = items_schema.dump(items)
    return jsonify(result)

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question