Search code examples
pythonflaskflask-restplusflask-restx

How to return a nested json response in Flask-Restx


I am trying to make an API with Flask-RestX that can show a response like this,

{
  "id": 1,
  "msg": "How are things",
  "score": 345,
  "additional": {
    "goal": 56,
    "title": "ASking how"
  }
}

when data is like this (In my case, I do not control the data format),

data = {
    "id":1,
    "msg":"How are things",
    "goal": 56,
    "score":345,
    "title":"Asking how"
}

But the response I get with the current code is wrong, it shows null values

{
  "id": 1,
  "msg": "How are things",
  "score": 345,
  "additional": {
    "goal": null,
    "title": null
  }
}

Full code --

from flask import Flask
from flask_restx import Resource, Api, fields

app = Flask(__name__)
api = Api(app)

data = {
    "id":1,
    "msg":"How are things",
    "goal": 56,
    "score":345,
    "title":"Asking how"
}

extra = api.model('Extra', {
    'goal': fields.Integer,
    'title': fields.String
    })

model = api.model('Model', {
    'id' : fields.Integer,
    'msg' : fields.String,
    'score': fields.Integer,
    'additional' : fields.Nested(extra)
  })


@api.route('/hello')
class HelloWorld(Resource):
    @api.marshal_with(model)
    def get(self):
        return data

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

I am completely new to Flask-RestX / Flask-RestPlus. Please tell me, how can I achieve this without changing the data format itself.


Solution

  • In accordance with waynetech's comment above, the following worked for me:

    from flask import Flask
    from flask_restx import Resource, Api, fields
    
    app = Flask(__name__)
    api = Api(app)
    
    data = {
        "id":1,
        "msg":"How are things",
        "score":345,
        "additional": {
            "goal": 56,
            "title": "Asking how",
        }
    }
    
    extra = api.model('Extra', {
        'goal': fields.Integer,
        'title': fields.String
        })
    
    model = api.model('Model', {
        'id' : fields.Integer,
        'msg' : fields.String,
        'score': fields.Integer,
        'additional' : fields.Nested(extra)
      })
    
    
    @api.route('/hello')
    class HelloWorld(Resource):
    
        @api.marshal_with(model)
        def get(self):
            return data
    
        @api.marshal_with(model)
        def post(self):
            data = api.payload
    
            return data
    
    if __name__ == '__main__':
        app.run(debug=True, port=4000)
    

    here's the quick test script I used:

    from pprint import pprint
    import requests
    
    payload = {
        "id": 1,
        "msg":"Test",
        "score":345,
        "additional": {
            "goal": 56,
            "title": "Test",
        }
    }
    
    url = 'http://127.0.0.1:4000/hello'
    r = requests.post(url, json=payload)
    
    if r.status_code == 200:
        print(r.status_code)
        pprint(r.json())
    else:
        print("FAIL: ", r.status_code)