Anzu
Anzu

Reputation: 1

How to parse x-www-form-urlencoded POST requests with JSON body?

I'm new to Flask and trying to build a Flask app to receive POST requests coming from an API, then insert data into a database. The POST requests come as-is from a 3rd party program, I cannot modify how they are sent. Below is an example from one such request:

POST / HTTP/1.1
Host: example.com
Accept: */*
Content-Length: 264
Content-Type: application/x-www-form-urlencoded
User-Agent: Arma Reforger/1.1.0.42 (Headless; Windows)
{"token":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx","events":[{"name":"serveradmintools_conflict_base_captured","title":"Base André's Beacon captured by Soviet Army","data":{"faction":"Soviet Army","base":"André's Beacon"},"timestamp":1716526768}]}

I am using Postman to simulate these requests using the same HTTP headers, since I'm testing locally. I have tried parsing these requests a number of different ways and cannot get the results I want. The two closest solutions I have found are the following:

1.) First attempt using request.get_data() and unquote:

from flask import Flask, request
from urllib.parse import unquote

app = Flask(__name__)

@app.route('/', methods=['POST'])
def events():
    requestData = request.get_data()
    eventData = unquote(requestData) # works but replaces first colon with equals sign?
    return eventData

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

And the results I see in Postman look like this (notice how the first colon in the JSON string is replaced with an equals sign. I can't figure out why this is happening for the life of me):

{"token"="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx","events":[{"name":"serveradmintools_conflict_base_captured","title":"Base André's Beacon captured by Soviet Army","data":{"faction":"Soviet Army","base":"André's Beacon"},"timestamp":1716526768}]}

2.) Second attempt using request.form:

from flask import Flask, request

app = Flask(__name__)

@app.route('/', methods=['POST'])
def events():
    eventData = request.form
    return eventData

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

But the results in Postman look like this (notice the extra, escaped double-quotes, and some of the characters didn't display properly). I've been able to fix the character display issue, and I could using regex or string replace to remove the extra, escaped double-quotes, but why are they there in the first place and is there a better way to do this?):

{
  "{\"token\"": "\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\"events\":[{\"name\":\"serveradmintools_conflict_base_captured\",\"title\":\"Base Andr\u00e9's Beacon captured by Soviet Army\",\"data\":{\"faction\":\"Soviet Army\",\"base\":\"Andr\u00e9's Beacon\"},\"timestamp\":1716526768}]}"
}

I just want to parse the submitted POST data as JSON so I can then insert it into a database. How should I do this properly? I have tried things like request.get_json(force=True) and json.loads() but it fails with errors about invalid JSON (even though running the JSON string through a validator says its valid).

Here are screenshots of the request headers and body in Postman: POST Request Body in Postman HTTP Request Headers in Postman

Any and all help is greatly appreciated! :)

Update: I can't figure out why the json isn't parsed correctly, but I've just added some extra code to check and replace the random equals sign with a colon, which fixes the string to be valid JSON. Below is the code for my solution. I still don't feel like this is the best way, but until I find a better solution...

from flask import Flask, request
from urllib.parse import unquote

app = Flask(__name__)

@app.route('/', methods=['POST'])
def events():
    requestData = unquote(request.get_data())
    eventData = requestData
    # check for equals sign in first 10 chars, replace it with colon:
    firstChars = eventData[:10]
    if '=' in firstChars:
        eventDataJson = eventData.replace('=',':')

    return eventDataJson


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

Upvotes: 0

Views: 173

Answers (0)

Related Questions