lbvirgo
lbvirgo

Reputation: 404

How to populate Models using python Flask RESTplus

I'm coming from Java background and now trying my hands on Python. I'm trying to create a RESTful web application for CRUD operations. I've already tried to go through the various links that provide step by step approach in achieving it using Flask RESTplus + SQLAlchemy.

However, I'm more keen on getting this the usual "java-way". Also I would like to avoid using ORM and instead use SQLAlchemy for executing raw SQL and then iterating resultsets to populate my model and then return the model.

I'm taking baby steps and initially I want to see how to populate my Model with dummy data and return it back to the caller. Below is what I'm trying to achieve but not able to move further:

from flask import request
from flask import Flask
from flask import Blueprint
from flask_restplus import Resource, Api, apidoc
from flask_restplus import fields, marshal
from sqlalchemy import create_engine
from sqlalchemy.sql import text
import json

app = Flask(__name__)
blueprint = Blueprint('api', __name__, url_prefix='/edslnk/rest')
api = Api(blueprint, version='1.0', title='EDSLink ResourceSvc API',description='Set of APIs to interactively communicate with Database and HDFS')
app.register_blueprint(blueprint)

ns = api.namespace('eds-workflows', description='Operations related to EDS Workflows')

#engine = create_engine('oracle+cx_oracle://scott:tiger@tnsname')

workFlow = api.model('WorkFlow', {
    'workflowName': fields.String,
    'workflowScriptLoc': fields.String,
    'createUser': fields.String,
    'createDate': fields.String,
    'lstUpdateUser': fields.String,
    'lstUpdateDate': fields.String,
})

@ns.route('/')
class WorkflowsCollection(Resource):

    @ns.marshal_list_with(workFlow)
    def get(self):
        try:
            #connection = engine.connect()
            #result = connection.execute("select * from EDSOPERATION.EDSLNK_WORKFLOWS")
            workFlow_list = []
            for x in range(6):
                workFlow.workflowName = 'Workflow_Name'+x
                workFlow.workflowScriptLoc = 'Workflow_Script_Loc'+x
                workFlow.createUser = 'Create_User'+x
                workFlow.createDate = 'Create_Date'+x
                workFlow.lstUpdateUser = 'Lst_Modified_User'+x
                workFlow.lstUpdateDate = 'Lst_Modified_Date'+x
                workFlow_list.append(workFlow)
        finally:
            #connection.close()
            print('finally')

        #what should I return ? 'workFlow' or 'workFlow_list' ?


    @ns.response(201, 'Category successfully created.')
    def post(self):
        #create_workflow(request.json)
        pass

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

When I trying to invoke the url curl -X GET "http://127.0.0.1:5000/edslnk/rest/eds-workflows/" -H "accept: application/json" I get server error code 500

My total objective at this stage is to populate my model workFlow with some hardcoded data and then return list of these models as json data back to the caller.

Once I'm able to achieve this, I'll try with actual data from database by iterating the resultset and populating the resultset rows to the model.

Thanks in advance for any help !

********** UPDATE - 1 ***********

I was able to achieve some breakthrough based on below code. I get expected output with below code.

However, I'm now ending up creating two definitions of my Model class viz., one via api.model and other via creating a normal class The model object workFlow created via api.Model is referred only for marshalling operation (in the @ns.marshal_list_with decorator) while the normal class created model objects workFlow1 and workFlow2 are used to populate the actual data and add them to the workFlow_list

Is it not possible to get different instances of my model object using the api.model and populate them with my data (kind-of using 'setters' as in java) ?

from flask import request
from flask import Flask,jsonify
from flask import Blueprint
from flask_restplus import Resource, Api, apidoc
from flask_restplus import fields, marshal
from sqlalchemy import create_engine
from sqlalchemy.sql import text
import json

app = Flask(__name__)
blueprint = Blueprint('api', __name__, url_prefix='/edslnk/rest')
api = Api(blueprint, version='1.0', title='EDSLink ResourceSvc API',description='Set of APIs to interactively communicate with Database and HDFS')
app.register_blueprint(blueprint)

ns = api.namespace('eds-workflows', description='Operations related to EDS Workflows')

#engine = create_engine('oracle+cx_oracle://scott:tiger@tnsname')

workFlow = api.model('WorkFlow', {
    'workflowName': fields.String,
    'workflowScriptLoc': fields.String,
    'createUser': fields.String,
    'createDate': fields.String,
    'lstUpdateUser': fields.String,
    'lstUpdateDate': fields.String,
})

#workFlow_list = []

class WorkFlow:
   def __init__(self, workflowName, workflowScriptLoc, createUser, createDate, lstUpdateUser, lstUpdateDate):
      self.workflowName = workflowName
      self.workflowScriptLoc = workflowScriptLoc
      self.createUser = createUser
      self.createDate = createDate
      self.lstUpdateUser = lstUpdateUser
      self.lstUpdateDate = lstUpdateDate

class MyEncoder(json.JSONEncoder):
    def default(self, o):
        return o.__dict__


@ns.route('/')
class WorkflowsCollection(Resource):

    @ns.marshal_list_with(workFlow)
    def get(self):
        try:
            #connection = engine.connect()
            #result = connection.execute("select * from EDSOPERATION.EDSLNK_WORKFLOWS")
            workFlow_list = []
            #workFlow1 = WorkFlow()
            #workFlow1.workflowName='abc'
            workFlow1 = WorkFlow('Workflow_Name', 'Workflow_Script_Loc', 'Create_User', 'Create_Date', 'Lst_Modified_User', 'Lst_Modified_Date')
            workFlow2 = WorkFlow('Workflow_Name', 'Workflow_Script_Loc', 'Create_User', 'Create_Date', 'Lst_Modified_User', 'Lst_Modified_Date')
            workFlow_list.append(workFlow1)
            workFlow_list.append(workFlow2)
            #responseString = json.dumps(workFlow_list, cls=MyEncoder)
            #print('responseString --> ' + responseString)
            #response = app.response_class(response=workFlow_list,status=200,mimetype='application/json')
#           for x in range(6):
#                workFlow.workflowName = 'Workflow_Name'+x
#                workFlow.workflowScriptLoc = 'Workflow_Script_Loc'+x
#                workFlow.createUser = 'Create_User'+x
#                workFlow.createDate = 'Create_Date'+x
#                workFlow.lstUpdateUser = 'Lst_Modified_User'+x
#                workFlow.lstUpdateDate = 'Lst_Modified_Date'+x
#                workFlow_list.append(workFlow)
        finally:
            #connection.close()
            print('finally')

        return workFlow_list

    @ns.response(201, 'Category successfully created.')
    def post(self):
        #create_workflow(request.json)
        pass

if __name__ == '__main__':
    #x = WorkflowsCollection()
    #r = x.get()
    #print(r)
    app.run(debug=True)

Upvotes: 0

Views: 3533

Answers (1)

Gastón Avila
Gastón Avila

Reputation: 309

Flask restful models are not the appropriate tool for what you are trying to do. They are meant to be input validation models and output serializers. For validation of input, you use a decorator @ns.expect(your_model) and it will check your payload.

Instead create a simple class like the one you made in your update for the object you are trying to model and create an array of instances of that object. If you return that list from your resource get method and use the @marshal_list_with(your_model) decorator, you will get the output you want.

As for the model being defined in two places, the api.model one serves as an interface between your internal models and what your API calls each field or how it is structured. One can however create API model from sqlalchemy models if using marshmallow which is a more general purpose validation/serialization library which is what restplus intends to use in the future.

Also I would recommend you stay away from handling the connection and specially from creating SQL statements to manipulate your objects. Sqlalchemy is a very expressive orm and you will be missing a lot by not using it.

Upvotes: 2

Related Questions