Flask Restful respond with XML or JSON format based on the data in request body

Viewed 766

I am trying to build an API using Flask-Restful where the users send a request body with the desired output like JSON or XML:

{ "output_format": "XML" }

The above request body would require an XML response. I only have a single resource.

My app.py file looks like this:

from flask import Flask, make_response
from flask_restful import Api
import json
from simplexml import dumps

from config import Config
from resources.location_resource import CoordinateResource


app = Flask(__name__)
app.config.from_object(Config)

api = Api(app)


@api.representation('application/xml')
def output_xml(data, code, headers=None):
    resp = make_response(dumps({'root': data}), code)
    resp.headers.extend(headers or {})
    return resp


@api.representation('application/json')
def output_json(data, code, headers=None):
    resp = make_response(json.dumps(data), code)
    resp.headers.extend(headers or {})
    return resp


api.add_resource(CoordinateResource, '/getAddressDetails')


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

my resource file looks like this:

from flask import request
from flask_restful import Resource
from http import HTTPStatus
from flask import request
import requests

# from geocode_play import getGeocodes
from geocode import getGeocodes


class CoordinateResource(Resource):
    def post(self):
        request.__setattr__(
            'headers', {'Accept': 'application/'.join(request.get_json()['output_format'])})
        json_data = request.get_json()
        output_format = json_data['output_format']
        address = json_data['address'] or 'New York'

        output_data = getGeocodes(address, output_format)

        return output_data, HTTPStatus.OK

and my intermediary file that builds the responses is this:

import requests
import xml.etree.ElementTree as ET


def getGeocodes(address, output_format):
    API_KEY = 'your-api-key'
    url = 'https://maps.googleapis.com/maps/api/geocode/json?'
    parameters = {
        "address": address,
        "key": API_KEY
    }
    response_data = requests.get(url, params=parameters).json()
    output_json_data = {
        "coordinates": {
            "lat": response_data['results'][0]['geometry']['location']['lat'],
            "lng": response_data['results'][0]['geometry']['location']['lng']
        },
        "address": response_data['results'][0]['formatted_address']
    }
    if output_format == 'xml' or output_format == 'XML':
        return {
            "coordinates": {
                "lat": response_data['results'][0]['geometry']['location']['lat'],
                "lng": response_data['results'][0]['geometry']['location']['lng']
            },
            "address": response_data['results'][0]['formatted_address']

        }
        
    return output_json_data

This example requires the header of the request to declare Accept: application/XML for XML to work but it doesn't care about the output format variable. Can you please help?

1 Answers

Try below code not tested but should work

from flask import make_response

class CoordinateResource(Resource):
        json_data = request.get_json()
        output_format = json_data['output_format']
        address = json_data['address'] or 'New York'

        output_data = getGeocodes(address, output_format)
        response = make_response(output_data)
        format = json_data["output_format"]
        if format.lower() == "xml":
            response.headers["Content-Type"] = "application/xml"
        else:
            response.headers["Content-Type"] = "application/json"
        return response

Related