4

I have a REST API endpoint in which I need to parse incoming nested JSON of the format:

        site: {
            id: '37251',
            site_name: 'TestSite',
            address: {
                'address': '1234 Blaisdell Ave',
                'city': 'Minneapolis',
                'state': 'MN',
                'zip': '55456',
                'neighborhood': 'Kingfield',
                'county': 'Hennepin',
            },
            geolocation: {
                latitude :  '41.6544',
                longitude :  '73.3322',
                accuracy: '45'
            }
        }

into the following SQLAlchemy classes:

Site:

class Site(db.Model):
    __tablename__ = 'site'
    id = Column(Integer, primary_key=True, autoincrement=True)
    site_name  = Column(String(80))# does site have a formal name
    address_id = Column(Integer, ForeignKey('address.id'))
    address = relationship("Address", backref=backref("site", uselist=False))
    geoposition_id = Column(Integer, ForeignKey('geoposition.id'))
    geoposition = relationship("Geoposition", backref=backref("site", uselist=False))
    evaluations = relationship("Evaluation", backref="site")
    site_maintainers = relationship("SiteMaintainer", backref="site")

Address (a Site has one Address):

class Address(db.Model):
    __tablename__ = 'address'
    id = Column(Integer, primary_key=True, autoincrement=True)
    address = Column(String(80))
    city = Column(String(80))
    state = Column(String(2))
    zip = Column(String(5))
    neighborhood =  Column(String(80))
    county = Column(String(80))

and Geoposition (a Site has one Geoposition):

class Geoposition(db.Model):
    __tablename__ = 'geoposition'
    id = Column(Integer, primary_key=True, autoincrement=True)
    site_id = Column(Integer)
    latitude = Column(Float(20))
    longitude = Column(Float(20))
    accuracy = Column(Float(20))
    timestamp = Column(DateTime)

Getting the SQLAlchemey data into JSON is easy, but I need to parse the JSON from my request so that I can append/update data that is sent via POST to the RESTful API. I know how to handle non-nested JSON, but I will be the first to admit that I am clueless in dealing with the nested JSON for records that belong to multiple tables in a relational structure.

I've tried searching high and low for this without any luck. Closest I could find is here "Nested validation with the flask-restful RequestParser", but this is not clicking for what I need to do based on my nested structure.

Community
  • 1
  • 1
horcle_buzz
  • 2,101
  • 3
  • 30
  • 59

2 Answers2

6

Cool! Looks like Flask handles this through the request handler:

With this JSON:

site: {
                "id": "37251",
                "site_name": "TestSite",
                "address": {
                    "address": "1234 Blaisdell Ave",
                    "city": "Minneapolis",
                    "state": "MN",
                    "zip": "55456",
                    "neighborhood": "Kingfield",
                    "county": "Hennepin"
                },
                geolocation: {
                    latitude :  "41.6544",
                    longitude :  "73.3322",
                    accuracy: "45"
                }
            }

Sent to this endpoint:

@app.route('/api/resource', methods=['GET','POST','OPTIONS'])
@cross_origin() # allow all origins all methods
@auth.login_required
def get_resource():
    # Get the parsed contents of the form data
    json = request.json
    print(json)

    # Render template
    return jsonify(json)

I get the following object:

{u'site': {u'geolocation': {u'latitude': u'41.6544', u'longitude': u'73.3322', u'accuracy': u'45'}, u'site_name': u'TestSite', u'id': u'37251', u'address': {u'city': u'Minneapolis', u'neighborhood': u'Kingfield', u'zip': u'55456', u'county': u'Hennepin', u'state': u'MN', u'address': u'1234 Blaisdell Ave'}}}

UPDATE:

Am able to access all my dictionary items just fine using this code for a test in my endpoint:

# print entire object
print json['site']

# define dictionary item for entire object
site = json['site']
print site["site_name"]

# print address object
print site['address']

# define address dictionary object
address = json['site']['address']
print address["address"]

# define geolocation dictionary object
geolocation = json['site']['geolocation']
print geolocation["accuracy"]

In retrospect, this seems rather trivial now. I hope this helps someone in the future.

horcle_buzz
  • 2,101
  • 3
  • 30
  • 59
2

Do you have access and can edit the JSON?

A few edits would help make it a valid JSON:

  1. Use double quotes for keys and values
  2. Open and close JSON with { and }
  3. Delete the trailing , in the country line

If you can do so, you JSON will look like this:

{
    "site": {
        "id": "37251",
        "site_name": "TestSite",
        "address": {
            "address": "1234BlaisdellAve",
            "city": "Minneapolis",
            "state": "MN",
            "zip": "55456",
            "neighborhood": "Kingfield",
            "county": "Hennepin"
        },
        "geolocation": {
            "latitude": "41.6544",
            "longitude": "73.3322",
            "accuracy": "45"
        }
    }
}

Sorting that out, use Python's json to deal with it:

import json
file_handler = open('test.json', 'r')
parsed_data = json.loads(file_handler.read())
print parsed_data

The output is a diciotnary that you can easily iterate with to validate your data:

{u'site': {u'geolocation': {u'latitude': u'41.6544', u'longitude': u'73.3322', u'accuracy': u'45'}, u'site_name': u'TestSite', u'id': u'37251', u'address': {u'city': u'Minneapolis', u'neighborhood': u'Kingfield', u'zip': u'55456', u'county': u'Hennepin', u'state': u'MN', u'address': u'1234BlaisdellAve'}}}

But if you can't edit your JSON to make its syntax better, json.loads would not parse it…

cuducos
  • 730
  • 6
  • 17
  • 1
    Perfect! Yes, I have access to the JSON (doing testing from a Sencha Touch Ajax request... the posted example was made on-the-fly so can easily be modified). I thought there was a simpler way of handling it, other than having to go through and individually parse out everything. Looks like I was right. – horcle_buzz Dec 22 '14 at 15:55