4

In flask-restplus, I want to model the response body which has nested list strucure, so whenever make api call, response body will be returned what I expected. In responce body, it has a nested structure, I don't know how to document that. Am I gonna use fields.Dict()? can anyone point me out here how to make this happen in flask-restplus?

response body:

{
  "score": 0,
  "category": "low",
  "guidance": "string",
  "is_ready": true,
  "used_features": [
    {
      "name": "hear_rate",
      "value": 1002,
      "range_value": [
        10,
        1000,
        10000,
        20000
      ],
      "range_frequency": [
        80,
        15,
        2,
        1
      ],
      "importance": 1
    },
    {
      "name": "pressure",
      "value": 400,
      "range_value": [
        10,
        1000,
        3000
      ],
      "range_frequency": [
        85,
        10,
        5
      ],
      "importance": 2
    }
  ]
}

my partial solution:

here is my partial solution

from flask import Flask, jsonify
from flask_restplus import Api, Resource, fields, reqparse, inputs

app = Flask(__name__)
api = Api(app)
ns = api.namespace('ns')

payload = api.model('Payload', {
    'score': fields.Integer,
    'category': fields.String,
    'guidance': fields.String,
    'is_ready': fields.Boolean,
    ## how to add used features arrays
})


@ns.route('/')
class AResource(Resource):
    @ns.expect(payload)
    def get(self):
        parser = reqparse.RequestParser()
        parser.add_argument('score', type=str, required=True)
        parser.add_argument('category', type=str, required=True)
        parser.add_argument('guidance', type=str, required=True)
        parser.add_argument('category', type=str, required=True)
        parser.add_argument('is_ready', type= bool, required=True)
        try:  # Will raise an error if date can't be parsed.
            args = parser.parse_args()  # type "dict"
            return jsonify(args)
        except:
            return None, 400

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

in my attempted code, I couldn't come up with a solution of how to model used_features dictionary. Is there any way to fix the defect of above attempt? can anyone point me out how to make this work where I can model the response body correctly? Am I gonna use Dict or Nested in my code? any further thought? thanks

beyond_inifinity
  • 305
  • 5
  • 23

1 Answers1

4

Use @ns.marshal_with(payload).

The decorator marshal_with() is what actually takes your data object and applies the field filtering. The marshalling can work on single objects, dicts, or lists of objects. Marshalling Resource Link: https://flaskrestplus.readthedocs.io/en/stable/marshalling.html

And to model used_features use fields.Nested. I have shown how to use it in the following code.


from flask import Flask, jsonify
from flask_restplus import Namespace, Resource, fields, reqparse
from flask_restplus import Api

app = Flask(__name__)
api = Api(app)
ns = api.namespace('ns')


used_features = {}
used_features['name'] = fields.String(attribute='name')
used_features['value'] = fields.Integer(attribute='value')
used_features['range_value'] = fields.List(
    fields.Integer, attribute='range_value')
used_features['range_frequency'] = fields.List(
    fields.Integer, attribute='range_frequency')
used_features['importance'] = fields.Integer(attribute='importance')

used_features_payload = api.model('feature_payload', used_features)

payload = api.model('Payload', {
    'score': fields.Integer,
    'category': fields.String,
    'guidance': fields.String,
    'is_ready': fields.Boolean,
    'used_features': fields.Nested(used_features_payload)
    # how to add used features arrays
})


@ns.route('/')
class AResource(Resource):
    @ns.expect(payload)
    @ns.marshal_with(payload)
    def get(self):
        parser = reqparse.RequestParser()
        parser.add_argument('score', type=str, required=True)
        parser.add_argument('category', type=str, required=True)
        parser.add_argument('guidance', type=str, required=True)
        parser.add_argument('category', type=str, required=True)
        parser.add_argument('is_ready', type=bool, required=True)
        try:  # Will raise an error if date can't be parsed.
            args = parser.parse_args()  # type "dict"
            return jsonify(args)
        except:
            return None, 400


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

Subir Verma
  • 306
  • 2
  • 8
  • How am I gonna use `X-Fields` on server endpoint? I have few more questions regarding your answer, can I get instant response before accepting your solution? thanks – beyond_inifinity Apr 26 '20 at 15:47
  • 1
    @beyond_inifinity By default the header is X-Fields but it can be changed with the RESTPLUS_MASK_HEADER parameter. The syntax is actually quite simple. You just provide a comma-separated list of field names, optionally wrapped in brackets. ` # These two mask are equivalents mask = '{name,age}' # or mask = 'name,age' ` – Subir Verma Apr 26 '20 at 16:12
  • in my case, I make a post request with json data, then api will consume json data and pass params to make a function call then function return something, how can I use returned output into above response body? I can't print out response body on server endpoint like that. How can I pass function output to response body above? any thought? – beyond_inifinity Apr 26 '20 at 16:25
  • You can return the function output as a json object to response body and it should work fine. – Subir Verma Apr 26 '20 at 18:48
  • do you mind to demonstrate with code with dummy input data and output should yield response body above? let's say you make a post request with certain dummy data and expect api function output should yield response body function. thanks for your help. – beyond_inifinity Apr 26 '20 at 18:51
  • what do you mean by that: `return the function output as a json object to response body`? ould you show coding demo with dummy input data but function output as a json object to above response body? thanks a lot – beyond_inifinity Apr 26 '20 at 18:58
  • any update on my above comment? could you give coding demo for how to attach function output to response body? thanks – beyond_inifinity Apr 27 '20 at 15:27
  • Hi. Something like below code. Returning the output of a function **utils.generate_summary(filepath)** in result and jsonify it in return of POST method. `class Example(Resource): def post(self): try: result = utils.generate_summary(filepath) return { 'Response':result} except: api.abort(404)` – Subir Verma Apr 27 '20 at 15:45
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/212631/discussion-between-beyond-inifinity-and-subir-verma). – beyond_inifinity Apr 27 '20 at 16:03